使用MFC的CDC类绘制三维坐标系及球面函数
2017-10-13 01:28
483 查看
系列链接
使用MFC的CDC类绘制二维坐标系及正余弦函数 / 源码使用MFC的CDC类绘制三维坐标系及球面函数 / 源码
概述
本文使用MFC的CDC类绘制三维坐标系及球面函数。首先计算推导出三维坐标在二维平面显示的坐标变换方程(使用斜二测视图),使用球面的参数方程,然后定义图形缩放比例规模、坐标轴位移,变换坐标系和规模等,最后绘制坐标轴及球面函数。如果对绘制二维坐标系还不太熟悉可以先看上面系列链接的:使用MFC的CDC类绘制二维坐标系及正余弦函数,本文对二维绘制及绘制函数部分不再赘述。因为二维坐标系的博文已经分模块讲解地比较清楚了,而与三维坐标系的基本思路相同,所以本文大部分直接使用注释讲解。
三维转二维的推导
若图片字体太小请右键图片在新标签页中打开图片上图可知,只要使用
Transform3Dto2D()函数,即可方便的把三维坐标转化为二维坐标(斜二测视图)。
球面参数方程
在三维空间直角坐标系中,以原点为球心、半径为r的球面的方程为
x^2 + y^2 + z^2 = r^2,其参数方程为
新建项目
Visual Studio-
新建项目-
MFC应用程序- 命名为
GraphicsExercise3D-
确定-
下一步- 应用程序类型选择
单个文档-
完成
GraphicsExercise3DView.h
在GraphicsExercise3DView.h添加以下内容
// 操作 public: void SetScale(int scale); void SetTransformOrigin(float transformOriginX, float transformOriginY); void SetPlotSphere(float radius, float stepPhi, float stepTheta); void SetSlantRadian(float slant); float TransformScale(float num); float TransformOriginX(float x); float TransformOriginY(float y); float TransformOriginScaleX(float x); float TransformOriginScaleY(float y); void Transform3Dto2D(float &x, float &y, float z); private: int scale; float radius, stepPhi, stepTheta, slant, transformOriginX, transformOriginY;
GraphicsExercise3DView.cpp
引入数学函数库#include <math.h>
定义π
#ifndef PI #define PI 3.14159 #endif // !PI
在构造函数初始化
CGraphicsExercise3DView::CGraphicsExercise3DView() { // TODO: 在此处添加构造代码 // 设置斜二测视图倾斜角度(弧度制) SetSlantRadian(PI / 4); // 设置规模比例 SetScale(70); // 设置坐标系在x、y方向的位移(不改变规模情况下,即移动像素) SetTransformOrigin(300, 350); // 设置球面半径radius、取样步长stepPhi、stepTheta SetPlotSphere(2.0, 0.01, 0.1); }
设置初始化参数的Set函数
// 设置规模 void CGraphicsExercise3DView::SetScale(int scale) { this->scale = scale; } // 设置坐标系原点在x、y方向的位移(不改变规模情况下,即移动像素) void CGraphicsExercise3DView::SetTransformOrigin(float transformOriginX, float transformOriginY) { this->transformOriginX = transformOriginX; this->transformOriginY = transformOriginY; } // 设置球面半径radius、取样步长stepPhi、stepTheta void CGraphicsExercise3DView::SetPlotSphere(float radius, float stepPhi, float stepTheta) { this->radius = radius; this->stepPhi = stepPhi; this->stepTheta = stepTheta; } // 设置斜二测视图的倾斜角(单位弧度) void CGraphicsExercise3DView::SetSlantRadian(float slant) { this->slant = slant; }
坐标及规模变换
// 变换规模 float CGraphicsExercise3DView::TransformScale(float num) { return num * scale; } // 坐标系X轴方向位移 float CGraphicsExercise3DView::TransformOriginX(float x) { return x + transformOriginX / scale; } // 坐标系y轴方向位移 float CGraphicsExercise3DView::TransformOriginY(float y) { return y - transformOriginY / scale; } // 变换坐标系X和规模 float CGraphicsExercise3DView::TransformOriginScaleX(float x) { return TransformScale(TransformOriginX(x)); } // 变换坐标系Y和规模 float CGraphicsExercise3DView::TransformOriginScaleY(float y) { return -TransformScale(TransformOriginY(y)); }
三维坐标转化为二维坐标
// 使用斜二测视图,把三维坐标点转化为二维平面上的点 void CGraphicsExercise3DView::Transform3Dto2D(float &x, float &y, float z) { x = x - (z * cos(slant)) / 2; y = y - (z e525 * sin(slant)) / 2; }
绘制坐标轴及函数图形
// CGraphicsExercise2View 绘制 void CGraphicsExercise3DView::OnDraw(CDC* pDC) { CGraphicsExercise3DDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; // TODO: 在此处为本机数据添加绘制代码 float x, y, z; // -------------------- 绘制坐标系 ------------------------- // 坐标x轴 pDC->MoveTo(TransformOriginScaleX(0), TransformOriginScaleY(0)); pDC->LineTo(TransformOriginScaleX(radius + 2), TransformOriginScaleY(0)); // 坐标y轴 pDC->MoveTo(TransformOriginScaleX(0), TransformOriginScaleY(0)); pDC->LineTo(TransformOriginScaleX(0), TransformOriginScaleY(radius + 2)); // 坐标z轴 x = 0, y = 0; Transform3Dto2D(x, y, radius + 5); pDC->MoveTo(TransformOriginScaleX(0), TransformOriginScaleY(0)); pDC->LineTo(TransformOriginScaleX(x), TransformOriginScaleY(y)); // 坐标x轴的箭头 pDC->MoveTo(TransformOriginScaleX(radius + 1.8), TransformOriginScaleY(0.2)); pDC->LineTo(TransformOriginScaleX(radius + 2), TransformOriginScaleY(0)); pDC->LineTo(TransformOriginScaleX(radius + 1.8), TransformOriginScaleY(-0.2)); // 坐标y轴的箭头 pDC->MoveTo(TransformOriginScaleX(-0.2), TransformOriginScaleY(radius + 1.8)); pDC->LineTo(TransformOriginScaleX(0), TransformOriginScaleY(radius + 2)); pDC->LineTo(TransformOriginScaleX(0.2), TransformOriginScaleY(radius + 1.8)); // 坐标z轴的箭头 x = 0, y = 0.2; Transform3Dto2D(x, y, radius + 5 - 0.2); pDC->MoveTo(TransformOriginScaleX(x), TransformOriginScaleY(y)); x = 0, y = 0; Transform3Dto2D(x, y, radius + 5); pDC->LineTo(TransformOriginScaleX(x), TransformOriginScaleY(y)); x = 0.2, y = 0; Transform3Dto2D(x, y, radius + 5 - 0.2); pDC->LineTo(TransformOriginScaleX(x), TransformOriginScaleY(y)); // -------------------- 绘制刻度线 ------------------------- // 绘制x轴刻度线 for (float scaleX = 0.2; scaleX < radius + 1; scaleX += 0.2) { pDC->MoveTo((int)TransformOriginScaleX(scaleX), (int)TransformOriginScaleY(0)); pDC->LineTo((int)TransformOriginScaleX(scaleX), (int)TransformOriginScaleY(0.1)); } // 绘制y轴刻度线 for (float scaleY = 0.2; scaleY <= radius + 1; scaleY += 0.2) { pDC->MoveTo((int)TransformOriginScaleX(0), (int)TransformOriginScaleY(scaleY)); pDC->LineTo((int)TransformOriginScaleX(0.1), (int)TransformOriginScaleY(scaleY)); } // 绘制z轴刻度线 for (float x = 0, y = 0, scaleZ = 0.2; scaleZ <= radius + 4; scaleZ += 0.2, x = 0, y = 0) { Transform3Dto2D(x, y, scaleZ); pDC->MoveTo((int)TransformOriginScaleX(x), (int)TransformOriginScaleY(y)); pDC->LineTo((int)TransformOriginScaleX(x + 0.1), (int)TransformOriginScaleY(y)); } // -------------------- 绘制文字 ------------------------- // 绘制x轴的x pDC->TextOutW(TransformOriginScaleX(radius + 1.6), TransformOriginScaleY(-0.2), CString("x")); // 绘制y轴的y pDC->TextOutW(TransformOriginScaleX(-0.2), TransformOriginScaleY(radius + 1.6), CString("y")); // 绘制z轴的z x = 0.2, y = 0; Transform3Dto2D(x, y, radius + 5 - 0.4); pDC->TextOutW(TransformOriginScaleX(x), TransformOriginScaleY(y), CString("z")); CString s; // 绘制x轴刻度文字 for (float ScaleTextX = 0.4; ScaleTextX < radius + 1; ScaleTextX += 0.4) { s.Format(_T("%.1f"), ScaleTextX); pDC->TextOutW(TransformOriginScaleX(ScaleTextX - 0.1), TransformOriginScaleY(-0.1), s); } // 绘制y轴刻度文字 for (float ScaleTextY = 0.4; ScaleTextY <= radius + 1; ScaleTextY += 0.4) { s.Format(_T("%.1f"), ScaleTextY); pDC->TextOutW(TransformOriginScaleX(-0.4), TransformOriginScaleY(ScaleTextY + 0.1), s); } // 绘制z轴刻度文字 for (float ScaleTextZ = 0.6; ScaleTextZ <= radius + 4; ScaleTextZ += 0.6) { s.Format(_T("%.1f"), ScaleTextZ); x = 0, y = 0; Transform3Dto2D(x, y, ScaleTextZ); pDC->TextOutW(TransformOriginScaleX(x + 0.15), TransformOriginScaleY(y + 0.12), s); } // 绘制函数图的Title x = 0, y = 0; Transform3Dto2D(x, y, radius + 5); pDC->TextOutW(TransformOriginScaleX(x + 3), TransformOriginScaleY(y), CString("x^2 + y^2 + z^2 = r^2")); // -------------------- 绘制函数 ------------------------- // 球面 float phi, theta; for (phi = 0; phi < 2 * PI; phi += stepPhi) { for (theta = 0; theta < PI; theta += stepTheta) { x = radius * sin(phi) * cos(theta); y = radius * sin(phi) * sin(theta); z = radius * cos(phi); Transform3Dto2D(x, y, z); srand(z); pDC->SetPixel(TransformOriginScaleX(x), TransformOriginScaleY(y), RGB(rand() % 255, rand() % 255, rand() % 255)); } } //// 三棱锥(测试用) //x = 1, y = 0, z = 0; //Transform3Dto2D(x, y, z); //pDC->MoveTo((int)TransformOriginScaleX(x), (int)TransformOriginScaleY(y)); //x = 0, y = 1, z = 0; //Transform3Dto2D(x, y, z); //pDC->LineTo((int)TransformOriginScaleX(x), (int)TransformOriginScaleY(y)); //x = 0, y = 0, z = 1; //Transform3Dto2D(x, y, z); //pDC->LineTo((int)TransformOriginScaleX(x), (int)TransformOriginScaleY(y)); //x = 1, y = 0, z = 0; //Transform3Dto2D(x, y, z); //pDC->LineTo((int)TransformOriginScaleX(x), (int)TransformOriginScaleY(y)); }
效果图
相关文章推荐
- 使用 4000 MFC的CDC类绘制二维坐标系及正余弦函数
- 在MFC程序中使用CImage类绘制半透明图像
- 使用MFC进行编程,绘制直线椭圆以及样条曲线
- MFC使用API函数GdiAlphaBlend绘制半透明控件
- 使用MFC CImage类绘制PNG图片时遇到的问题
- 使用MFC CImage类绘制PNG图片时遇到的问题
- MFC 绘制窗口 CDC类 CBitmap类
- Lesson4 MFC消息映射机制和CDC类的使用 ---孙鑫VC++教程
- 使用MFC CImage类绘制PNG图片时遇到的问题
- 使用MFC CImage类绘制PNG图片时遇到的问题
- 在MFC下绘制直线,使用橡皮筋技术,可以使直线效果跟随鼠标移
- 使用MFC CImage类绘制PNG图片时遇到的问题
- 孙鑫VC学习笔记:第四讲 MFC消息映射机制和CDC类的使用
- MFC 使用双缓冲技术绘制坐标曲线
- mfc中使用不同的画笔来绘制图形
- 解析RTSP流后,使用opengl在MFC界面绘制1920*1080P的图像
- mfc ,vc 使用过滤色绘制图片
- MFC绘图 (孙鑫老师 第四讲 MFC消息映射机制和CDC类的使用 参考文章)
- 孙鑫VC学习笔记:第四讲 MFC消息映射机制和CDC类的使用
- MFC中使用agg绘制直线