精华内容
下载资源
问答
  • 一、次参数样条曲线 次样条曲线的唯一缺点就是缺乏几何不变形。即当值点发生几何变换时不能保证参数递增。因此提出了以弦长为参数的次参数样条曲线。 1.1 定义 已知n个值点Pi(xi, yi), i = 1, 2,…, n且...

    在这里插入图片描述

    一、三次参数样条曲线

    三次样条曲线的唯一缺点就是缺乏几何不变形。即当型值点发生几何变换时不能保证参数递增。因此提出了以弦长为参数的三次参数样条曲线。

    1.1 定义

    已知n个型值点Pi(xi, yi), i = 1, 2,…, n且相邻型值点不重合;若 p(t) 满足下列条件:
    (1)型值点Pi在函数 p(t) 上。
    (2)p(t) 在整个区间[P1, Pn]上二阶连续可导。
    (3)在每个子区间[Pi, Pi+1], i = 1, 2,…, n-1上,分段函数 p(t) 都是参数t的三次多项式。则称函数 是过型值点的三次参数样条函数,由三次参数样条函数构成的曲线称为三次参数样条曲线。

    其中,
    在这里插入图片描述
    子区间的弦长Li为:
    在这里插入图片描述

    1.2 表达式

    第i段的 pi(t) 表示为:
    在这里插入图片描述

    总的来说,三次参数样条曲线就是在三次样条曲线基础上对xyz各分量分别进行参数化的曲线表达,如下:

    • 3个坐标分量x,y,z分别是参数 t 的三次样条函数
    • 对型值点做参数化
    • 对3个坐标分量分别处理

    1.3 算法

    (1)读入n个型值点坐标。
    (2)根据实际情况,确定三次参数样条曲线的边界条件。
    (3)计算曲线的系数,将其表达为型值点二阶导数的函数。
    (4)用追赶法分别沿x方向与y方向求解三弯矩方程。
    (5)将求解出的系数代入三次参数样条函数的x分量与y分量表达式中,构造三次参数样条曲线。
    (6)循环访问每个节点。在每个子区间内,参数t按照弦长计算增量,根据每组(x,y)坐标,绘制三次参数样条曲线。

    1.4 代码实现

    1.4.1 读取型值点

    首先我们需要来扩充以下二维点类p2.h与p2.cpp(主要如下):

    class CP2  
    {
    public:
    	CP2();
    	virtual ~CP2();
    	CP2(double x, double y);
    	friend CP2 operator +(const CP2 &p0, const CP2 &p1);//运算符重载
    	friend CP2 operator -(const CP2 &p0, const CP2 &p1);
    	friend CP2 operator -(double scalar, const CP2 &p);
    	friend CP2 operator -(const CP2 &p, double scalar);
    	friend CP2 operator *(const CP2 &p, double scalar);
    	friend CP2 operator *(double scalar, const CP2 &p);
    	friend CP2 operator /(const CP2 &p0, CP2 &p1);
    	friend CP2 operator /(const CP2 &p, double scalar);
    public:
    	double x;//直线段端点x坐标
    	double y;//直线段端点y坐标
    };
    
    CP2::CP2()
    {
    
    }
    
    CP2::~CP2()
    {
    
    }
    
    CP2::CP2(double x, double y)
    {
    	this->x = x;
    	this->y = y;
    }
    
    CP2 operator +(const CP2 &p0, const CP2 &p1)//对象的和
    {
    	CP2 result;
    	result.x = p0.x + p1.x;
    	result.y = p0.y + p1.y;
    	return result;
    }
    
    CP2 operator -(const CP2 &p0, const CP2 &p1)//对象的差
    {
    	CP2 result;
    	result.x = p0.x - p1.x;
    	result.y = p0.y - p1.y;
    	return result;
    }
    CP2 operator -(double scalar, const CP2 &p)//常量和对象的差
    {
    	CP2 result;
    	result.x = scalar - p.x;
    	result.y = scalar - p.y;
    	return result;
    }
    CP2 operator -(const CP2 &p, double scalar)//对象和常量的差
    {
    	CP2 result;
    	result.x = p.x - scalar;
    	result.y = p.y - scalar;
    	return result;
    }
    
    CP2 operator *(const CP2 &p, double scalar)//对象和常量的积
    {
    	return CP2(p.x * scalar, p.y * scalar);
    }
    
    CP2 operator *(double scalar, const CP2 &p)//常量和对象的积
    {	
    	return CP2(p.x * scalar, p.y * scalar);
    }
    
    CP2 operator /(const CP2 &p0, CP2 &p1)//对象的商
    {
    	if(fabs(p1.x)<1e-6)
    		p1.x = 1.0;
    	if(fabs(p1.y)<1e-6)
    		p1.y = 1.0;
    	CP2 result;
    	result.x = p0.x / p1.x;
    	result.y = p0.y / p1.y;
    	return result;
    }
    
    CP2 operator /(const CP2 &p, double scalar)//对象数除
    {
    	if(fabs(scalar)<1e-6)
    		scalar = 1.0;
    	CP2 result;
    	result.x = p.x / scalar;
    	result.y = p.y / scalar;
    	return result;
    }
    

    之后在主函数中定义读取函数:

    // CGeometricfiguretestViewmessage handlers
    void CGeometricfiguretestView::ReadPoint()
    {
    	P[1].x = -400, P[1].y = -150;
    	P[2].x = -100, P[2].y =  0;
    	P[3].x = -300, P[3].y =  100;
    	P[4].x =  0,   P[4].y =  200;
    	P[5].x =  300, P[5].y =  100;
    	P[6].x =  100, P[6].y =  0;
    	P[7].x =  400, P[7].y =  -150;
    }
    

    1.4.2 绘制型值点

    //绘制型值点
    void CGeometricfiguretestView::DrawDataPoint(CDC* pDC)
    {
    	CBrush NewBrush, *OldBrush;
    	NewBrush.CreateSolidBrush(RGB(0, 0, 0));
    	OldBrush = pDC->SelectObject(&NewBrush);
    	for(int i = 1; i < 8; i++)
    		pDC->Ellipse(ROUND(P[i].x - 5), ROUND(P[i].y - 5), ROUND(P[i].x + 5), ROUND(P[i].y + 5));
    	pDC->SelectObject(OldBrush);
    }
    

    1.4.3 三次参数样条曲线绘制

    三次参数样条曲线计算与绘制,具体过程见注释(计算与推导和三次样条曲线致):

    //三次参数样条曲线
    void CGeometricfiguretestView::DrawCubicSpline(CDC* pDC)
    {
    	int n = 7;
    	const int dim = 8;//二维数组维数
    	double b1 = 0, bn = 0;//起点和终点的一阶导数
    	double L[dim];//参数样条曲线的弦长
    	double lambda[dim], mu[dim];
    	double l[dim], m[dim], u[dim];
    	CP2 c1, cn;//起点和终点的方向余弦
    	CP2	D[dim];
        CP2 M[dim], K[dim];//追赶法过渡矩阵
        CP2 B1[dim], B2[dim], B3[dim], B4[dim];//函数的系数
    	CP2 delt[dim];
    	for(int i=1; i<n;i++)//计算弦长
        {
    		delt[i]=P[i+1]-P[i];
    		L[i]=sqrt(delt[i].x*delt[i].x+delt[i].y*delt[i].y);
    	}
    	//边界条件的投影
        c1.x = b1*cos(delt[1].x/L[1]);//起点
    	c1.y = b1*cos(delt[1].y/L[1]);
       	cn.x = bn*cos(delt[n-1].x/L[n-1]);//终点
    	cn.y = bn*cos(delt[n-1].y/L[n-1]);
    	for(int i = 2; i < n; i++)
    	{
    		lambda[i] = L[i-1]/(L[i-1]+L[i]);//计算λ
    		mu[i]=L[i]/(L[i-1]+L[i]);//计算μ
    		D[i]=6/(L[i-1]+L[i])*((P[i+1]-P[i])/L[i]-(P[i]-P[i-1])/L[i-1]);//计算D
        }
    	D[1]=6*((P[2]-P[1])/L[1]-b1)/L[1];//夹持端的D[1]
        D[n]=6*(bn-(P[n]-P[n-1])/L[n-1])/L[n-1];//夹持端的D[n]
        mu[1]=1;//夹持端的μ[1],
    	lambda[n]=1;//夹持端的λ[n]
    	//追赶法求解三弯矩方程
        l[1]=2;
    	u[1]=mu[1]/l[1];
        for(int i=2; i <= n; i++)
        {
    		m[i]=lambda[i];
            l[i]=2-m[i]*u[i-1];
            u[i]=mu[i]/l[i];
        }
        K[1] = D[1]/l[1];//解LK=D
        for(int i = 2; i <= n;i++)
        {
    		K[i]=(D[i]-m[i]*K[i-1])/l[i];
    	}
    	M[n] = K[n];//解UM=K
    	for(int i = n-1; i >= 1;i--)
    	{
    		M[i]=K[i]-u[i]*M[i+1];
    	}
    	//计算三次样条函数的系数
    	for(int i = 1; i < n; i++)
        {
    		B1[i]=P[i];
            B2[i]=(P[i+1]-P[i])/L[i]-L[i]*(M[i]/3+M[i+1]/6);
            B3[i]=M[i]/2;
            B4[i]=(M[i+1]-M[i])/(6*L[i]);
        }
    	CPen pen(PS_SOLID,3,RGB(0,0,0));
    	pDC->SelectObject(&pen);
    	pDC->MoveTo(ROUND(P[1].x), ROUND(P[1].y));
    	double tStep = 0.5;//步长
    	CP2 p;
    	for(int i = 1; i < n; i++)//循环访问每个节点
        {
    		for(double t=0; t <= L[i]; t += tStep)
    		{
    			p =B1[i]+B2[i]*t+B3[i]*t*t+B4[i]*t*t*t;
    			pDC->LineTo(ROUND(p.x), ROUND(p.y));//绘制参数样条曲线
            }
        }
    

    1.4.4 主函数调用

    void CGeometricfiguretestView::OnDraw(CDC* pDC)
    {
    	CTestDoc* pDoc = GetDocument();
    	ASSERT_VALID(pDoc);
    	if (!pDoc)
    		return;
    	// TODO: add draw code for native data here
    	CRect rect;//定义客户区矩形
    	GetClientRect(&rect);//获得客户区矩形的信息
    	pDC->SetMapMode(MM_ANISOTROPIC);//自定义二维坐标系
    	pDC->SetWindowExt(rect.Width(), rect.Height());//设置窗口范围
    	pDC->SetViewportExt(rect.Width(), -rect.Height());//设置视区范围,且x轴水平向右为正,y轴垂直向上为正
    	pDC->SetViewportOrg(rect.Width() / 2, rect.Height() / 2);//设置客户区中心为二维坐标系原点
    	rect.OffsetRect(-rect.Width() / 2, -rect.Height() / 2);//rect矩形与客户区重合
    	ReadPoint();
    	DrawDataPoint(pDC);
    	DrawCubicParameterSpline(pDC);
    }
    

    编译运行,可见如下:

    在这里插入图片描述
    我们也可以改变一下边界约束条件:

    double b1 = 1, bn = 1;//起点和终点的一阶导数
    

    在这里插入图片描述

    二、Cardinal曲线

    2.1 Hermite基矩阵

    Hermite的每个曲线两个端点的坐标和导数来定义。
    在这里插入图片描述
    假设Hermite样条曲线的方程可以写成矩阵形式,如下:
    在这里插入图片描述
    将边界条件p(0)=yi和p(1)=yi+1代入上式,得:

    yi ﹦d,yi+1﹦a﹢b﹢c﹢d

    且上式的一阶导数为:

    在这里插入图片描述
    将边界条件p’(0)=Ri和p’(1)=Ri+1带入上式,得:

    Ri ﹦c,Ri+1﹦3a﹢2b﹢c

    Hermite边界条件的矩阵表示为:
    在这里插入图片描述

    该方程对多项式系数求解,有:
    在这里插入图片描述
    式中,Mh称为Hermite基矩阵,是边界约束矩阵的逆矩阵。需要说明的是,弗格森于1963年用于飞机设计的均匀参数插值三次样条方程就是Mh。
    在这里插入图片描述
    因此,可得:
    在这里插入图片描述
    最终可得到:
    在这里插入图片描述

    2.2 Cardinal曲线

    Cardinal样条是Hermite样条的变形,仅由相邻型值点的坐标就可以计算出导数。

    设相邻的四个型值点分别记为Pi-1, Pi, Pi+1,Pi+2。Cardinal样条插值方法规定Pi, Pi+1两型值点间插值多项式的边界条件为:
    在这里插入图片描述

    式中, u为可调参数,称为张力参数,可以控制Cardinal样条曲线型值点间的松紧程度。
    记s=(1-u)/2,用类似Hermite曲线样条中的方法,将Cardinal边界条件代入下边的参数方程,
    在这里插入图片描述

    可以得到矩阵表达式:
    在这里插入图片描述

    式中,Mc称为Cardinal矩阵。

    一条Cardinal样条曲线完全由四个连续的型值点给出,中间两个型值点是曲线段端点,另外两个型值点用来辅助计算端点导数。只要给出一组型值点的坐标值,就可以分段绘制出Cardinal样条曲线。

    2.3 Cardinal 算法

    (1)读入n个型值点坐标Pi,i=1,2,…n。
    (2)在两端各加入一个虚拟点P0和Pn+1。
    (3)设置张力参数u值,计算Cardinal基矩阵Mc。
    (4)计算Mc矩阵与边界条件矩阵的算法,每4个顶点构成一个条件矩阵。
    (5)根据型值点个数计算每段曲线中插值参数t的值,使用直线段连接对应的点p(x(t),y(t))绘制曲线。

    2.4 代码实现

    1.4.1 读取型值点

    void CGeometricfiguretestView::ReadPoint()
    {
    	P[0].x =-500, P[0].y =0;
    	P[1].x =-450, P[1].y =-100;
    	P[2].x =-350, P[2].y =-250;
    	P[3].x =-250, P[3].y = 200;
    	P[4].x =-150, P[4].y = 100;
    	P[5].x =-50,  P[5].y = 150;
    	P[6].x = 40, P[6].y = 10;
    	P[7].x = 100, P[7].y = -60;
    	P[8].x = 150, P[8].y = 80;
    	P[9].x = 200, P[9].y = 70;
    	P[10].x =230,P[10].y =-10;
    	P[11].x =300,P[11].y =-200;
    	P[12].x =400,P[12].y = 150;
    	P[13].x =520,P[13].y = 250;
    	n = 13;
    }
    

    1.4.2 绘制型值点

    void CGeometricfiguretestView::DrawDataPoint(CDC* pDC)//绘制型值点
    {
    	CBrush NewBrush, *pOldBrush;
    	NewBrush.CreateSolidBrush(RGB(0, 0, 0));
    	pOldBrush = pDC->SelectObject(&NewBrush);
    	for( int i = 1; i < 13; i++)
    		pDC->Ellipse(ROUND(P[i].x - 5), ROUND(P[i].y - 5), ROUND(P[i].x + 5), ROUND(P[i].y + 5));
    	pDC->SelectObject(pOldBrush);
    	pDC->Ellipse(ROUND(P[0].x - 5), ROUND(P[0].y - 5), ROUND(P[0].x + 5), ROUND(P[0].y + 5));
    	pDC->Ellipse(ROUND(P[13].x - 5), ROUND(P[13].y - 5), ROUND(P[13].x + 5), ROUND(P[13].y + 5));
    }
    

    1.4.3 计算与绘制

    void CGeometricfiguretestView::DrawCardinalCurve(CDC* pDC)//Cardinal曲线
    {
    	double M[4][4];
    	double u=0.2;
    	double s=(1-u)/2;
    	CP2 p;
    	M[0][0]=-s ,M[0][1]=2-s,M[0][2]= s-2 ,M[0][3]= s;//Mc矩阵
    	M[1][0]=2*s,M[1][1]=s-3,M[1][2]=3-2*s,M[1][3]=-s;
    	M[2][0]=-s ,M[2][1]= 0 ,M[2][2]=  s  ,M[2][3]= 0;
    	M[3][0]= 0 ,M[3][1]= 1 ,M[3][2]=  0  ,M[3][3]= 0;
    	double t3,t2,t1,t0;
    	CPen pen(PS_SOLID,2,RGB(0,0,0));
    	CPen* pOldPen=pDC->SelectObject(&pen);
    	pDC->MoveTo(ROUND(P[1].x),ROUND(P[1].y));
    	for(int i=0; i< n-2; i++)
    	{
    		Point[0]=P[i],Point[1]=P[i+1],Point[2]=P[i+2],Point[3]=P[i+3];
    		MultiplyMatrix(M, P, i);
    		double tStep = 0.001;
    		for(double t=0.0; t<1; t += tStep)
    		{
    			t3 = t*t*t; t2 = t*t; t1 = t; t0 = 1;
    			p = t3*Point[0] + t2*Point[1] + t1*Point[2] + t0*Point[3];
    			pDC->LineTo(ROUND(p.x),ROUND(p.y));
    		}
    	}
    	pDC->SelectObject(pOldPen);
    }
    
    void CGeometricfiguretestView::MultiplyMatrix(double M0[][4], CP2 P0[4], int n)
    {
    	for(int i=0;i<4;i++)
    		Point[i] = M0[i][0]*P0[n] + M0[i][1]*P0[n+1] + M0[i][2]*P0[n+2] + M0[i][3]*P0[n+3];
    }
    

    其中定义MultiplyMatrix函数为了实现4x4的Mc矩阵与1x4的边界约束矩阵的乘法计算。

    编译运行,如下:
    在这里插入图片描述

    我们也可以改变一下张力参数来试一下:

    double u=1.0;
    

    在这里插入图片描述

    展开全文
  • MFC绘制次Cardinal曲线 参考《计算几何算法与实现》–孔令德 给定12个值点,绘制Cardinal曲线: 1、新建MFC单文档程序 2、添加二维点类: #pragma once //为了避免按照x和y方向进行重复运算,重载运算对象 ...

    MFC绘制三次Cardinal曲线


    在这里插入图片描述
    在这里插入图片描述

    参考《计算几何算法与实现》–孔令德

    给定12个型值点,绘制Cardinal曲线:
    1、新建MFC单文档程序
    2、添加二维点类:

    #pragma once
    //为了避免按照x和y方向进行重复运算,重载运算对象
    class CP2
    {
    public:
    	CP2(void);
    	~CP2(void);
    	CP2(double x,double y);
    	friend CP2 operator+(const CP2&p0,const CP2&p1);//运算符重载
    	friend CP2 operator-(const CP2&p0,const CP2&p1);
    	friend CP2 operator-(double scalar,const CP2&p);
    	friend CP2 operator-(const CP2&p,double scalar);
    	friend CP2 operator*(const CP2&p,double scalar);
    	friend CP2 operator*(double scalar,const CP2&p);
    	friend CP2 operator/(const CP2&p0,const CP2&p1);
    	friend CP2 operator/(const CP2&p,double scalar);
    
    public:
    	double x;
    	double y;
    };
    
    #include "StdAfx.h"
    #include "P2.h"
    #include"math.h"
    
    CP2::CP2(void)
    {
    }
    
    
    CP2::~CP2(void)
    {
    }
    
    CP2::CP2(double x,double y)
    {
    	this->x=x;
    	this->y=y;
    }
    
     CP2 operator+(const CP2&p0,const CP2&p1)//运算符重载
     {
    	 CP2 result;
    	 result.x=p0.x+p1.x;
    	 result.y=p0.y+p1.y;
    	 return result;
     }
     CP2 operator-(const CP2&p0,const CP2&p1)
     {
    	 CP2 result;
    	 result.x=p0.x-p1.x;
    	 result.y=p0.y-p1.y;
    	 return result;
     }
     CP2 operator-(double scalar,const CP2&p)
     {
    	 CP2 result;
    	 result.x=scalar-p.x;
    	 result.y=scalar-p.y;
    	 return result;
     }
     CP2 operator-(const CP2&p,double scalar)
     {
    	 CP2 result;
    	 result.x=p.x-scalar;
    	 result.y=p.y-scalar;
    	 return result;
     }
     CP2 operator*(const CP2&p,double scalar)
     {
    	 return CP2(p.x*scalar,p.y*scalar);
     }
     CP2 operator*(double scalar,const CP2&p)
     {
    	 return CP2(p.x*scalar,p.y*scalar);
     }
     CP2 operator/(const CP2&p0, CP2&p1)
     {
    	 if(fabs(p1.x)<1e-6)
    	 {
    		 p1.x=1.0;
    	 }
    	 if(fabs(p1.y)<1e-6)
    	 {
    		 p1.y=1.0;
    	 }
    	 CP2 result;
    	 result.x=p0.x/p1.x;
    	 result.y=p0.y/p1.y;
    	 return result;
     }
     CP2 operator/(const CP2&p,double scalar)
     {
    	 if(fabs(scalar)<1e-6)
    	 {
    		 scalar=1.0;
    	 }
    	 if(fabs(scalar)<1e-6)
    	 {
    		 scalar=1.0;
    	 }
    	 CP2 result;
    	 result.x=p.x/scalar;
    	 result.y=p.y/scalar;
    	 return result;
     }
    
    

    2、在View中包含头文件:

    #include"P2.h"
    #include"math.h"
    #define ROUND(h) int(h+0.5)
    

    添加变量

    	CP2 P[14];//型值点
    	CP2 Point[4];//矩阵运算的点
    	int n;//型值点最大值
    

    添加函数

    	void ReadPoint(void);//读取点
    	void MultiplyMatrix(double M[4][4],CP2 P[4],int n);//矩阵计算
    	void DrawDataPoint(CDC*pDC);//加粗型值点
    	void DrawCardinalCurve(CDC*pDC);//绘制曲线
    
    void CDrawCardinalCurveView::ReadPoint(void)
    {
    	P[0].x =-500, P[0].y =0;
    	P[1].x =-450, P[1].y =-100;
    	P[2].x =-350, P[2].y =-250;
    	P[3].x =-250, P[3].y = 200;
    	P[4].x =-150, P[4].y = 100;
    	P[5].x =-50,  P[5].y = 150;
    	P[6].x = 40, P[6].y = 10;
    	P[7].x = 100, P[7].y = -60;
    	P[8].x = 150, P[8].y = 80;
    	P[9].x = 200, P[9].y = 70;
    	P[10].x =230,P[10].y =-10;
    	P[11].x =300,P[11].y =-200;
    	P[12].x =400,P[12].y = 150;
    	P[13].x =520,P[13].y = 250;
    }
    void CDrawCardinalCurveView::MultiplyMatrix(double M[4][4],CP2 P[4],int n)
    {
    	for(int i=0;i<4;i++)
    	{
    		Point[i]=M[i][0]*P[n]+M[i][1]*P[n+1]+M[i][2]*P[n+2]+M[i][3]*P[n+3];
    	}
    }
    void CDrawCardinalCurveView::DrawDataPoint(CDC*pDC)//绘制型值点
    {
    	CBrush NewBrush, *pOldBrush;
    	NewBrush.CreateSolidBrush(RGB(0, 0, 0));
    	pOldBrush = pDC->SelectObject(&NewBrush);
    	for( int i = 1; i < 13; i++)
    		pDC->Ellipse(ROUND(P[i].x - 5), ROUND(P[i].y - 5), ROUND(P[i].x + 5), ROUND(P[i].y + 5));
    	pDC->SelectObject(pOldBrush);
    	pDC->Ellipse(ROUND(P[0].x - 5), ROUND(P[0].y - 5), ROUND(P[0].x + 5), ROUND(P[0].y + 5));
    	pDC->Ellipse(ROUND(P[13].x - 5), ROUND(P[13].y - 5), ROUND(P[13].x + 5), ROUND(P[13].y + 5));
    }
    void CDrawCardinalCurveView::DrawCardinalCurve(CDC*pDC)
    {
    	double M[4][4];
    	double u=1;
    	double s=(1-u)/2;
    	CP2 p;
    	M[0][0]=-s ,M[0][1]=2-s,M[0][2]= s-2 ,M[0][3]= s;//Mc矩阵
    	M[1][0]=2*s,M[1][1]=s-3,M[1][2]=3-2*s,M[1][3]=-s;
    	M[2][0]=-s ,M[2][1]= 0 ,M[2][2]=  s  ,M[2][3]= 0;
    	M[3][0]= 0 ,M[3][1]= 1 ,M[3][2]=  0  ,M[3][3]= 0;
    	double t3,t2,t1,t0;
    	CPen pen(PS_SOLID,2,RGB(0,0,0));
    	CPen*pOldPen=pDC->SelectObject(&pen);
    	pDC->MoveTo(ROUND(P[1].x),ROUND(P[1].y));
    	for(int i=0;i<11;i++)
    	{
    		Point[0]=P[i],Point[1]=P[i+1],Point[2]=P[i+2],Point[3]=P[i+3];
    		MultiplyMatrix(M,P,i);
    		double tStep=0.001;
    		for(double t=0.0;t<1.0;t+=tStep)
    		{
    			t3=t*t*t,t2=t*t,t1=t,t0=1;
    			p=t3*Point[0]+t2*Point[1]+t1*Point[2]+t0*Point[3];
    			pDC->LineTo(ROUND(p.x),ROUND(p.y));
    		}
    	}
    	pDC->SelectObject(pOldPen);
    }
    

    最后在OnDraw中添加

    	CRect rect;//定义客户区矩形
    	GetClientRect(&rect);//获得客户区矩形的信息
    	pDC->SetMapMode(MM_ANISOTROPIC);//自定义二维坐标系
    	pDC->SetWindowExt(rect.Width(), rect.Height());//设置窗口范围
    	pDC->SetViewportExt(rect.Width(), -rect.Height());//设置视区范围,且x轴水平向右为正,y轴垂直向上为正
    	pDC->SetViewportOrg(rect.Width() / 2, rect.Height() / 2);//设置客户区中心为二维坐标系原点
    	rect.OffsetRect(-rect.Width() / 2, -rect.Height() / 2);//rect矩形与客户区重合
    	ReadPoint();
    	DrawDataPoint(pDC);
    	DrawCardinalCurve(pDC);
    
    展开全文
  • 参考 # -- coding: utf-8 -- @Project: lecture @Time : 2020/4/29 21:54 @Author : Yang xu @Site : @File : parameter equation.py @IDE: PyCharm ... def __init__(self, p, p_): self.p = p #
  • Koch曲线

    2018-04-29 15:37:41
    算法设计每次等分时,由起始点p1, p2生成曲线三等分坐标w1, w2, w3, w4w1=p1;w2=p1+(p2-p1)/3;w3=w2+(p2-p1)/3*[cos(pi)/3, ...function my_exam(p,n)%p表示初始点,n表示分次数,由于增长为指数,不宜超过8A=[c...

    算法设计

    每次等分时,由起始点p1, p2生成曲线三等分坐标w1, w2, w3, w4

    w1=p1;

    w2=p1+(p2-p1)/3;

    w3=w2+(p2-p1)/3*[cos(pi)/3, sin(pi)/3; -sin(pi)/3, cos(pi)/3];

    w4=p1+2*(p2-p1)/3;

    function my_exam(p,n)
    %p表示初始点,n表示三分次数,由于增长为指数型,不宜超过8
    A=[cos(pi/3) sin(pi/3);-sin(pi/3) cos(pi/3)];
    [s,t]=size(p);
    m=s-1;
    for k=1:n
        j=0;
        for i=1:m
            q1=p(i,:); %提取p的第i行
            q2=p(i+1,:);
            d=(q2-q1)/3;
            j=j+1;
            w(j,:)=q1;
            j=j+1;
            w(j,:)=q1+d;
            j=j+1;
            w(j,:)=q1+d+d*A;
            j=j+1;
            w(j,:)=q1+2*d;
        end
        m=4*m;%?
        p=[w;q2];
    end
    plot(p(:,1),p(:,2),'k')
    axis off
    p=[0,0;10,0];
    my_exam(p,6)
    p=[0,0;5,5*sqrt(3);10,0;0,0];
    my_exam(p,1)
    my_exam(p,6)


    展开全文
  • <p>针对加速度驱动型三关节体操机器人, 从机理和数据两方面进行了动力学模型分析. 首先通过机理分析得 到模型的刚体动力学分量和电机驱动分量; 然后通过加速度阶跃响应曲线分析得到纯滞后分量. 综合这3 种分量,...
  • 23.用次样条函数去模拟汽车车门的曲线,车门曲线值点数据如下 (P89页) : `%%% function f=cf(y) p=length(y); for k=1:p-1; f(k)=y(k+1)-y(k); end %%% function [lk,mk,ek]=jh(x,h,f) n=length(x);...

    23.用三次样条函数去模拟汽车车门的曲线,车门曲线的型值点数据如下 (P89页) :
    在这里插入图片描述

    `%%%
    function f=cf(y)
     p=length(y);
     for k=1:p-1;
         f(k)=y(k+1)-y(k);
     end
    %%%
     function [lk,mk,ek]=jh(x,h,f)
     n=length(x);
     for k=2:n-1;
         lk(k)=h(k)/(h(k-1)+h(k));
         mk(k)=h(k-1)/(h(k-1)+h(k));
         ek(k)=3*(lk(k)*f(k-1)+mk(k)*f(k));
     end
    %%%
     function h=bc(x)
     n=length(x);
     for k=1:n-1;
         h(k)=x(k+1)-x(k);
     end
    %%%
    x=[0,1,2,3,4,5,6,7,8,9,10];
    y=[2.51,3.30,4.04,4.70,5.22,5.54,5.78,5.40,5.57,5.70,5.80];
    h=bc(x)
    f=cf(y)
    [lk,mk,ek]=jh(x,h,f)
    m1=0.8;
    m11=0.2;
    A=[2 mk(2) 0 0 0 0 0 0 0;lk(3) 2 mk(3) 0 0 0 0 0 0;0 lk(4) 2 mk(4) 0 0 0 0 0;...
        0 0 lk(5) 2 mk(5) 0 0 0 0;0 0 0 lk(6) 2 mk(6) 0 0 0;0 0 0 0 lk(7) 2 mk(7) 0 0;...
        0 0 0 0 0 lk(8) 2 mk(8) 0;0 0 0 0 0 0 lk(9) 2 mk(9);0 0 0 0 0 0 0 lk(9) 2]
    B=[ek(2)-lk(2)*m1;ek(3);ek(4);ek(5);ek(6);ek(7);ek(8);ek(9);ek(10)-mk(10)*m11]
    C=A\B
    m2=C(1);m3=C(2);m4=C(3);m5=C(4);m6=C(5);m7=C(6);m8=C(7);m9=C(8);m10=C(9);
    m=[m1 m2 m3 m4 m5 m6 m7 m8 m9 m10 m11]
    for i=1:10;
        x1=[i-1:0.00001:i]
        s1=(x1-x(i+1)).^2.*(h(i)+2.*(x1-x(i))).*y(i)/h(i).^3;
        s2=(x1-x(i)).^2.*(h(i)+2.*(x(i+1)-x1)).*y(i+1)/h(i).^3;
        s3=(x1-x(i+1)).^2.*(x1-x(i)).*m(i)/(h(i).^2);
        s4=(x1-x(i)).^2.*(x1-x(i+1))*m(i+1)/(h(i).^2);
        s=s1+s2+s3+s4;
        plot(x,y,'bo-',x1,s,'--red')
        hold on
     end
     axis([0 10 0 8]);
     title('汽车车门的三次插值样条曲线')
     xlabel('插值点横坐标X');
     ylabel('插值点纵坐标Y');
    %%%
    function createfigure(X1, Y1, X2, Y2, X3, Y3, X4, Y4, X5, Y5, X6, Y6, X7, Y7, X8, Y8, X9, Y9, X10, Y10, X11, Y11)
    %CREATEFIGURE(X1, Y1, X2, Y2, X3, Y3, X4, Y4, X5, Y5, X6, Y6, X7, Y7, X8, Y8, X9, Y9, X10, Y10, X11, Y11)
    %  X1:  x 数据的矢量
    %  Y1:  y 数据的矢量
    %  X2:  x 数据的矢量
    %  Y2:  y 数据的矢量
    %  X3:  x 数据的矢量
    %  Y3:  y 数据的矢量
    %  X4:  x 数据的矢量
    %  Y4:  y 数据的矢量
    %  X5:  x 数据的矢量
    %  Y5:  y 数据的矢量
    %  X6:  x 数据的矢量
    %  Y6:  y 数据的矢量
    %  X7:  x 数据的矢量
    %  Y7:  y 数据的矢量
    %  X8:  x 数据的矢量
    %  Y8:  y 数据的矢量
    %  X9:  x 数据的矢量
    %  Y9:  y 数据的矢量
    %  X10:  x 数据的矢量
    %  Y10:  y 数据的矢量
    %  X11:  x 数据的矢量
    %  Y11:  y 数据的矢量
    %  由 MATLAB 于 04-Nov-2018 18:57:48 生成
    % 创建 figure
    figure1 = figure;
    % 创建 axes
    axes1 = axes('Parent',figure1);
    hold(axes1,'on');
    % 创建 plot
    plot(X1,Y1,'Marker','o','Color',[0 0 1]);
    % 创建 plot
    plot(X2,Y2);
    % 创建 plot
    plot(X3,Y3);
    % 创建 plot
    plot(X4,Y4);
    
    % 创建 plot
    plot(X5,Y5);
    % 创建 plot
    plot(X6,Y6);
    % 创建 plot
    plot(X7,Y7);
    % 创建 plot
    plot(X8,Y8);
    % 创建 plot
    plot(X9,Y9);
    % 创建 plot
    plot(X10,Y10);
    % 创建 plot
    plot(X11,Y11,'LineStyle','--','Color',[1 0 0]);
    % 创建 xlabel
    xlabel('插值点横坐标X','FontSize',11);
    % 创建 title
    title('汽车车门的三次插值样条曲线','FontSize',11);
    % 创建 ylabel
    ylabel('插值点纵坐标Y','FontSize',11);
    % 取消以下行的注释以保留坐标轴的 X 范围
    % xlim(axes1,[0 10]);
    % 取消以下行的注释以保留坐标轴的 Y 范围
    % ylim(axes1,[0 8]);
    box(axes1,'on');
    % 创建 textarrow
    annotation(figure1,'textarrow',[0.728928571428571 0.7075],...
        [0.468095238095238 0.660476190476191],'String',{'三次样条函数插值曲线'});
    % 创建 textarrow
    annotation(figure1,'textarrow',[0.520833333333333 0.559895833333333],...
        [0.533720930232558 0.686046511627907],'String',{'   用线段连接插值点'});
    % 创建 textarrow
    annotation(figure1,'textarrow',[0.384895833333333 0.364583333333333],...
        [0.436046511627907 0.582558139534884],'String',{'插值点'});`
    
    展开全文
  • (26)二次插值样条曲线

    万次阅读 2017-01-01 21:49:06
    在拟合生成样条曲线的众多方法中,首先来讨论用插值方法生成通过给定离散值点的二次样条曲线,即抛物样条曲线。 已知不在同一直线上的三点P1、P2、P3,要求通过给定的这三点定义一条抛物线。   二次样条曲线的...
  • Bezier曲线类的构造

    2012-05-19 17:36:44
    尽管如今在CAD 领域有许多种不同的自由型曲线和曲面的构造方法, 但使用Bezier 曲线 仍不失为一种重要的备选方案. 例如国内外多种矢量字库的构建, 仍然广泛使用Bezier 曲线技 术. Bezier 曲线的实现方法传统上主要...
  • 场效应管分结(JFET)、绝缘栅型(MOSFET)两大类。按沟道材料和绝缘栅型各分N沟道和P沟道两种;按导电方式:耗尽与增强,结场效应...结场效应管也具有个电极,它们是:栅极;漏极;源极。电路符号中栅极的
  • 在以前的论文中(Nie等人在JHEP 1311:087,arXiv:1309.2204 [hep-th],2013年),我们提出了一个全息s + p超导体模型,其标量重态在SU(2)规场下充电 散装。 我们还研究了探针极限中s波和p波阶的竞争和共存。 ...
  • P ro/E 中完成5 自由度机械手及其手爪的维造型和装配, 通过P ro/E 和A D A M S 的接口M echanism /P ro 将模型导入A D A M S /V IE W 中, 并进行运动学仿真, 得到其未端位移和速度的分析曲线, 为实际的机器人...
  • 在试验所获得的滞回曲线和骨架曲线的基础上建立了适合于型钢高强高性能混凝土框架节点的考虑刚度退化的三线恢复力模型。该恢复力模型包括一条基于计算的三折线骨架曲线模型、刚度退化规律以及基于试验现象的滞回...
  • React/Vue/Angular 大框架互相学习进步,整体上没有大的短板了,选择哪个都可以。其中,React以JS为核心,JSX格外强大且不影响UI的声明式表达。Vue追求平衡中庸,追求符合规范ÿ...
  • 次B样条插值和误差分析

    万次阅读 2018-07-27 20:10:46
    前言:之前写写过一篇B样条曲线,这篇是原文的深度扩展,是针对B样条曲线的一种特殊情况,次B样条,讨论了其插值和误差分析,添加了一些个人总结。 思路:根据已知的值点(就是给出的已知的数据点),采用均匀...
  • 根据支架围岩关系的基本原理,对王村矿“软”煤层采面的支架围岩关系进行了分析,确定了该采区的采面直接顶刚度具有关键作用,为中间刚度直接顶,P—Δl为双曲线关系,支架的合理工作范围为600~2000kN/架,原设计的...
  • 研究了叠加态光场与级联型三能级原子相互作用过程中场熵的压缩特性。数值计算结果表明:场为真空态和单光子数态的叠加态时,光场熵的压缩特性与决定叠加态的几率幅参数有密切关系。位置熵的演化曲线p的变化呈现出...
  • 根据2012年疣梭子蟹放流前后的渔业资源调查数据,借助大型多元统计软件 PRIMER的聚类分析、多维排序尺度、相似性分析以及生物量丰度曲线分析功能,对山东半岛南部各放流海湾渔业生物群落结构进行了分析....
  • https://www.jianshu.com/p/b8ded87e0c0c   常用的激活函数有种: 1.Sigmoid or Logistic 2.Tanh-双曲正切 ...这是一个S型曲线,容易理解和使用,但是有缺陷:1)消失的梯度问题, 2)输出不是以0...
  • PNP三极管分析方法

    2020-07-12 21:57:32
    通过观察可以发现,npn晶体管的输入输出特性曲线都在第一象限,而pnp晶体管的在第象限。说明pnp晶体管的电流和电压都和npn晶体管的相反,那么在分析pnp晶体管的工作状态时,就可以将其电压和电流取绝对值...
  • 求解方程后,代入参数在MATLAB中对两层结构的n+/p- sub和n- well/p- sub,以及层结构的p+/n- well/p- sub二极管进行了计算模拟,得到了3种二极管响应率与波长的关系曲线。最后将结果与实际值进行了对比分析...
  • 图形学个人笔记

    2016-10-18 21:16:55
    曲线和曲面的表示方程有参数表示(P(t)=[x(t),y(t),z(t))]和非参数表示之分,非参数表示又分为显示表示(y=f(x))和隐世表示(f(x,y)=0)。 显示表示可以满足几何不变性的要求,有更大的自由度来控制曲线曲面的形状...
  • 然后再根据模拟结果对山东半岛波浪分布情况进行了研究,运用P-Ⅲ型曲线对黄河三角洲、成山头、青岛的斋堂岛这3处进行极值统计,得到不同重现期条件下的波浪要素。研究结果表明山东半岛波浪最大处在成山头。
  • 组建暗黑齿爪鳃金龟生命期望表和生殖力表表明,在室温...世代种群存活率曲线为Weibull分布曲线:S_p(t)=exp[-(t/2.7082) ̄(4.6827))。种群自然增长过程符合二次项式经验曲线方程:logY=-0.6689+0.3264X-0.0243X ̄2。
  • 椭圆拟合算法总结

    万次阅读 2015-07-31 15:26:38
    椭圆拟合算法 椭圆拟合在医疗图像、工程设计、交通识别、生物识别、人工智能、林火蔓延等领域具有广泛应用,本文总结前人研究综合出基于MATLAB的种椭圆拟合的算法:直接计算方法,二次...% 拟合椭圆型曲线段 clo
  • 根据已有的夏比V缺口冲击试验数据,建立了冲击试验吸收能与试验温度和韧脆转变温度之间的曲线关系,提出了不同强度不同质量等级船用钢板厚度、使用温度和断裂韧性者之间函数关系,并结合P-S-N曲线的思想,引入了...
  • 结合自适应多目标差分进化算法、基于3次非均匀B样条曲线的曲面造型技术及透平级气动和强度性能分析评价方法,建立了长叶片透平级多学科多目标优化设计系统,其中气动性能评估采用数值求解维RANS方程完成,长叶片强度...
  • 激活函数

    2018-10-26 16:35:49
    激活函数一. Sigmoid 函数sigmoid基本性质...Sigmoid函数是一个在生物学中常见的S函数,也称为S生长曲线。在信息科学中,由于其单增以及反函数单增等性质,Sigmoid函数常被用作神经网络的阈值函数,将变量映射到...
  • 内容提要 【了解】半导体的相关知识 【熟悉】...热激发:自由电子-空穴对、载流子、复合、浓度(微量,温度影响) 与掺杂半导体:N(五价磷)、P型半导体(价硼)、多子、少子;3.PN结:扩散、不能移动的离子、空间电
  • S.P纽曼模型仅是本法未计滞后疏干的特例,其水位解不符合实测“阶段”式,文中图示了降深曲线随各参变量的演变规律,并从弹性给水度(μe)、滞后指数与岩性的关系,论证了毛管和边界层滞水较弹性给水度影响的...
  • 场效应管FET

    2019-08-25 20:28:31
    1.JFET传输特性曲线 图一 图二 图 1.N沟道 GS加负电压,P沟道GS加正向电压。 2.通过改变GS电压,改变栅极和衬底PN结耗尽层的大小,从而改变沟道大小来控制电流大小。 3.Idss 和Gm分散性比较大。由Idss...

空空如也

空空如也

1 2 3 4 5
收藏数 94
精华内容 37
关键字:

p三型曲线