#ifndef COMPLEX_H
#define COMPLEX_H
#define MY_PI acos(-1)
#include <cmath>
class Complex
{
public:
double m_A;//实部或模长
double m_B;//虚部或弧度角
public:
Complex(double a=0,double b=0);
static Complex toExpComplex(const Complex& x);
static Complex toDescartesComplex(const Complex& x);
static bool isAlmostZero(double value, double epsilon = 1e-9)noexcept
{
return std::fabs(value) < epsilon;
}
};
#endif // COMPLEX_H
#include "complex.h"
Complex::Complex(double a, double b):
m_A(a),
m_B(b)
{
}
Complex Complex::toExpComplex(const Complex &x)
{
Complex c;
c.m_A=pow(pow(x.m_A,2)+pow(x.m_B,2),0.5);
if(isAlmostZero(x.m_A) && isAlmostZero(x.m_B)){
c.m_B=double(0);//无意义
}
else if(isAlmostZero(x.m_A) && !isAlmostZero(x.m_B)){
if(x.m_B>0)c.m_B=double(MY_PI/double(2));
else c.m_B=double((MY_PI/double(2))*double(3));
}
else if(!isAlmostZero(x.m_A) && isAlmostZero(x.m_B)){
if(x.m_A>0)c.m_B=double(0);
else c.m_B=double(MY_PI);
}
else {
if(x.m_A>0 && x.m_B>0)
c.m_B=atan(fabs(x.m_B/x.m_A))+double(0);
else if(x.m_A<0 && x.m_B>0)
c.m_B=atan(fabs(x.m_A/x.m_B))+double(MY_PI/double(2));
else if(x.m_A<0 && x.m_B<0)
c.m_B=atan(fabs(x.m_B/x.m_A))+double(MY_PI);
else if(x.m_A>0 && x.m_B<0)
c.m_B=atan(fabs(x.m_A/x.m_B))+double((MY_PI/double(2))*double(3));
}
return c;
}
Complex Complex::toDescartesComplex(const Complex &x)
{
Complex c;
c.m_A=x.m_A*cos(x.m_B);
c.m_B=x.m_A*sin(x.m_B);
return c;
}
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QPainter>
#include <QPaintEvent>
#include <QDebug>
#include <QMap>
#include <QTimer>
#include "complex.h"
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
private:
int m_FittingNum =201; //拟合用的函数数量
int m_CutNum =1000; //近似积分切分区间的数量
int m_TimeNum =1000; //时间刻度
QMap<int,Complex> m_PointsMap;
QVector<Complex> m_Points;
QMap<int,Complex> m_PointArrow;
public:
explicit Widget(QWidget *parent = nullptr);
~Widget();
private:
Complex f(const double& t);
void init();
void paintEvent(QPaintEvent* e);
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
this->resize(1000,900);
init();
}
Widget::~Widget()
{
delete ui;
}
void Widget::init()
{
for(int n=-m_FittingNum/2;n<=m_FittingNum/2;++n){
Complex cn;
for(int j=1;j<=m_CutNum;++j){
double jek=double(j)/double(m_CutNum);
Complex ct=Complex::toExpComplex(f(jek));
cn.m_A+=(ct.m_A*cos(-2.0*MY_PI*double(n)*jek+ct.m_B))/double(m_CutNum);
cn.m_B+=(ct.m_A*sin(-2.0*MY_PI*double(n)*jek+ct.m_B))/double(m_CutNum);
}
cn=Complex::toExpComplex(cn);
m_PointsMap[n]=cn;
}
QTimer* timer=new QTimer(this);
connect(timer,&QTimer::timeout,[=](){
static int t=0;t++;
if(t>m_TimeNum)return ;
double timecoming=double(t)/double(m_TimeNum);
Complex c;
m_PointArrow.clear();
for(auto it=m_PointsMap.begin();it!=m_PointsMap.end();++it){
Complex ct;
ct.m_A=it.value().m_A*cos(it.value().m_B+double(it.key())*2.0*MY_PI*timecoming);
ct.m_B=it.value().m_A*sin(it.value().m_B+double(it.key())*2.0*MY_PI*timecoming);
c.m_A+=ct.m_A;
c.m_B+=ct.m_B;
m_PointArrow[it.key()]=ct;
}
m_Points.push_back(c);
update();
});
timer->start(10);
}
Complex Widget::f(const double &t)
{
//t 0 —> 1
//m_A代表实部 m_B代表虚部
//这个函数随时间t变化返回一个a+b*i的复数(收尾闭合,极坐标a*exp(b*i)通过toDescartesComplex转化为a+b*i形式)
Complex c;
c.m_A = t*600 * sin(t * MY_PI * 10.0);
c.m_B = t * 2.0 * MY_PI * 1.0;
c=Complex::toDescartesComplex(c);
return c;
}
void Widget::paintEvent(QPaintEvent *e)
{
Q_UNUSED(e)
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing, true);
QBrush brush;
brush.setColor(QColor(0,0,0));
brush.setStyle(Qt::SolidPattern);
painter.setBrush(brush);
painter.drawRect(0,0,this->width(),this->height());
painter.setBrush(Qt::NoBrush);
painter.setPen(QPen(QColor(255,255,255,100), 2));
painter.setWindow(0, height(), width(), -1 * height());
int centerX = width() / 2;
int centerY = height() / 2;
painter.translate(centerX, centerY);
painter.drawLine(-centerX, 0, centerX, 0);
painter.drawLine(0, -centerY, 0, centerY);
Complex ct;
double r=0.0;
ct.m_A=0;ct.m_B=0;
int i=0;
do
{
painter.drawLine(QPointF(ct.m_A,ct.m_B),QPointF(ct.m_A+m_PointArrow[i].m_A,ct.m_B+m_PointArrow[i].m_B));
r =Complex::toExpComplex(m_PointArrow[i]).m_A;
painter.drawEllipse(QPointF(ct.m_A,ct.m_B),r,r);
ct.m_A+=m_PointArrow[i].m_A;
ct.m_B+=m_PointArrow[i].m_B;
if(i!=0){
if(i<0){i=-i;}
else {i=-i;--i;}
}
else {--i;}
}while(qAbs(i)<=m_FittingNum/2);
painter.setPen(QPen(Qt::yellow, 2));
for (int i = 0; i < m_Points.size()-1; ++i) {
// painter.drawEllipse(QPointF(m_Points[i].m_A,m_Points[i].m_B), 2, 2);
painter.drawLine(QPointF(m_Points[i].m_A,m_Points[i].m_B),QPointF(m_Points[i+1].m_A,m_Points[i+1].m_B));
}
}