数值分析实验 插值方法 拉格朗日 牛顿插值 三次样条
效果图
废话不多说,直接上效果图!!
效果说明
图中取的点使用鼠标点击生成,点的个数可以无限多。
描点后点击左边的按钮生成函数图像,再次点击按钮可以取消函数的生成。
三种函数任意组合,随切随换,麻麻再也不用担心我的数值分析实验啦!
备注
如果运行不出来,可能是工程文件的内容有问题,建议照着我给的工程文件内容依葫芦画瓢,每个人建的项目名,类名什么的可能不太一样,一模一样的照搬也会出问题。如果实在运行不出来,加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