计算机图形学--全部实验的实验报告

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

一、实验目的
根据曲线和曲面的基础知识和常用曲线的数学基础,对其算法进行程序设计,验证算法的正确性,并通过程序结果加深对常用曲线数学模型的理解。

二、实验任务
1.抛物线程序设计;
2.Hermite 曲线程序设计;
3.Bezier曲线的算法实现;
4.B样条曲线的程序设计
三、实验内容和实验步骤
任务一:抛物线程序设计
实现抛物线算法的C语言程序段如下:(工程名:parabola)
Par(int xs,int ys,int xm,int ym,int xe,int ye) //已知起点、中点和终点三个控制点的坐标
{
double t,dt,ax,ay,bx,by,cx,cy;
int n,i;
ax=xe-2*xm+xs;
ay=ye-2*ym+ys;
bx=2.0*(xm-xs);
by=2.0*(ym-ys);
cx=xs; cy=ys;
n=sqrt(ax*ax+ay*ay);
n=sqrt(n*100.0);
moveto(xs,ys);
dt=1.0/n; t=0;
for (i=0;i<=n; i++)
{
lineto((int)(ax*t*t+bx*t+cx),(int)( ay*t*t+by*t+cy));
t=t+dt;
}
lineto(xe,ye);
}
读者可以根据上述抛物线程序设计,写出抛物线参数样条曲线的程序。

任务二:Hermite 曲线程序设计
P(t)=FB=TMB=[ t3 t2 t 1 ]
程序设计时只考虑二维图形的显示,其代数形式为:
x(t)=TMBx , Bx =[ P0x P1x R0x R1x]T
y(t)= TMBy , By =[ P0y P1y R0y R1y]T
所以,只要给出Hermite曲线的起点坐标(P0x,P0y),终点坐标(P1x,P1y),以及起点处的切矢量(R0x,R0y)和终点处的切矢量(R1x,R1y),参数变量t在[0,1]的范围内分别取0.01,0.02,…,1,步长为0.01,取100个点,分别求出P(t)=[ x(t),y(t)],在计算机屏幕上显示出每个坐标点,即可绘出Hermite曲线。

任务三:Bezier曲线的算法实现
(1)算法描述
根据 Q(t)=ΣPi•Bi,n(t) = ΣPi• C in ti(1-t)n-i
并且C in =C(n,k)= C(n,k-1)
Bezier曲线的C语言算法描述如下:
#include <math.h>
#include <graphics.h>
void computeCoefficients(int n, int *c)
int k, i;
for (k=0;k<=n;k++) /*求C kn =n!/(k!(n-k)!= )*/
{
int c[k]=1;
for (i=n; i>=k+1; i--) /*求c[k]=n*(n-1)…(k+1) */
c[k]*=i;
for (i=n-k; i>=2; i--) /*求c[k]/(n-k)!*/
c[k]/=i;
}
}
void computepoint(float t,wcPt3 *pt,int ncontrols,wcPt3 *controls,int *c)
int i, n=ncontrols-1;
float blend;
pt->x=0.0; pt->y=0.0; pt->z=0.0;
for (i=0; i<ncontrols; i++)
{
blend = c[k]*powf(t,i)*powf(1-t,n-i); /*求C kn ti(1-t)n-i */ pt->x+=controls[i].x*blend; /*求x(t)*/
pt->y+=controls[i].y*blend; /*求y(t)*/
pt->z+=controls[i].z*blend; /*求z(t)*/
}
}
void Bezier(wcPt3 *controls, int ncontrols, int m, wcPt3 *curve)
int *c=(int *) malloc(ncontrols *sizeof(int));
int i;
computecoefficients(ncontrols-1,c);
for (i=0; i<=m; i++)
computepoint(i/(float)m,&curve[i],ncontrols,controls,c); free(c);
}
在主程序中提供特征多边形的各个顶点坐标放入controls[]数组中,ncontrols为顶点的个数,m为曲线上取的样点数,比如m=100表示取100个样点。

计算出曲线上的各个样点坐标放入curve[]数组中,这样可以通过相邻点连线绘出生成的Bezier曲线。

程序实现步骤:(工程名:BezierCurve)
(ⅰ)C m n的函数实现,定义成成员函数,命名为Multiply_n。

C mn = =
int Multiply_n(int m,n)
{
int i,j,a;
if (m!=0)
{
a=1;
for (i=m+1;i<=n;i++) //求(m+1)(m+2)…(n-1).n a=a*i;
for (j=1;j<=n-m;j++) //求(n-m)!和C mn
a=a/j;
return a;
}
else
return 1;
}
(ⅱ)伯恩斯坦多项式Bm,n(t)的函数实现Bm,n(t)= C mn tm(1-t)n-m
Double Bernstein(int m,int n,double t) {
int i,j;
double sum;
sum=Multiply_n(m,n); //求C mn
for (i=1;i<=m;i++)
sum=sum*t; // C mn tm
for (j=1;j<=n-m;j++)
sum=sum*(1-t); // C mn tm(1-t)n-m
return sum;
}
(ⅲ) 在OnDraw(CDC* pDC)函数中添加如下代码:
int i,j,k,n=3; //n=3 表示三次Bezier曲线
double curx,cury,t,b;
double dt=0.01;
int array[4][2]={{30,100},{100,30},{50,150},{200,40}}; CPen PenRed(PS_SOLID,1,RGB(255,0,0));//定义红色笔
CPen PenBlue(PS_SOLID,1,RGB(0,0,255));//定义蓝色笔
//首先绘出特征多边形
pDC->SelectObject(&PenBlue);
pDC->MoveTo(array[0][0],array[0][1]);
for (i=0;i<=n;i++)
pDC->LineTo(array[i][0],array[i][1]);
i=0
//绘制Bezier曲线
pDC->MoveTo(array[0][0],array[0][1]); //回到起点pDC->SelectObject(&PenRed);
t=0.0;
for (i=0;i<=(int)1/dt;i++)
{
curx=0; cury=0;
for(j=0;j<=n;j++)
{
b=Bernstein(j,n,t);
curx=curx+array[j][0]*b;
cury=cury+array[j][1]*b;
}
pDC->LineTo(curx,cury);
t=t+dt;
}
编译、运行后查看结果,如图7-1所示。

图7-1 Bezier曲线程序结果
这时Bezier曲线的通用程序设计。

通过这个程序,我们绘出二次、三次甚至高次Bezier曲线。

读者可以通过修改程序来实现,并观察程序的结果。

(2)三次Bezier曲线的绘制
如果仅仅是绘制三次Bezier曲线,可以通过
Q(t)=ΣPi•Bi,3(t) = P0•B0,3(t)+ P1•B1,3(t)+ P2•B2,3(t)+ P3•B3,3(t) ,t∈[0,1]
来简化程序设计。

程序如下:(工程名:Bezier)
将调和函数设计成成员函数:
double CBezierView::b03(double t)
{
return(pow(1-t,3));
}
double CBezierView::b13(double t)
{
return(3*t*pow(1-t,2));
}
double CBezierView::b23(double t) {
return(3*(1-t)*t*t);
}
double CBezierView::b33(double t) {
return(t*t*t);
}
在OnDraw()函数中输入下面代码:
void CBezierView::OnDraw(CDC* pDC) {
CBezierDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
int i;
int x0,y0,x1,y1,x2,y2,x3,y3,curx,cury;
double t,dt;
// 创建两个不同颜色的画笔
CPen PenRed(PS_SOLID,1,RGB(255,0,0));
CPen PenBlue(PS_SOLID,1,RGB(0,0,255));
// 设置控制点,绘出特征多边形
x0=220;y0=10;x1=410;y1=10;x2=225;y2=150;x3=410;y3=100; pDC->SelectObject(PenBlue); //使用蓝色画笔
pDC->MoveTo(x0,y0);
pDC->LineTo(x1,y1);
pDC->LineTo(x2,y2);
pDC->LineTo(x3,y3);
//绘制Bezier曲线
pDC->MoveTo(x0,y0);
t=0; dt=0.01; //t从0到1,每步增加0.01,取100个点pDC->SelectObject(PenRed); //使用红色画笔
for (i=0;i<=100;i++)
{
curx=(int)(b03(t)*x0+b13(t)*x1+b23(t)*x2+b33(t)*x3); cury=(int)(b03(t)*y0+b13(t)*y1+b23(t)*y2+b33(t)*y3); pDC->LineTo(curx,cury);
t=t+dt;
}
}
读者可以使用鼠标实现交互式绘制Bezier曲线。

使用数组ControlsPoints[3]记录鼠标选择的P0,P1,P2,P3 四个控制点,然后根据算法,当t从0到1取100个值,分别求出Bezier曲线上的点的坐标(curx,cury)。

相邻点通过直线段连接构成Bezier曲线。

任务四:三次B样条曲线的算法实现
从三次B样条曲线的定义可知:当n=3时,
Qi,3(t)=ΣPi+l Fl,3(t)= Pi F0,3(t)+ Pi+1 F1,3(t)+ Pi+2 F2,3(t)+ Pi+ 3 F3,3(t)
因为四个调和函数F0,3(t)、F1,3(t)、F2,3(t)和F3,3(t) 已知(参看公式7-5-3)因此只要给出四个控制点的位置矢量的坐标,当t在[0,1]范围内取离散地取100个点时(dt=0.01),分别求出每一个曲线上点,相邻点用直线段连接起来,就可以得到相应的B样条曲线。

设控制点的个数为PointNum,要求PointNum≥4,则可以生成(PointNum-3)段三次B样条曲线。

其中第i段三次B样条曲线的代数形式为:
Qi,3(t)x= Pi x F0,3(t)+ P (i+1) x F1,3(t)+ P (i+2) x F2,3(t)+ P (i+3) x F3,3(t)
Qi,3(t)y= Pi y F0,3(t)+ P (i+1) y F1,3(t)+ P (i+2) y F2,3(t)+ P (i+3) y F3,3(t)
其中,i=1,2,…, PointNum-3
程序算法如下:(工程名:BSpring)
(1)将调和函数定义为成员函数,函数形式如下:
double CBSpringView::f03(double t)
{
return ((-pow(t,3)+3*pow(t,2)-3*t+1)/6);
}
double CBSpringView::f13(double t)
{
return ((3*pow(t,3)-6*pow(t,2)+4)/6);
}
double CBSpringView::f23(double t)
{
return ((-3*pow(t,3)+3*pow(t,2)+3*t+1)/6); }
double CBSpringView::f33(double t)
{
return (pow(t,3)/6);
}
(2)编写OnDraw()函数,程序如下:
int n,m,pointnum,i,j;
int x[10],y[10],curx,cury; //(x[i],y[i])为顶点坐标double t,dt;
n=3; pointnum=5; //5个顶点,则绘制(5-3)=2段B样条曲线x[1]=10;y[1]=200;x[2]=40;y[2]=100;x[3]=100;y[3]=100;
x[4]=150;y[4]=150;x[5]=150;y[5]=200;
//绘出特征多边形
pDC->MoveTo(x[1],y[1]);
for (i=2;i<=pointnum;i++)
pDC->LineTo(x[i],y[i]);
//绘制B样条曲线
m=pointnum-n; dt=0.01;
for (i=1;i<=m;i++) //绘制m条B样条曲线
t=0;
for (j=0;j<=100;j++) // 绘制每一条B样条曲线
{
curx=f03(t)*x[i]+f13(t)*x[i+1]+f23(t)*x[i+2]+f33(t)*x[i+3]; cury=f03(t)*y[i]+f13(t)*y[i+1]+f23(t)*y[i+2]+f33(t)*y[i+3]; if (j==0)
pDC->MoveTo(curx,cury);
else
{
pDC->LineTo(curx,cury);
t+=dt;
}
}
(3)编译程序,查看运行结果。

一、实验目的
编写区域填充算法程序,验证算法的正确性。

验证线型与线宽处理技术。

二、实验任务
1.多边形有序边表算法程序设计;
2.边填充算法和边标志填充算法;
3.简单的种子填充算法和扫描线填充算法;
4.区域填充图案程序设计;
三、实验步骤
下面以实现扫描线填充算法程序为例,介绍实验编程步骤。

步骤1:建立工程文件:Sampleseedfill;
步骤2:建立成员变量和成员函数
protected:
int stack[10000]; //定义栈;
int stack_top; //栈顶位置
public:
int stackpop(); //出栈;
void stackpush(int p_xy); //入栈
int isstackempty(); //判断栈是否为空
void setstackempty(); //清空栈
void floodfill4(int x,int y, COLORREF oldcolor,COLORREF newcolor); //填充函数
步骤3:在构造函数中,对变量和栈初始化;
CSampleseedfillView::CSampleseedfillView()
{
// TODO: add construction code here
stack_top=0;
}
步骤4:编写成员函数程序
void CSampleseedfillView::setstackempty()
{
int i;
for(i=0;i<=stack_top;i++)
stack[i]=0;
stack_top=0;
}
int CSampleseedfillView::isstackempty()
{
if (stack_top>0)
return 1;
else
return 0;
}
void CSampleseedfillView::stackpush(int p_xy) {
stack_top+=1;
stack[stack_top]=p_xy;
}
int CSampleseedfillView::stackpop()
{
int val;
val=stack[stack_top];
stack_top=stack_top-1;
return val;
}
步骤5:编写扫描线填充算法
void CSampleseedfillView::floodfill4(int x, int y, COLORREF oldcolor, COLORREF newcolor)
{
CDC * pDC=GetDC();
int xl,xr,x0,xnextspan;
bool spanNeedFill;
//将栈清空
setstackempty();
//种子入栈
stackpush(x);
stackpush(y);
while(isstackempty()!=0)
{
//栈顶出栈,注意出栈顺序
y= stackpop();
x= stackpop();
pDC->SetPixel(x,y,newcolor);
x0=x+1;
while(pDC->GetPixel(x0,y)==oldcolor) //向右填充{
pDC->SetPixel(x0,y,newcolor);
x0++;
}
xr = x0-1; //最右元素
x0 = x-1;
while(pDC->GetPixel(x0,y)==oldcolor) //向左填充{
pDC->SetPixel(x0,y,newcolor);
x0--;
}
xl = x0+1; //最左元素
//处理上面一条扫描线
x0 = xl;
y = y+1;
while (x0<=xr)
{
spanNeedFill=FALSE;
//while((pDC->GetPixel(x0,y)!=RGB(0,0,255))&&(pDC->GetPixel(x 0,y)!=newcolor)&&(x0<xr))
while (pDC->GetPixel(x0,y)==oldcolor)
{ if (spanNeedFill==FALSE) spanNeedFill=TRUE;
x0++;
}
if(spanNeedFill)
{
//if
((x0==xr)&&(pDC->GetPixel(x0,y)!=RGB(0,0,255))&&(pDC->GetPixe l(x0,y)!=newcolor))
if (x0==xr)
{ stackpush(x0);
stackpush(y);}
else
{stackpush(x0-1);
stackpush(y);}
spanNeedFill=FALSE;
} //end if
xnextspan=x0;
while(pDC->GetPixel(x,y)!=oldcolor && x0<xr) x0++;
if (xnextspan==x0) x0++;
}//End of while(x0<=xr)
}//End of while(!isstackempty())
}
步骤6:编写OnDraw()函数
绘制多边形,设置种子位置和填充颜色。

void CSampleseedfillView::OnDraw(CDC* pDC)
{
CSampleseedfillDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
//定义画笔颜色
CPen PenRed(PS_SOLID,1,RGB(255,0,0));//定义红色笔
CPen PenBlue(PS_SOLID,1,RGB(0,0,255));//定义蓝色笔
int x,y;
//用蓝色笔画出多变形的边界
pDC->SelectObject(&PenBlue);
POINT
polygon[5]={{300,120},{390,160},{430,320},{180,300},{150,240} };
pDC->Polygon(polygon,5);
//定义种子位置,背景色oldcolor和填充色newcolor
x=300;y=200;
COLORREF newcolor=RGB(255,0,0);
COLORREF oldcolor=RGB(255,255,255);
//调用扫描线填充算法程序
floodfill4(x,y, oldcolor,newcolor);
}
步骤7:编译、调试,运行程序。

一、实验目的
编写圆和椭圆的扫描转换算法程序,验证算法的正确性。

二、实验任务
1.编写中点画圆法的扫描转换程序,考虑原点在(x0,y0)处程序的改动;
2.添加鼠标程序,实现交互式画圆;
3.编写中点画椭圆法的扫描转换程序;
4.添加鼠标程序,实现交互式画椭圆;
三、实验内容
任务一:中点画圆法的扫描转换算法
程序实现步骤:
(1)建立MidPointCircle工程文件;
(2)右击CMidPointCircleView类,建立成员函数
void MidpointCircle(CDC *pDC,int x0, int y0, int r, COLORREF color)
int CirPot(CDC *pDC,int x0, int y0, int x, int y, COLORREF color) (3) 编写成员函数代码,程序如下:
void CMidPointCircleView::MidpointCircle(CDC *pDC,int x0, int y0, int r, COLORREF color)
{
int x,y;
float d;
x=0;y=r;d=1.25-r;
CirPot(pDC,x0,y0,x,y,color); while (x<=y)
{
if(d<0)
{
d+=2*x+3; x++;
}
else
{
d+=2*(x-y)+5;
x++; y--;
}
CirPot(pDC,x0,y0,x,y,color);
} /* while*/
}
int CMidPointCircleView::CirPot(CDC *pDC,int x0, int y0, int x, int y, COLORREF color)
{
pDC->SetPixel((x0+x),(y0+y),color);
pDC->SetPixel((x0+y),(y0+x),color);
pDC->SetPixel((x0+y),(y0-x),color);
pDC->SetPixel((x0+x),(y0-y),color);
pDC->SetPixel((x0-x),(y0-y),color);
pDC->SetPixel((x0-y),(y0-x),color);
pDC->SetPixel((x0-y),(y0+x),color);
pDC->SetPixel((x0-x),(y0+y),color);
return 0;
}
(4)编写OnDraw(CDC* pDC)函数,程序如下:
void CMidPointCircleView::OnDraw(CDC* pDC)
{
CMidPointCircleDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc);
// TODO: add draw code for native data here MidpointCircle(pDC,100, 100, 10, RGB(255,0,0)); MidpointCircle(pDC,500, 300, 60, RGB(255,255,0)); }
(6)编译、运行程序,查看结果。

任务二:添加鼠标程序,实现交互式画圆
在任务1的基础上,完成下列步骤:
(1)向视图类中添加自定义的成员变量
用鼠标右键单击视图类,选择“Add Member Variable…”,添加下面三个成员变量。

proctected :
int m_r; // 半径
CPoint m_bO; // 圆心
CPoint m_bR; //圆上的点
int m_ist; //圆心与圆周上点的区别,m_ist=0,表示鼠标左击点为圆心,
//m_ist=1,表示鼠标左击点为圆周上的点
(2)在视图类CPP文件的构造函数中初始化成员变量
CMidPointCircleMouseView::CMidPointCircleMouseView()
{
// TODO: add construction code here
m_bO.x=0; m_bO.y=0; //圆心
m_bR.x=0; m_bR.y=0; //圆上的点
m_ist=0; //圆心与圆上的点区别
m_r=0; //圆的半径
}
(3)向视图类中添加自定义的成员函数原型:
public:
int ComputeRadius(CPoint cenp,CPoint ardp);
添加成员函数的程序代码:
int CMouseSpringView::ComputeRadius(CPoint cenp, CPoint ardp)
{
int dx=cenp.x-ardp.x;
int dy=cenp.y-ardp.y;
//sqrt()函数的调用,在头文件中加入#include "math.h"
return (int)sqrt(dx*dx+dy*dy);
}
(4)向视图类中添加两个鼠标消息响应函数,并输入鼠标处理程序代码。

具体操作方法与鼠标示例1方法相同。

一个是OnLButtonDown()函数,另一个是OnMouseMove()函数。

程序如下:
void CMidPointCircleMouseView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CDC *pDC=GetDC();
pDC->SelectStockObject(NULL_BRUSH);
if (!m_ist) //绘制圆
{
m_bO=m_bR=point; //纪录第一次单击鼠标位置,定圆心
m_ist++;
}
else
{
m_bR=point; //记录第二次单击鼠标的位置,定圆周上的点m_ist--; // 为新绘图作准备
m_r=ComputeRadius(m_bO,m_bR);
MidpointCircle(pDC,m_bO.x,m_bO.y,m_r,RGB(255,0,0));
}
ReleaseDC(pDC); //释放设备环境
CView::OnLButtonDown(nFlags, point);
}
void CMidPointCircleMouseView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default CDC *pDC=GetDC();
int nDrawmode=pDC->SetROP2(R2_NOT); //设置异或绘图模式,并保存原来绘图模式
pDC->SelectStockObject(NULL_BRUSH);
if(m_ist==1)
{
CPoint prePnt,curPnt;
prePnt=m_bR; //获得鼠标所在的前一位置
curPnt=point;
//绘制橡皮筋线
m_r=ComputeRadius(m_bO,prePnt);
MidpointCircle(pDC,m_bO.x,m_bO.y,m_r,RGB(255,0,0));//用异或模式重复画圆,擦出所画的圆
// DrawCircle(pDC,m_bO,prePnt);
m_r=ComputeRadius(m_bO,curPnt);
MidpointCircle(pDC,m_bO.x,m_bO.y,m_r,RGB(255,0,0)); //用当前位置作为圆周上的点画圆
m_bR=point;
}
pDC->SetROP2(nDrawmode); //恢复原绘图模式
ReleaseDC(pDC); //释放设备环境
CView::OnMouseMove(nFlags, point);
}
任务三:编写中点画椭圆法的扫描转换程序
程序实现步骤:
(1) 建立MidPointEllise工程文件;
(2)右击CMidPointElliseView类,建立成员函数
void MidpointEllise(CDC *pDC, int x0, int y0, int a, int b, COLORREF color)
(3) 编写成员函数代码,程序如下:
void CMidPointEllipseView::MidpointEllise(CDC *pDC, int x0, int y0, int a, int b, COLORREF color)
{
int x,y;
float d1,d2;
x=0;y=b;
d1=b*b+a*a*(-b+0.25);
pDC->SetPixel(x+x0,y+y0,color); while (b*b*(x+1)<a*a*(y-0.5)) {
if (d1<0)
{
d1+=b*b*(2*x+3);
x++;
}
else
d1+=(b*b*(2*x+3)+a*a*(-2*y+2));
x++; y--;
}
pDC->SetPixel(x0+x,y0+y,color);
pDC->SetPixel(x0+x,y0-y,color);
pDC->SetPixel(x0-x,y0+y,color);
pDC->SetPixel(x0-x,y0-y,color);
} // 上半部分
d2=(b*(x+0.5))*(b*(x+0.5))+(a*(y-1))*(a*(y-1))-(a*b)*(a*b); while (y>0)
{
if (d2<0)
d2+=b*b*(2*x+2)+a*a*(-2*y+3); x++; y--;
}
else
{
d2+=a*a*(-2*y+3);
y--;
}
pDC->SetPixel(x0+x,y0+y,color); pDC->SetPixel(x0+x,y0-y,color); pDC->SetPixel(x0-x,y0+y,color); pDC->SetPixel(x0-x,y0-y,color);
} //下半部分
}
(4) 编写OnDraw()函数
void CMidPointEllipseView::OnDraw(CDC* pDC)
{
CMidPointEllipseDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here MidpointEllise(pDC, 300, 200, 50, 20, RGB(255,0,0)); }
(5)编译、运行程序。

任务四:添加鼠标程序,实现交互式画椭圆
程序实现步骤:
(1)~(3)同上,建立MidPointElliseMouse工程文件。

(4)添加成员变量
protected:
int b;
int a;
int m_ist;
CPoint CenterPoint;
CPoint RightBottom;
CPoint LeftTop;
(5)在构造函数中赋初值
CMidPointElliseMouseView::CMidPointElliseMouseView()
{
// TODO: add construction code here
LeftTop.x=0;LeftTop.y=0; // 左上角坐标初值
RightBottom.x=0;RightBottom.y=0; // 右下角坐标初值CenterPoint.x=0;CenterPoint.y=0; // 中心点坐标初值
a=0; b=0; //长轴和短轴长度
m_ist=0; //0:表示第一点,1:表示第二点
}
(6) 添加OnLButtonDown()函数
void CMidPointElliseMouseView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default CDC *pDC=GetDC();
pDC->SelectStockObject(NULL_BRUSH);
if (!m_ist) //第一点,左上角
{
LeftTop=RightBottom=point; //纪录第一次单击鼠标位置
m_ist++;
}
else
{
RightBottom=point; //记录第二次单击鼠标的位置
m_ist--; // 为新绘图作准备
CenterPoint.x=(LeftTop.x+RightBottom.x)/2;
CenterPoint.y=(LeftTop.y+RightBottom.y)/2;
a=(int)abs((RightBottom.x-LeftTop.x))/2;
b=(int)abs((RightBottom.y-LeftTop.y))/2;
MidpointEllise(pDC,CenterPoint.x,CenterPoint.y,a,b,RGB(255,0, 0));
}
ReleaseDC(pDC); //释放设备环境
CView::OnLButtonDown(nFlags, point);
}
(7)添加OnMouseMove()函数
void CMidPointElliseMouseView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CDC *pDC=GetDC();
int nDrawmode=pDC->SetROP2(R2_NOT); //设置异或绘图模式,并保存原来绘图模式
pDC->SelectStockObject(NULL_BRUSH);
if(m_ist==1)
{
CPoint prePnt,curPnt;
prePnt=RightBottom; //获得鼠标所在的前一位置
curPnt=point;
//绘制橡皮筋线
CenterPoint.x=(LeftTop.x+prePnt.x)/2;
CenterPoint.y=(LeftTop.y+prePnt.y)/2;
a=(int)abs((prePnt.x-LeftTop.x))/2;
b=(int)abs((prePnt.y-LeftTop.y))/2;
MidpointEllise(pDC,CenterPoint.x,CenterPoint.y,a,b,RGB(255,0, 0));
//用异或模式重复画圆,擦出所画的圆
//用当前点作为右下角点,画椭圆
CenterPoint.x=(LeftTop.x+curPnt.x)/2;
CenterPoint.y=(LeftTop.y+curPnt.y)/2;
a=(int)abs((curPnt.x-LeftTop.x))/2;
b=(int)abs((curPnt.y-LeftTop.y))/2;
MidpointEllise(pDC,CenterPoint.x,CenterPoint.y,a,b,RGB(255,0, 0));
//用当前位置作为圆周上的点画圆
RightBottom=point;
}。

相关文档
最新文档