1.问题描述与数学模型
给定 10 个控制点:P0(100,300),P1(200,230),P2(300,360),P3(360,150),
P4(480,520),P5(550,230),P6(660,30),P7(800,400),P8(850,400),P9(900,
500)。绘制颜色渐变的连续三次 B 样条曲线并用鼠标来确定控制点。
2.算法思想
基于对直线绘制类的使用,对 B 样条曲线进行变色处理,然后根据 B 样条的基函
数和 B 样条的分段参数表达式使用循环语句进行编译,再通过鼠标确定控制点绘
制 B 样条曲线。
3.程序设计步骤及流程图
(1)根据控制点坐标绘制控制多边形
(2)计算三次 B 样条基函数:
F0,3(t)=(-t*t*t+3*t*t-3*t+1)/6
F1,3(t)=(3*t*t*t-6*t*t+4)/6
F2,3(t)=(-3*t*t*t+3*t*t+3*t+1)/6
F3,3(t)=t*t*t/6
(3)设置曲线段绘制起点以及起点处颜色
(4)开启第一重重循环,循环次数为 7 次,分别绘制 7 段三次 B 样条曲线
(5)开启第一重重循环,循环控制变量 t 从 0 到 1,循环中计算四个 B 样条基
函数
(6)计算 Pi,3(t)=P[i].x*F03+P[i+1].x*F13+P[i+2].x*F23+P[i+3].x*F33 使
用直线连接曲线上的每一点,并用 t 调节对应点的颜色
(7)当 t<=1 时,返回步骤(5)
(8)当 i<=7 时,返回步骤(4)
4.实现源程序
//MY206XR.h
class CP2//二维点类
{
public:
CP2();
virtual~CP2();
CP2(double,double);
public :
double x;
double y;
};
class CLine//直线绘制类
{
public:
CLine();
virtual~CLine();
void SetLineColor(COLORREF);
void MoveTo(CP2);
void MoveTo(double,double);
void LineTo(CP2,CDC*);
void LineTo(double,double,CDC*);
public:
CP2 P0;
CP2 P1;
COLORREF clr;
};
//MY206XRView.h
void B3Spline(CDC*pDC);//绘制 B 样条曲线
//MY206XR.cpp
CP2::CP2()
{
}
x=0.0;
y=0.0;
CP2::~CP2()
{}
CP2::CP2(double x, double y)
{
}
this->x=x;
this->y=y;
CLine::CLine()
{}
CLine::~CLine()
{}
void CLine::SetLineColor(COLORREF color)
{
}
clr=color;
void CLine::MoveTo(CP2 p0)//记录直线起点函数
{
}
P0=p0;
void CLine::MoveTo(double x, double y)
{
P0.x=x;
P0.y=y;
}
void CLine::LineTo(double x, double y, CDC *pDC)
{
}
CP2 p;
p.x=x;
p.y=y;
LineTo(p,pDC);
void CLine::LineTo(CP2 p1, CDC *pDC)
{
P1=p1;
CP2 p,t;
if(fabs(P0.x-P1.x)<1e-6)
{
if(P0.y>P1.y)//交换顶点,使得起始点低于终点
{
}
t=P0;
P0=P1;
P1=t;
for(p=P0;p.y
SetPixelV(Round(p.x),Round(p.y),clr);
{
}
}
else
{
double k,d;
k=(P1.y-P0.y)/(P1.x-P0.x);
if(k>1.0)//绘制 k>1
{
if(P0.y>P1.y)
{
}
t=P0;
P0=P1;
P1=t;
d=1-0.5*k;
for(p=P0;p.ypDC->SetPixelV(Round(p.x),Round(p.y),clr);
if(d>=0)
{
}
p.x++;
d+=1-k;
else
d+=1;
{
}
}
if(0.0<=k&&k<=1.0)//绘制 0<=k<=1
{
if(P0.x>P1.x)
{
}
t=P0;
P0=P1;
P1=t;
d=0.5-k;
for(p=P0;p.x
SetPixelV(Round(p.x),Round(p.y),clr);
if(d<0)
{
}
p.y++;
d+=1-k;
else
d-=k;
}
}
if(k>=-1.0&&k<0.0)//绘制-1<=k<=0
{
if(P0.x>P1.x)
{
}
t=P0;
P0=P1;
P1=t;
d=-0.5-k;
for(p=P0;p.xSetPixelV(Round(p.x),Round(p.y),clr);
if(d>0)
{
}
p.y--;
d-=1+k;
else
d-=k;
}
}
if(k<-1.0)
{
if(P0.y
P1.y;p.y--)
pDC->SetPixelV(Round(p.x),Round(p.y),clr);
if(d<0)
{
}
p.x++;
d-=1+k;
else
d-=1;
{
}
}
}
P0=p1;
}
//MY206XRView.cpp
void CMy206XRView::B3Spline(CDC*pDC)
{
CP2 P[10];
P[0]=CP2(100,300);
P[1]=CP2(200,230);
P[2]=CP2(300,360);
P[3]=CP2(360,150);
P[4]=CP2(480,520);
P[5]=CP2(550,230);
P[6]=CP2(660,30);
P[7]=CP2(800,400);
P[8]=CP2(850,400);
P[9]=CP2(900,500);
CLine*line=new CLine;
line->SetLineColor(RGB(0,0,0));
line->MoveTo(P[0]);
for(int i=1;i<10;i++)
{
}
line->LineTo(P[i],pDC);
CP2 ps,pe;
ps.x=(P[0].x+4.0*P[1].x+P[2].x)/6.0;
ps.y=(P[0].y+4.0*P[1].y+P[2].y)/6.0;
line->SetLineColor(RGB(0,0,255));
line->MoveTo(ps);
for(int i=0;i<7;i++)
{
double delt=1.0/10;
double F03,F13,F23,F33;
for(double t=0;t<=1;t+=delt)
{
F03=(-t*t*t+3*t*t-3*t+1)/6;
F13=(3*t*t*t-6*t*t+4)/6;
F23=(-3*t*t*t+3*t*t+3*t+1)/6;
F33=t*t*t/6;
pe.x=P[i].x*F03+P[i+1].x*F13+P[i+2].x*F23+P[i+3].x*F33;
pe.y=P[i].y*F03+P[i+1].y*F13+P[i+2].y*F23+P[i+3].y*F33;
line->SetLineColor(RGB(int(i/7.0*255),int(t*255),int((1-t)*255)));
line->LineTo(pe,pDC);
}
}
delete line;
}
void CMy206XRView::OnMouseMove(UINT nFlags,CPoint point)
{
if(TRUE==m_AbleToMove)
P[m_i]=point;
m_i=-1;
int i;
for(i=0;i<9;i++)
{
if((point.x-P[i].x)*(point.x-P[i].x)+(point.y-P[i].y)*(point.y-P[i].y)<50)
{
}
m_i=i;
m_AbleToLeftBtn=TRUE;
SetCursor(LoadCursor(NULL,IDC_SIZEALL));
break;
}
if(10==i)
{
}
m_i=-1;
Invalidate(FALSE);
CView::OnMouseMove(nFlags,point);
}
void CMy206XRView::OnDraw(CDC*pDC)
{
}
CMy206XRDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
B3Spline(pDC);
// TODO: 在此处为本机数据添加绘制代码
5.典型测试结果