logo资料库

二维绘图系统.doc

第1页 / 共19页
第2页 / 共19页
第3页 / 共19页
第4页 / 共19页
第5页 / 共19页
第6页 / 共19页
第7页 / 共19页
第8页 / 共19页
资料共19页,剩余部分请下载后查看
一.实验目的 1.设计和开发一个小型的二维绘图系统 2.通过对计算机图形学中 DDA、中点、Bresenham 算法、椭圆以及 Bezier 曲线等 生成算法的理解,完成直线、椭圆、圆的实现; 3.通过图形软件的设计开发和上机实验,巩固所学图形学基本知识 4.掌握交互式图形系统的设计方法 5.熟悉并掌握有关图形图象编程语言、工具和类库的使用。 二.实验环境 Windows 7 Microsoft Visual C++ 6.0 以及 MFC 三.实验内容 1.绘制直线 (1)DDA 算法的原理 DDA 算法是根据直线的微分方程来计算Δx或Δy生成直线的扫描转换算法。 在一个坐标轴上以单位间隔对线段取样, 以决定另一个坐标轴方向上最靠近理 想线段的整数值。 设(x0, y0)为直线段的始点, (x1, y1)为直线段的终点, 且端点坐标均为整 数, 则直线的微分方程为 y 1 x 1   设|k|≤1, 则有 0  y x 0 y  x   k yi+1=kxi+1+b=k(xi+Δx)+b=yi+kΔx 上式表明, 若Δx=1, 则当 x每递增 1 时, y递增 k。 扫描转换开始时, 取直
线始点(x0, y0)作为初始坐标。 (2)中点法 算法的原理: 为了讨论的方便, 假定直线的斜率在 0~1 之间, 其它情况参照下述讨论进 行处理。 假设直线的起点和终点分别为(x0, y0)和(x1, y1), 则直线方程为 F(x, y)=ax+by+c=0 其中, a=y0-y1, b=x1-x0, c=x0y1-x1y0。对于直线上的点, F(x,y)=0; 对于直线上 方的 点, F(x,y)>0; 而对于直线下方的点, F(x,y)<0。 如图 3.1 所示, 若直线在 x 方向 上增加一个单位, 则在 y 方向上的增量只能在 0 和 1 之间。 假设横坐标为 xP 的 各像素点中最佳逼近于理想直线的像素为(xP,yP), 用实心小圆表示。 那么, 下一 个与直线最近的像素只能是正右方的 P1(xP+1,yP)或右上方的 P2(xP+1, yP+1)两者 之一, 用空心小圆表示。 我们用 P1 和 P2 的中点 M(xP+1, yP+0.5)与理想直线的位 置关系来判定。 中点画线示意图 (3)Bresenham 算法 算法的原理: Bresenham 画线算法与中点画线法有相似之处, 也是通过在每列像素中确定 与理想直线最近的像素来进行直线的扫描转换的。 为了讨论的方便,不妨也假定 直线的斜率在 0~1 之间。 如图所示, 过各行、 各列像素中心构造一组虚拟网 格线, 按直线从起点到终点的顺序计算直线与各垂直网格线的交点, 然后确定该 列像素中与该交点最近的像素。
2.圆 算法的原理: 为了讨论的方便, 我们考虑中心在原点, 半径为 R 的圆的第二个八分圆弧, 圆的其它部分可通过一系列的简单的反射变换得到。 也就是讨论如何从(0, R)到 (R / )顺时针确定最佳逼近于该圆弧的像素序列。 ,R/ 2 2 中心在原点, 半径为 R 的圆的方程为 x2+y2=R2 若令 F(x,y)=x2+y2-R2, 则上述方程为 F(x, y)=0 如图所示, 假定 x 坐标为 xP 的像素中最佳逼近理想圆弧的为 P(xP, yP), 那么, 下一个像素只能是正右方的 P1(xP+1, yP)或右下方的 P2(xP+1, yP-1)两者之一。 引 入 P1 和 P2 的中点 M(xP+1, yP-0.5), 当 M 在圆内时, 应取 P1(xP+1, yP)为下一个像 素, 否则, 应取 P2(xP+1, yP-1)为下一个像素。 为此, 构造判别式 d=F(M)=F(xP+1, yP-0.5)=(xP+1)2+(yP-0.5)2-R2 中点画圆法
若 d<0, 则应取 P1(xP+1, yP)为下一个像素, 而且再下一个像素的判别 式为 d′=F(xP+2, yP-0.5)=(xP+2)2+(yP-0.5)2-R2 =d+2xP+3 而 d≥0, 则应取 P2(xP+1, yP-1)为下一个像素, 而且再下一个像素 判别式为 d′=F(xP+2, yP-1.5)=(xP+2)2+(yP-1.5)2-R2 由于第一个像素是(0,R), 因而 d 的初始值为 d0=F(1, R-0.5)=1.25-R =d+2(xP-yP)+5 3.椭圆 算法的原理: 中点画圆法可以推广到一般二次曲线的生成, 下面以中心在原点的标准椭 圆的扫描转换为例说明。 设椭 圆的方程为 F(x,y)=b2x2+a2y2-a2b2=0 其中, a 为沿 x 轴方向的长半轴长度, b 为 y 轴方向的短半轴长度, a、b 均为整数。 不失一般性, 我们只讨论第一象限椭圆弧的生成。需要注意的是, 在处理这段椭 圆时, 必须以弧上斜率为-1 的点(即法向量两个分量相等的点)作为分界把它分为 上部分和下部分, 如图所示。 第一象限的椭圆弧 该椭圆上一点(x, y)处的法向量为 ,( yxN )  F  x  i  F  y  j  2 2 xib  2 2 yia
其中, i 和 j 分别为沿 x 轴和 y 轴方向的单位向量。 从图 3.6 可看出, 在上 分, 法向量的 y 分量更大, 而在下部分, 法向量的 x 分量更大, 因而, 在上部 若当前最佳逼近理想椭圆弧的像素(xP,yP)满足下列不等式 b2(xP+1)<a2(yP-0.5) 而确定的下一个像素不满足上述不等式, 则表明椭圆弧从上部分转入下部分。 在上部分, 假设横坐标为 xP 的像素中与椭圆弧更接近点是(xP, yP), 那么下一对候 选像素的中点是(xP+1, yP-0.5)。 因此判别式为 d1=F(xP+1, yP-0.5)=b2(xP+1)2+a2(yP-0.5)2-a2b2 若 d1<0, 中点在椭圆内, 则应取正右方像素, 且判别式应更新为 d′1=F(xP+2, yP-0.5)=b2(xP+2)2+a2(yP-0.5)2-a2b2 =d1+b2(2xP+3) 当 d1≥0, 中点在椭圆之外, 这时应取右下方像素, 并且更新判别式为 d′1=F(xP+2, yP-1.5)=b2(xP+2)2+a2(yP-1.5)2-a2b2 =d1+b2(2xP+3)+a2(-2yP+2) 由于弧起点为(0, b), 因此, 第一中点是(1, b-0.5), 对应的判别式是 d10=F(1, b-0.5)=b2+a2(b-0.5)2-a2b2 =b2+a2(-b+0.25) 在下部分, 应改为从正下方和右下方两个像素中选择下一像素。 如果在上部分 所选择的最后一像素是(xP, yP), 则下部分的中点判别式 d2 的初始值为 d20=F(xP+0.5, yP-1)=b2(xP+0.5)2+a2(yP-1)2-a2b2 d2 在正下方向与右下方向的增量计算与上部分类似, 这里不 重复论述。下部分弧的终止条件是 y=0。 直线,矩形,椭圆,Bezier 曲线,橡皮筋线以及颜色源程序代码如下: // ZUOYEView.cpp : implementation of the CZUOYEView class // #include "stdafx.h" #include "ZUOYE.h"
#include "ZUOYEDoc.h" #include "ZUOYEView.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CZUOYEView IMPLEMENT_DYNCREATE(CZUOYEView, CView) BEGIN_MESSAGE_MAP(CZUOYEView, CView) //{{AFX_MSG_MAP(CZUOYEView) ON_WM_LBUTTONDOWN() ON_WM_LBUTTONUP() ON_COMMAND(IDR_Line, OnLine) ON_UPDATE_COMMAND_UI(IDR_Line, OnUpdateLine) ON_COMMAND(IDR_Rectangle, OnRectangle) ON_UPDATE_COMMAND_UI(IDR_Rectangle, OnUpdateRectangle) ON_COMMAND(IDR_Red, OnRed) ON_UPDATE_COMMAND_UI(IDR_Red, OnUpdateRed) ON_COMMAND(IDR_Adjust, OnAdjust) ON_UPDATE_COMMAND_UI(IDR_Adjust, OnUpdateAdjust) ON_COMMAND(IDR_Circle, OnCircle) ON_UPDATE_COMMAND_UI(IDR_Circle, OnUpdateCircle) ON_COMMAND(IDR_BLSELINE, OnBlseline) ON_UPDATE_COMMAND_UI(IDR_BLSELINE, OnUpdateBlseline)
ON_WM_MOUSEMOVE() ON_COMMAND(IDR_ONLine, OnONLine) ON_UPDATE_COMMAND_UI(IDR_ONLine, OnUpdateONLine) ON_COMMAND(IDR_Clean, OnClean) ON_UPDATE_COMMAND_UI(IDR_Clean, OnUpdateClean) //}}AFX_MSG_MAP // Standard printing commands ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CZUOYEView construction/destruction CZUOYEView::CZUOYEView() { // TODO: add construction code here JW=0; m_fstart=m_fend=0; m_fbLine=m_fbRect=m_fbe=Selecting=m_fbflag=m_fbflag1=m_fbflag2=m_fbfl ag3=0; m_fgreen=m_fwhite=m_fred=m_fblue=m_fblack=0; m_fblseLine=0; m_fbclean=0; m_bONLine=0; M_f=m_fb=0; Flag=0;
} CZUOYEView::~CZUOYEView() { } BOOL CZUOYEView::PreCreateWindow(CREATESTRUCT& cs) { // TODO: Modify the Window class or styles here by modifying // the CREATESTRUCT cs return CView::PreCreateWindow(cs); } ///////////////////////////////////////////////////////////////////////////// // CZUOYEView drawing void CZUOYEView::OnDraw(CDC* pDC) { CZUOYEDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // TODO: add draw code for native data here } ///////////////////////////////////////////////////////////////////////////// // CZUOYEView printing BOOL CZUOYEView::OnPreparePrinting(CPrintInfo* pInfo) {
分享到:
收藏