计算机图形学 Visual C++ MFC 图形开发初步

计算机图形学 Visual C++ MFC 图形开发初步

目录

1 实验目的和要求

2 基本原理

3 主要仪器与设备

4 实验步骤/数据处理与结果

        4.1 创建MFC项目

        4.2 绘制点

        4.3 绘制线

        4.4 绘制面

        4.5 绘制简易叶片图形

5 体会与总结

参考文献


1 实验目的和要求

        搭建能够显示图形、文字的单文档绘图环境。

        (1)在OnDraw函数内,使用MFC封装函数(MoveTo,LineTo,Rectangle,Ellipse等)和点、线、矩形、椭圆/圆等基本图形,表示出指定实验区域的行政中心(或实验样点、河流(或类型边界)和行政区(或实验区)等图形。

        (2)使用阔叶树种的叶片采集数据,表示出叶片的投影图形,为三维建模奠定基础。

提示:可通过平移坐标点,使数据显示在客户区的中央。

2 基本原理

        (1)MFC(Microsoft Foundation Classes)库是Microsoft为利用VC++开发Windows应用程序而提供的应用程序框架。在这个框架的支持下,对于不同的应用程序,编程的主要任务是填写各自特殊部分的代码。MFC类库由130多个类组成,封装了两千多个API函数。

        (2)MFC程序的设计流程[1],如图1:

图1 程序的开发流程

3 主要仪器与设备

        Visual C++ 6.0

4 实验步骤/数据处理与结果

        4.1 创建MFC项目

        (1)启动Visual C++6.0。

        (2)从File菜单中选择New选项,出现New对话框。选中Projects分页,在Projects面板中左侧的项目类型列表框中单击选中MFC AppWizard[exe]项,创建一个MFC应用程序。

        (3)单击OK按钮。出现MFC AppWizard-Step 1对话框。创建基于Single document(单文档)。

        (4)其他设置默认,完成创建。如图2:

图2 创建MFC项目

        (5)编译执行,查看效果。如图3:

图3 初始应用程序运行结果

        4.2 绘制点

        (1)增加成员函数DrawPoint。如图4,用鼠标右键单击类面板中的CExp_01View类节点,在弹出的快捷菜单中选择“Add Member Function…”,在出现的对话框中输入如图所示内容。

图4 增加成员函数DrawPoint

        (2)编辑DrawPoint函数。代码如下:

void CExp_01View::DrawPoints(CDC *pDC) { //绘制邻近的点集,以突出显示 pDC->SetPixel(100,100,RGB(255,0,0)); pDC->SetPixel(101,100,RGB(255,0,0)); pDC->SetPixel(100,101,RGB(255,0,0)); pDC->SetPixel(101,101,RGB(255,0,0)); pDC->SetPixel(99,100,RGB(255,0,0)); pDC->SetPixel(100,99,RGB(255,0,0)); pDC->SetPixel(99,99,RGB(255,0,0)); }

        (3)在OnDraw函数中调用DrawPoints函数。代码如下:

void CExp_01View::OnDraw(CDC* pDC) { CExp_01Doc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // TODO: add draw code for native data here DrawPoints(pDC); //调用DrawPoints函数 }

        (4)修改DrawPoints函数,绘制行政中心。代码如下:

void CExp_01View::DrawPoints(CDC *pDC) { /* //方法尝试,查看效果 //Method_1:绘制邻近的点集,以突出显示 pDC->SetPixel(100,100,RGB(255,0,0)); pDC->SetPixel(101,100,RGB(255,0,0)); pDC->SetPixel(100,101,RGB(255,0,0)); pDC->SetPixel(101,101,RGB(255,0,0)); pDC->SetPixel(99,100,RGB(255,0,0)); pDC->SetPixel(100,99,RGB(255,0,0)); pDC->SetPixel(99,99,RGB(255,0,0)); //Method_2:使用for循环成实心方块,以突出显示 for(int i=0; i<10; ++i) { for (int j=0; j<10; ++j) { pDC->SetPixel(200+j, 150+i, RGB(255,0,0)); } } */ //绘制行政中心 for(int i=0; i<10; ++i) { for (int j=0; j<10; ++j) { //绘制4个实心方块,作行政中心 pDC->SetPixel(200+j, 150+i, RGB(255,0,0)); pDC->SetPixel(600+j, 150+i, RGB(0,255,0)); pDC->SetPixel(350+j, 300+i, RGB(0,0,255)); pDC->SetPixel(800+j, 400+i, RGB(200,100,100)); } } }

        (5)调试运行,结果如下图5所示:

图5 绘制行政中心

        4.3 绘制线

        (1)增加成员函数DrawLines。

        (2)编辑DrawLines函数。使用LineTo函数和MoveTo函数绘制实线的主干道,使用SetPixel函数for循环绘制虚线的支路,使用Ployline函数绘制折线的边界,使用PolyBezierTo函数与创建画笔绘制蓝色河流。代码如下:

void CExp_01View::DrawLines(CDC *pDC) { //实线主干道绘制:LineTo函数和MoveTo函数 pDC->MoveTo(50,250); POINT p1;p1.x=700;p1.y=250; //使用POINT结构 pDC->LineTo(p1); CPoint p2;p2.x=1200;p2.y=20; //使用CPoint类 pDC->LineTo(p2); pDC->MoveTo(50,270); pDC->LineTo(720,270); pDC->LineTo(1240,20); pDC->TextOut(600,260,_T("主干道")); //注记 //虚线支路绘制:SetPixel函数for循环 for(int i=0;i<300;i=i+5) { pDC->SetPixel(500,270+i,RGB(255,0,0)); pDC->SetPixel(520,270+i,RGB(255,0,0)); pDC->TextOut(530,400,_T("支路")); //注记 } //折线边界绘制:Ployline函数 POINT p[10]; p[0].x=1100;p[0].y=400; p[1].x=1100;p[1].y=500; p[2].x=1200;p[2].y=500; p[3].x=1200;p[3].y=600; p[4].x=10;p[4].y=600; p[5].x=10;p[5].y=10; p[6].x=1250;p[6].y=10; p[7].x=1250;p[7].y=200; p[8].x=1100;p[8].y=200; p[9].x=1100;p[9].y=300; pDC->Polyline(p,10); pDC->TextOut(1100,350,_T("大门")); //注记 //曲线河流绘制:PolyBezierTo函数与创建画笔 HPEN hPen = CreatePen(PS_SOLID, 3, RGB(0,0,255)); //创建蓝色画笔 HPEN hOldPen = (HPEN)pDC->SelectObject(hPen); //把画笔选进DC POINT n[6]; pDC->MoveTo(200,100); n[0].x=200;n[0].y=200; n[1].x=300;n[1].y=200; n[2].x=400;n[2].y=300; n[3].x=500;n[3].y=400; n[4].x=300;n[4].y=400; n[5].x=100;n[5].y=450; pDC->PolyBezierTo(n,6); //六个点,两段连续 pDC->SelectObject(hOldPen); //还原旧笔 DeleteObject(hPen); //删除创建的画笔 pDC->TextOut(220,110,_T("河流")); //注记 }

        (3)在OnDraw函数中调用DrawLines函数。代码如下:

void CExp_01View::OnDraw(CDC* pDC) { CExp_01Doc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // TODO: add draw code for native data here DrawPoints(pDC); //调用DrawPoints函数 DrawLines(pDC); //调用DrawLines函数 }

        (4)调试运行,结果如下图7所示:

图6 绘制道路与边界

        4.4 绘制面

        (1)增加成员函数DrawPloygons。

        (2)编辑DrawPloygons函数。使用Rectangle函数绘制行政中心范围,使用RoundRect函数绘制操场,使用RoundRect函数绘制操场,使用Ellipse函数与创建画笔笔刷绘制湖泊。代码如下:

void CExp_01View::DrawPloygons(CDC *pDC) { // 1.绘制行政中心范围:Rectangle函数 //Method_1:使用对角坐标 pDC->Rectangle(70,120,140,190); pDC->TextOut(70,200,_T("第一实验楼")); pDC->Rectangle(570,110,640,200); pDC->TextOut(570,210,_T("第一教学楼")); //Method_2:使用CRect类 CRect r,h; r.left=330;r.top=280; r.right=380;r.bottom=330; h.left=760;h.top=360; h.right=850;h.bottom=450; pDC->Rectangle(r); pDC->TextOut(320,340,_T("第二教学楼")); pDC->Rectangle(h); pDC->TextOut(770,460,_T("第二实验楼")); // 2.绘制操场:RoundRect函数 pDC->RoundRect(230,450,450,580,30,30); pDC->RoundRect(240,460,440,570,30,30); pDC->TextOut(330,510,_T("操场")); // 3.绘制湖泊:Ellipse函数与创建画笔笔刷 HPEN hPen = CreatePen(PS_SOLID, 3, RGB(0,0,200)); //创建蓝色画笔 HPEN hOldPen = (HPEN)pDC->SelectObject(hPen); //把画笔选进DC HBRUSH hBrush = CreateSolidBrush(RGB(50,50,200)); //创建填充笔刷 HBRUSH hOldBrush = (HBRUSH)pDC->SelectObject(hBrush); //把笔刷选进DC CRect l; l.left=130;l.top=30; l.right=250;l.bottom=100; pDC->Ellipse(l); pDC->SelectObject(hOldPen); //还原旧笔 DeleteObject(hPen); //删除创建的画笔 pDC->SelectObject(hOldBrush); //还原原刷 DeleteObject(hBrush); //删除创建的笔刷 pDC->TextOut(260,60,_T("湖泊")); //注记 }

        (3)在OnDraw函数中调用DrawPloygons函数。代码如下:

void CExp_01View::OnDraw(CDC* pDC) { CExp_01Doc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // TODO: add draw code for native data here DrawPloygons(pDC); //调用DrawPloygons函数 DrawPoints(pDC); //调用DrawPoints函数 DrawLines(pDC); //调用DrawLines函数 }

        (4)调试运行,结果如下图9所示:

图7 绘制面要素

        4.5 绘制简易叶片图形

        (1)增加成员函数DrawLeaf。

        (2)编辑LoadData函数。使用画笔画刷绘制树叶颜色,Polygon函数描摹俯视树叶投影的轮廓,并通过MoveTo、LineTo绘制折线树叶叶脉凸显三维效果。同时,使用GetClientRect获取视图中心,保证调整窗口大小而叶片能始终显示在客户区的中央。代码如下:

void CExp_01View::DrawLeaf(CDC *pDC, const CPoint &center) { CPen leafPen(PS_SOLID, 2, RGB(34, 139, 34)); // 树叶轮廓颜色 CPen veinPen(PS_SOLID, 1, RGB(0, 100, 0)); // 叶脉颜色 CBrush leafBrush(RGB(124, 252, 0)); // 树叶填充颜色 CPen* pOldPen = pDC->SelectObject(&leafPen); CBrush* pOldBrush = pDC->SelectObject(&leafBrush); // 树叶轮廓点 CPoint pts[7]; pts[0] = CPoint(center.x, center.y - 40); // 叶尖 pts[1] = CPoint(center.x - 20, center.y - 20); pts[2] = CPoint(center.x - 30, center.y); pts[3] = CPoint(center.x, center.y + 30); // 叶底 pts[4] = CPoint(center.x + 30, center.y); pts[5] = CPoint(center.x + 20, center.y - 20); pts[6] = pts[0]; // 闭合 pDC->Polygon(pts, 7); // 绘制叶脉 pDC->SelectObject(&veinPen); pDC->MoveTo(center.x, center.y - 40); pDC->LineTo(center.x, center.y + 30); // 主脉 pDC->MoveTo(center.x, center.y - 10); pDC->LineTo(center.x - 20, center.y - 5); // 左侧脉 pDC->MoveTo(center.x, center.y - 10); pDC->LineTo(center.x + 20, center.y - 5); // 右侧脉 // 恢复原始画笔和画刷 pDC->SelectObject(pOldPen); pDC->SelectObject(pOldBrush); }

        (3)在OnDraw函数中调用LoadData函数。代码如下:

void CExp_01View::OnDraw(CDC* pDC) { CExp_01Doc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // TODO: add draw code for native data here DrawPloygons(pDC); //调用DrawPloygons函数 DrawPoints(pDC); //调用DrawPoints函数 DrawLines(pDC); //调用DrawLines函数 CRect rect; GetClientRect(&rect); CPoint center = rect.CenterPoint(); DrawLeaf(pDC, center); }

        (4)调试运行,结果如下图10所示: 

图8 简易树叶投影绘制

5 体会与总结

        本次实验通过创建单文本的MFC AppWizard项目,并使用MoveTo 、LineTo、Ploygon等函数绘制简易的区域平面图,包括行政中心等点要素,道路、河流等线要素,湖泊、操场、建筑范围等面要素。同时,在实验过程中,尝试以不同的方式实现相同的效果或以尝试其他方式以提高代码撰写的效率。最后,通过绘制简易的叶片投影,并将其始终置于客户区的中央,使用Ploygon等函数简化描摹树叶叶片以二维图像凸显三维效果,表示正射投影的图形表示。

        后期采集的叶片数据可能以.tex等文件格式存储三维叶片数据,可创建结构体、数组等将其读取与临时储存,通过正射投影、透视投影等投影方式将其转换为二维点集数据,以便于映射在二维的屏幕坐标中显示绘制。同时平移坐标点,使数据显示在客户区的中央。为三维与二维的建模转换的学习奠定良好的启发效果。

参考文献

  1. 侯俊杰. 深入浅出MFC(第2版)[M]. 武汉: 华中科技大学出版社, 2001: 80.00. ISBN 7-900614-93-1.

Read more

宇树机器人SDK2开发指南:从环境搭建到Demo测试

宇树机器人SDK2开发指南:从环境搭建到Demo测试

本文以宇树 G1 人形机器人为主线,系统介绍 unitree_sdk2(C++)与 unitree_sdk2_python(Python)的完整开发流程,涵盖通信架构原理、环境搭建、依赖安装、Demo 编译运行、网络配置以及常见问题处理,适合具身智能领域的初中级开发者快速上手。 目录 1. SDK2 概述与架构原理 2. 开发环境要求 3. 获取官方 SDK 包 4. 安装依赖与编译 5. 机器人与开发机网络配置 6. 调试并运行 Demo 7. Python SDK Demo 测试 8. 常见问题与解决方案 9. 总结 1. SDK2 概述与架构原理 1.

By Ne0inhk
从零开始使用ISSACLAB训练自己的机器人行走

从零开始使用ISSACLAB训练自己的机器人行走

ISAACLAB入门教程 作者:陈维耀 1. 环境配置 1.1 推荐配置 * 操作系统: Ubuntu 22.04 LTS * 显卡: NVIDIA RTX 4080或以上 1.2 ubuntu 22.04 LTS安装 参考ZEEKLOG的Ubuntu 16.04 LTS安装教程,将其中的ubuntu 16.04镜像文件替换为ubuntu 22.04镜像文件,其他步骤保持不变,建议/home与/usr的硬盘容量均不少于200G。 1.3 安装NVIDIA驱动 根据自身显卡型号与操作系统,选择对应的显卡驱动,建议选择550.xxx.xxx版本的显卡驱动,按照教程进行安装即可,安装完成后在终端输入nvidia-smi,若出现以下信息则表示驱动安装成功: Thu Jun 5

By Ne0inhk
最新 neo4j 5.26版本下载安装配置步骤(新手必备)

最新 neo4j 5.26版本下载安装配置步骤(新手必备)

目录 初识:neo4j 安装环境要求 一、下载Neo4j 二、配置环境变量 三、启动测试 四、常用命令及配置 创作不易,禁止转载抄袭!!!违者必究!!! 创作不易,禁止转载抄袭!!!违者必究!!! 创作不易,禁止转载抄袭!!!违者必究!!! 初识:neo4j Neo4j是一个高性能的NoSQL图形数据库,它将结构化数据存储在网络(从数学角度称为图)上而不是传统的表中。‌ Neo4j是一个嵌入式的、基于磁盘的、具备完全事务特性的Java持久化引擎,特别适合处理具有复杂关系的数据‌。 安装环境要求 * 操作系统:Windows 10/8/7、macOS 10.13或更高版本、Linux(Ubuntu、CentOS、Red Hat 等) * JDK 17 或更高版本(Neo4j

By Ne0inhk
【VR音游】音符轨道系统开发实录与原理解析(OpenXR手势交互)

【VR音游】音符轨道系统开发实录与原理解析(OpenXR手势交互)

VR音游音符轨道系统开发实录与原理解析 在 VR 音游的开发过程中,音符轨道系统是最核心的交互与可视化部分。本文结合一次完整的开发实录,分享从核心原理与设计到VR内容构建的完整过程,帮助读者快速理解音符轨道系统的实现思路。 文章目录 * VR音游音符轨道系统开发实录与原理解析 * 一、实录结果 * 二、VR内容开发步骤 * 1. 准备音符与交互逻辑 * 2. 创建谱面 * 3. 绘制音轨 * 4. 预制件与音频替换 * 三、原理解析(音符轨道系统) * 1. 音符轨道(Note Track) * 2. 轨迹调节与偏移控制 * 3. 音符触摸激活 * 4. 谱面编辑工具(Editor 功能) * 四、总结与展望 * 1. 成果回顾:从零到一的核心突破 * 2. 技术总结:核心设计理念 * 3. 开发难点与问题反思 * 4. 优化策略与改进方向 * 5.

By Ne0inhk