Qt实现数值分析实验之插值方法

数值分析实验 插值方法 拉格朗日 牛顿插值 三次样条

效果图

废话不多说,直接上效果图!!
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

效果说明

图中取的点使用鼠标点击生成,点的个数可以无限多。
描点后点击左边的按钮生成函数图像,再次点击按钮可以取消函数的生成。
三种函数任意组合,随切随换,麻麻再也不用担心我的数值分析实验啦!

备注

如果运行不出来,可能是工程文件的内容有问题,建议照着我给的工程文件内容依葫芦画瓢,每个人建的项目名,类名什么的可能不太一样,一模一样的照搬也会出问题。如果实在运行不出来,加q 1224983701(备注来意),由于这是小号登陆的时间不多,肯定不会第一时间通过的,所以有问题优先自己解决

代码

在这里插入图片描述

.pro文件

#-------------------------------------------------
#
# Project created by QtCreator 2020-11-18T14:39:01
#
#-------------------------------------------------

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = FirstExperiment
TEMPLATE = app


SOURCES += main.cpp\
        Mywidget.cpp

HEADERS  += Mywidget.h

FORMS    += widget.ui

CONFIG += c++11

main.cpp

#include "Mywidget.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();

    return a.exec();
}

Mywidget.h

#ifndef MYWIDGET_H
#define MYWIDGET_H
#include<iostream>
#include<QWidget>
#include<QFrame>
#include<QLabel>
#include<QPoint>
using namespace std;
namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();
    //画坐标轴
    void DrawCoordinate(QFrame* f);
    //描点
    void DrawPoints(QFrame* );
    //画牛顿插值曲线
    void DrawNewton();
    //画拉格朗日插值曲线
    void DrawLagrange();
    //画三次样条插值曲线
    void DrawCubic();
protected:
    //重写绘图事件
    //如果在窗口绘图,必须放在绘图事件里实现
    //绘图事件内部自动调用,窗口需要重绘的时候(状态改变
    void paintEvent(QPaintEvent *);

    //void mousePressEvent(QMouseEvent *);

    //void mouseMoveEvent(QMouseEvent *);

    //void mouseReleaseEvent(QMouseEvent *);

    //事件过滤器,用于子控件画图
    bool eventFilter(QObject *, QEvent *);


private:
    Ui::Widget *ui;
    QLabel x,y;//"x轴","y轴"字样
    QPoint oPos;//坐标原点
    bool isclear;

    bool isNoNewdon;//牛顿插值是否未描绘
    bool isNoGrange;//拉格朗日插值是否未描绘
    bool isNoCubic;//三次样条插值是否未描绘

    bool isYesNewdon;//牛顿插值是否已描绘
    bool isYesGrange;//拉格朗日插值是否已描绘
    bool isYesCubic;//三次样条插值是否已描绘

    int y1Marking;//拉格朗日颜色标注的Y坐标
    int y2Marking;//牛顿插值颜色标注的Y坐标
    int y3Marking;//三次样条颜色标注的Y坐标
    bool start;
    QImage *image;
    vector<double> xPos;
    vector<double> yPos;
};

#endif // MYWIDGET_H

Mywidget.cpp

#include "Mywidget.h"
#include "ui_widget.h"
#include<QPainter>
#include<QPen>
#include<QBrush>
#include<QFrame>
#include<QDebug>
#include<QMouseEvent>
#include<QLabel>
#include<iostream>
using namespace std;
Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    //ui->widget->installEventFilter(this);
    ui->frame_2->installEventFilter(this);

    isclear=0;

    //初始时候没有函数已经被描绘
    isNoNewdon=0;
    isNoGrange=0;
    isNoCubic=0;
    isYesNewdon=0;
    isYesGrange=0;
    isYesCubic=0;

    y1Marking=0;
    y2Marking=0;
    y2Marking=0;

    //正则表达式绑定“槽函数”

    connect(ui->clear,&QPushButton::clicked,
            [=]()
    {
        isclear=0;
        xPos.clear();
        yPos.clear();

        isNoNewdon=0;
        isNoGrange=0;
        isNoCubic=0;
        isYesNewdon=0;
        isYesGrange=0;
        isYesCubic=0;

        y1Marking=30;
        y2Marking=30;
        y2Marking=30;

        update();
    }
            );

    connect(ui->Lagelangri,&QPushButton::clicked,
            [=]()
    {
        if(isNoGrange==0){
            isNoGrange=1;
            y1Marking=y2Marking>y3Marking?y2Marking:y3Marking;
            y1Marking+=30;
        }
        else{
            isNoGrange=0;
            isYesGrange=0;
            if(y2Marking>y1Marking)y2Marking-=30;
            if(y3Marking>y1Marking)y3Marking-=30;
            y1Marking=0;
        }

        update();
    }
            );

    connect(ui->Niudun,&QPushButton::clicked,
            [=]()
    {
        if(isNoNewdon==0){
            isNoNewdon=1;
            y2Marking=y1Marking>y3Marking?y1Marking:y3Marking;
            y2Marking+=30;
        }
        else{
            isNoNewdon=0;
            isYesNewdon=0;
            if(y1Marking>y2Marking)y1Marking-=30;
            if(y3Marking>y2Marking)y3Marking-=30;
            y2Marking=0;
        }
        update();
    }
            );

    connect(ui->Threetime,&QPushButton::clicked,
            [=]()
    {
        if(isNoCubic==0){
            isNoCubic=1;
            y3Marking=y1Marking>y2Marking?y1Marking:y2Marking;
            y3Marking+=30;
        }
        else{
            isNoCubic=0;
            isYesCubic=0;
            if(y1Marking>y3Marking)y1Marking-=30;
            if(y2Marking>y3Marking)y2Marking-=30;
            y3Marking=0;
        }
        update();
    }
            );


}
void Widget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
}
//事件过滤器
bool Widget::eventFilter(QObject *obj, QEvent *ev)
{

    if(obj==ui->frame_2&&ev->type()==QEvent::Paint){
        //画坐标轴
        DrawCoordinate(ui->frame_2);
        if(isclear){
            DrawPoints(ui->frame_2);
        }
        if(isNoGrange){
            DrawLagrange();
            isYesGrange=1;
        }
        if(isNoNewdon){
            DrawNewton();
            isYesNewdon=1;
        }
        if(isNoCubic){
            DrawCubic();
            isYesCubic=1;
        }
    }
    else if(obj==ui->frame_2&&ev->type()==QEvent::MouseButtonPress){
        //记录鼠标点击的点的位置
        QMouseEvent *env=static_cast<QMouseEvent*>(ev);
        isclear=1;
        xPos.push_back(env->x()*1.0/ui->frame_2->width());
        yPos.push_back(env->y()*1.0/ui->frame_2->height());
        update();
    }
    else if(obj==ui->frame_2&&ev->type()==QEvent::Resize){
        if(isYesGrange)isNoGrange=1;
        if(isYesNewdon)isNoNewdon=1;
    }
    return QWidget::eventFilter(obj,ev);
}
//画坐标轴
void  Widget::DrawCoordinate(QFrame* frame_2)
{
    QPainter painter(ui->frame_2);

    painter.setBrush(Qt::white);
    painter.setPen(Qt::white);
    painter.drawRect(0,0,frame_2->width(),frame_2->height());

    painter.setBrush(Qt::red);
    painter.setPen(Qt::black);
    //画x轴
    painter.drawLine(20,ui->frame_2->height()*6/7,ui->frame_2->width()-20,ui->frame_2->height()*6/7);
    painter.drawLine(ui->frame_2->width()-20-15,ui->frame_2->height()*6/7-7,ui->frame_2->width()-20,ui->frame_2->height()*6/7);
    painter.drawLine(ui->frame_2->width()-20-15,ui->frame_2->height()*6/7+7,ui->frame_2->width()-20,ui->frame_2->height()*6/7);
    x.setParent(ui->frame_2);
    x.setText("x轴");
    x.move(ui->frame_2->width()-20-40,ui->frame_2->height()*6/7+15);
    x.show();

    //画y轴
    painter.drawLine(ui->frame_2->width()/8,20,ui->frame_2->width()/8,ui->frame_2->height()-20);
    painter.drawLine(ui->frame_2->width()/8-7,20+15,ui->frame_2->width()/8,20);
    painter.drawLine(ui->frame_2->width()/8+7,20+15,ui->frame_2->width()/8,20);
    y.setParent(ui->frame_2);
    y.setText("y轴");
    y.move(ui->frame_2->width()/8-40,20);
    y.show();
    oPos.setX(ui->frame_2->width()/8);
    oPos.setY(ui->frame_2->height()*6/7);
}
//描绘鼠标选中的点
void Widget::DrawPoints(QFrame *frame_2)
{
    QPainter p(frame_2);
    p.setPen(Qt::black);
    p.setBrush(Qt::black);
    for(int i=0;i<xPos.size();i++){
        p.drawEllipse(xPos[i]*frame_2->width(),yPos[i]*frame_2->height(),3,3);
    }
}
//画拉格朗日插值曲线
void Widget::DrawLagrange(){
    vector<int> xp;
    vector<double> yp;
    for(int x=0;x<ui->frame_2->width()-40;x++){
        double y=0;
        //根据x值计算p(x)值
        for(int i=0;i<xPos.size();i++){
            double m=1;
            for(int j=0;j<xPos.size();j++){
                if(j!=i){
                    m*=(x-(xPos[j]*ui->frame_2->width()-oPos.x()));
                    m/=(xPos[i]*ui->frame_2->width()-oPos.x()-(xPos[j]*ui->frame_2->width()-oPos.x()));
                }
            }
            y+=m*(yPos[i]*ui->frame_2->height()-oPos.y());
        }
        //将x以及其对应的p(x)值存储起来
        xp.push_back(x+oPos.x());
        yp.push_back(y+oPos.y());

    }

    QPainter p(ui->frame_2);
    QPen pen;
    pen.setColor(Qt::red);
    pen.setWidth(2);
    p.setPen(pen);
    p.setBrush(Qt::red);
    if(xPos.size()){
        //连点画曲线
        for(int i=1;i<xp.size();i++){
            p.drawLine(xp[i-1],yp[i-1],xp[i],yp[i]);
        }
        //画标注
        p.drawLine(ui->frame_2->width()-120,y1Marking,ui->frame_2->width()-90,y1Marking);
        QRect rect(ui->frame_2->width()-80,y1Marking-10,ui->frame_2->width()-15,y1Marking+10);
        p.setPen(Qt::black);
        p.drawText(rect,"拉格朗日");
    }
}

//画牛顿插值曲线
void Widget::DrawNewton()
{
    //构造差商表
    vector< vector<double> > dict;
    for(int i=0;i<xPos.size();i++)
    {
        vector<double> t;
        dict.push_back(t);
    }
    for(int i=0;i<xPos.size();i++)
    {
        dict[i].push_back(oPos.y()-yPos[i]*ui->frame_2->height());
    }
    for(int i=0;i<xPos.size();i++)
    {
        for(int j=i+1;j<yPos.size();j++)
        {
            double y;
            y=dict[j-1][i]-dict[j][i];
            double x;
            x=xPos[j-(i+1)]*ui->frame_2->width()-xPos[j]*ui->frame_2->width();
            dict[j].push_back(y*1.0/x);
        }
    }

   vector<double> xp;
   vector<double> yp;
   for(int x=0;x<ui->frame_2->width()-40;x++){
       double y=0;
       //根据x值计算p(x)值
       for(int i=0;i<xPos.size();i++){
           double m=1;
           for(int j=0;j<i;j++){
                   m*=(x-(xPos[j]*ui->frame_2->width()-oPos.x()));
           }
           y+=m*dict[i][i];
       }
       //将x以及其对应的p(x)值存储起来
       xp.push_back(x+oPos.x());
       yp.push_back(-y+oPos.y());
   }

   QPainter p(ui->frame_2);
   QPen pen;
   pen.setColor(Qt::blue);
   pen.setWidth(1.5);
   p.setPen(pen);
   //p.setBrush(Qt::red);
   //连点画曲线
   if(xPos.size()){
       for(int i=1;i<xp.size();i++){
           p.drawLine(xp[i-1],yp[i-1],xp[i],yp[i]);
       }
       //画标注
       p.drawLine(ui->frame_2->width()-120,y2Marking,ui->frame_2->width()-90,y2Marking);
       QRect rect(ui->frame_2->width()-80,y2Marking-10,ui->frame_2->width()-15,y2Marking+10);
       p.setPen(Qt::black);
       p.drawText(rect,"牛顿插值");
   }

}
//画三次样条插值
double HH(double x){
    return pow(x-1,2)*(2*x+1);
}
double I(double x){
    return x*x*(-2*x+3);
}
double J(double x){
    return pow(x-1,2)*x;
}
double K(double x){
    return x*x*(x-1);
}
void Widget::DrawCubic()
{
    double *M=new double[xPos.size()];
    M[0]=(yPos[1]-yPos[0])*ui->frame_2->height()/(xPos[1]-xPos[0])/ui->frame_2->width();
    M[xPos.size()-1]=(yPos[xPos.size()-1]-yPos[xPos.size()-2])*ui->frame_2->height()/(xPos[xPos.size()-1]-xPos[xPos.size()-2])/ui->frame_2->width();

    vector<double> H;
    vector<double> A;
    for(int i=1;i<xPos.size();i++){
        H.push_back(xPos[i]*ui->frame_2->width()-xPos[i-1]*ui->frame_2->width());
    }
    for(int i=0;i<H.size()-1;i++){
        A.push_back(H[i]/(H[i]+H[i+1]));
    }

    vector<double> B;
    for(int i=0;i<A.size();i++){
        B.push_back( 3/( (1-A[i])*(yPos[i+1]-yPos[i])*ui->frame_2->height()/H[i] +A[i]*(yPos[i+1]-yPos[i])*ui->frame_2->height()/H[i+1]) );
    }

    //追赶法
    vector<double> L,U;
    U.push_back(0);
    int i=0;
    for(;i<xPos.size()-3;i++){
        L.push_back(2-U[i]*(1-A[i+1]));
        U.push_back(A[i]/L[i]);
    }
    L.push_back(2-U[i]*(1-A[i+1]));

    vector<double> y;

    y.push_back(B[0]-(1-A[0])*M[0]);
    for(int i=1;i<xPos.size()-2;i++){
        y.push_back((B[i]+(1-A[i])*yPos[i]*ui->frame_2->height())/L[i-1]);
    }
    M[xPos.size()-2]=y[y.size()-1];
    for(int i=xPos.size()-3;i>1;i--){
       M[i]=y[i-1]-U[i-1]*M[i+1];
    }

    for(int i=0;i<xPos.size()-1;i++){

        vector<double> xp;
        vector<double> yp;
        for(int j=xPos[i]*ui->frame_2->width();j<xPos[i+1]*ui->frame_2->width();j++){
            double s=yPos[i]*ui->frame_2->height()*HH((j-xPos[i]*ui->frame_2->width())/H[i]);
            s+=yPos[i+1]*ui->frame_2->height()*I((j-xPos[i]*ui->frame_2->width())/H[i]);
            s+=H[i]*M[i]*J((j-xPos[i]*ui->frame_2->width())/H[i]);
            s+=H[i]*M[i+1]*K((j-xPos[i]*ui->frame_2->width())/H[i]);
            xp.push_back(j);
            yp.push_back(s);
        }

        QPainter p(ui->frame_2);
        QPen pen;
        pen.setColor(Qt::green);
        pen.setWidth(1.5);
        p.setPen(pen);
        //p.setBrush(Qt::red);
        //连点画曲线
        if(xPos.size()){
            for(int i=1;i<xp.size();i++){
                p.drawLine(xp[i-1],yp[i-1],xp[i],yp[i]);
            }
            //画标注
            p.drawLine(ui->frame_2->width()-120,y3Marking,ui->frame_2->width()-90,y3Marking);
            QRect rect(ui->frame_2->width()-80,y3Marking-10,ui->frame_2->width()-15,y3Marking+10);
            p.setPen(Qt::black);
            p.drawText(rect,"三次样条");
        }
    }
}


Widget::~Widget()
{
    delete ui;
}

ui_widget.h


#ifndef UI_WIDGET_H
#define UI_WIDGET_H

#include <QtCore/QVariant>
#include <QtWidgets/QAction>
#include <QtWidgets/QApplication>
#include <QtWidgets/QButtonGroup>
#include <QtWidgets/QFrame>
#include <QtWidgets/QHBoxLayout>
#include <QtWidgets/QHeaderView>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QVBoxLayout>
#include <QtWidgets/QWidget>

QT_BEGIN_NAMESPACE

class Ui_Widget
{
public:
    QHBoxLayout *horizontalLayout;
    QFrame *frame;
    QVBoxLayout *verticalLayout;
    QPushButton *Niudun;
    QPushButton *Lagelangri;
    QPushButton *Threetime;
    QPushButton *clear;
    QFrame *frame_2;

    void setupUi(QWidget *Widget)
    {
        if (Widget->objectName().isEmpty())
            Widget->setObjectName(QStringLiteral("Widget"));
        Widget->resize(986, 548);
        QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
        sizePolicy.setHorizontalStretch(0);
        sizePolicy.setVerticalStretch(0);
        sizePolicy.setHeightForWidth(Widget->sizePolicy().hasHeightForWidth());
        Widget->setSizePolicy(sizePolicy);
        Widget->setMinimumSize(QSize(800, 500));
        horizontalLayout = new QHBoxLayout(Widget);
        horizontalLayout->setSpacing(6);
        horizontalLayout->setContentsMargins(11, 11, 11, 11);
        horizontalLayout->setObjectName(QStringLiteral("horizontalLayout"));
        frame = new QFrame(Widget);
        frame->setObjectName(QStringLiteral("frame"));
        frame->setMaximumSize(QSize(110, 16777215));
        frame->setFrameShape(QFrame::Panel);
        frame->setFrameShadow(QFrame::Raised);
        verticalLayout = new QVBoxLayout(frame);
        verticalLayout->setSpacing(6);
        verticalLayout->setContentsMargins(11, 11, 11, 11);
        verticalLayout->setObjectName(QStringLiteral("verticalLayout"));
        Niudun = new QPushButton(frame);
        Niudun->setObjectName(QStringLiteral("Niudun"));

        verticalLayout->addWidget(Niudun);

        Lagelangri = new QPushButton(frame);
        Lagelangri->setObjectName(QStringLiteral("Lagelangri"));

        verticalLayout->addWidget(Lagelangri);

        Threetime = new QPushButton(frame);
        Threetime->setObjectName(QStringLiteral("Threetime"));

        verticalLayout->addWidget(Threetime);

        clear = new QPushButton(frame);
        clear->setObjectName(QStringLiteral("clear"));

        verticalLayout->addWidget(clear);


        horizontalLayout->addWidget(frame);

        frame_2 = new QFrame(Widget);
        frame_2->setObjectName(QStringLiteral("frame_2"));
        frame_2->setMinimumSize(QSize(0, 0));
        frame_2->setFrameShape(QFrame::Box);
        frame_2->setFrameShadow(QFrame::Raised);

        horizontalLayout->addWidget(frame_2);


        retranslateUi(Widget);

        QMetaObject::connectSlotsByName(Widget);
    } // setupUi

    void retranslateUi(QWidget *Widget)
    {
        Widget->setWindowTitle(QApplication::translate("Widget", "Widget", 0));
        Niudun->setText(QApplication::translate("Widget", "\347\211\233\351\241\277\346\217\222\345\200\274", 0));
        Lagelangri->setText(QApplication::translate("Widget", "\346\213\211\346\240\274\346\234\227\346\227\245\346\217\222\345\200\274", 0));
        Threetime->setText(QApplication::translate("Widget", "\344\270\211\346\254\241\346\240\267\346\235\241", 0));
        clear->setText(QApplication::translate("Widget", "\346\270\205\347\251\272", 0));
    } // retranslateUi

};

namespace Ui {
    class Widget: public Ui_Widget {};
} // namespace Ui

QT_END_NAMESPACE

#endif // UI_WIDGET_H

  • 16
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
双三次线性插值是一种常用的图像处理算法,可以用于图像的放大和缩小。下面是一个使用QtC++实现双三次线性插值的示例代码: ```cpp #include <QImage> #include <QDebug> // 双三次线性插值函数 double bicubicInterpolation(double p[4][4], double x, double y) { double px[4], py[4]; double result = 0.0; // 计算x方向的插值 for (int i = 0; i < 4; i++) { double s = x - i; double w = 0.0; if (s <= -1.0) { w = 0.0; } else if (s <= 0.0) { w = (s + 2.0) * (s + 2.0) * (s + 2.0) - 4.0 * (s + 1.0) * (s + 1.0) + 2.0; } else if (s <= 1.0) { w = -s * s * s + 5.0 * s * s - 8.0 * s + 4.0; } else if (s <= 2.0) { w = (2.0 - s) * (2.0 - s) * (2.0 - s); } else { w = 0.0; } px[i] = w; } // 计算y方向的插值 for (int j = 0; j < 4; j++) { double t = y - j; double w = 0.0; if (t <= -1.0) { w = 0.0; } else if (t <= 0.0) { w = (t + 2.0) * (t + 2.0) * (t + 2.0) - 4.0 * (t + 1.0) * (t + 1.0) + 2.0; } else if (t <= 1.0) { w = -t * t * t + 5.0 * t * t - 8.0 * t + 4.0; } else if (t <= 2.0) { w = (2.0 - t) * (2.0 - t) * (2.0 - t); } else { w = 0.0; } py[j] = w; } // 计算插值结果 for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { result += p[i][j] * px[i] * py[j]; } } return result; } int main() { double arr_x[5] = {1, 5, 8, 13, 17}; double arr_y[5] = {4, 45, 10, 40, 20}; double res; // 构造插值矩阵 double p[4][4] = { {arr_y[0], arr_y[1], arr_y[2], arr_y[3]}, {arr_y[1], arr_y[2], arr_y[3], arr_y[4]}, {arr_y[2], arr_y[3], arr_y[4], arr_y[5]}, {arr_y[3], arr_y[4], arr_y[5], arr_y[6]} }; // 计算插值结果 res = bicubicInterpolation(p, 6, 6); qDebug() << "插值结果:" << res; return 0; } ``` 这段代码使用了一个名为`bicubicInterpolation`的函数来实现双三次线性插值。该函数接受一个4x4的插值矩阵`p`和待插值的坐标`x`和`y`作为参数,并返回插值结果。 在主函数中,我们首先构造了一个插值矩阵`p`,然后调用`bicubicInterpolation`函数计算插值结果,并输出到控制台。 注意:这只是一个简单的示例代码,实际应用中可能需要根据具体需求进行修改和优化。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值