介绍
窗口中的矩形,带圆角的矩形和椭圆只能由GDI在轴向上绘制。假如有人希望在Windows NT下绘制旋转或歪斜的图形,他可以使用世界坐标系变换。很不幸的是在Windows 95/98下,是没有世界坐标系变换的。作为一个跨平台的解决方案,就需要自己做更多的工作。矩形能由四边形模拟,这样它就能旋转和歪斜了。然而,椭圆又该怎么办呢?基本上有三个选择。
两种选择
使用一个定制的函数来画椭圆。
椭圆的数学模型相对简单,而且还有用于在标准文本中旋转椭圆的修改过的Bresenham方程。然而,这种方法必须自己执行光栅操作,这样在绘制宽线时就变得复杂了。这种努力只有在向一个脱离屏幕的表面(比如DirectDraw)或位图上绘制视才是值得的 用连接的线段来绘制椭圆。
实际的线条可以通过LineTo(...)或Polyline(...)图形设备接口调用。你可以自己完成椭圆的近似,或者使用GDI的FlattenPath(...) 函数。
使用贝塞尔曲线来近似绘制椭圆。
这里就举例说明这种方法。
用贝塞尔曲线绘制椭圆
使用四条贝塞尔曲线,每条代表原轴向椭圆的90度,这样就能获得一个相当近似的椭圆,最大误差只有0.027%。这个最大误差相当于长径3700的椭圆的误差小于一个像素,这已经超出我们所要求的准确度了。
优点
简单。
只需要有四个GDI调用。贝塞尔曲线控制点的计算代价是很小的。
快速
你可以利用现在新的显卡对曲线绘制的硬件支持。在我的系统上,这和调用GDI函数Ellipse(...)绘制椭圆的速度比,如果不是更快,至少也是一样快。
变化
因为贝塞尔曲线在旋转、缩放和平移时是不变的,在对椭圆做同样的变化时就只需要传送控制点。更巧的是,因为在一个三次贝塞尔曲线上的每个点都是控制点的重心组合,在仿射映射中曲线上控制点之间的关系是不变的。
设备无关性
假如想自己把椭圆转化为线段或光栅,那么每次表面的分辨率和设备描述表改变时(例如向一个打印机设备描述表绘制时),就必须重新光栅化。而使用贝塞尔曲线时就不需要这样做。还有一个好处就是椭圆能通过图元文件输出到绘画程序,例如CORELDRAW,在其中可以没有失真的缩放图形。
过程
首先以一个轴向椭圆的外接边界矩形开始(使用一个普通的GDI调用)。13个定义4条组成椭圆的贝塞尔曲线的控制点(以下标为0-12)可使用一个经验常量计算得出。下列代码为Y轴正方向向下的的映射模式产生控制点(例如MM_TEXT)。在Y轴正方向向上时,只要如注释中所示,把偏移量设为负值就行了。
// Create points to simulate ellipse using beziers
//使用贝塞尔曲线创建点,模拟椭圆
void EllipseToBezier(CRect& r, CPoint* cCtlPt)
// MAGICAL CONSTANT to map ellipse to beziers
//
/3*(sqrt(2)-1)
// 把椭圆映射为贝塞尔曲线的常量 2/3*(sqrt(2)-1)
const double EToBConst =
.2761423749154;
CSize offset((int)(r.Width() * EToBConst), (int)(r.Height() * EToBConst));
// Use the following line instead for mapping systems where +ve Y is upwards
// 在Y轴正方向向上时,使用下面一行
// CSize offset((int)(r.Width() * EToBConst), -(int)(r.Height() * EToBConst));
CPoint centre((r.left + r.right) / 2, (r.top + r.bottom) / 2);
cCtlPt[0].x = //------------------------/
cCtlPt[1].x = // /
cCtlPt[11].x = // 2___3___4 /
cCtlPt[12].x = r.left; // 1 5 /
cCtlPt[5].x = // | | /
cCtlPt[6].x = // | | /
cCtlPt[7].x = r.right; // 0,12 6 /
cCtlPt[2].x = // | | /
cCtlPt[10].x = centre.x - offset.cx; // | | /
cCtlPt[4].x = // 11 7 /
cCtlPt[8].x = centre.x + offset.cx; // 10___9___8 /
cCtlPt[3].x = // /
cCtlPt[9].x = centre.x; //------------------------*
cCtlPt[2].y =
cCtlPt[3].y =
cCtlPt[4].y = r.top;
cCtlPt[8].y =
cCtlPt[9].y =
cCtlPt[10].y = r.bottom;
cCtlPt[7].y =
cCtlPt[11].y = centre.y + offset.cy;
cCtlPt[1].y =
cCtlPt[5].y = centre.y - offset.cy;
cCtlPt[0].y =
cCtlPt[12].y =
cCtlPt[6].y = centre.y;
使用与下面近似的代码可完成椭圆的旋转
// LDPoint is an equivalent type to CPoint but with floating point precision
// LDPoint是一个和CPoint相当的类型,不过它还具有浮点精度。
void Rotate(double radians, const CPoint& c, CPoint* vCtlPt, unsigned Cnt)
double sinAng = sin(radians);
double cosAng = cos(radians);
LDPoint constTerm( c.x - c.x * cosAng - c.y * sinAng,
c.y + c.x * sinAng - c.y * cosAng);
for (int i = Cnt-1; i>=0; --i)
{
vCtlPt[i] = (LDPoint( vCtlPt[i].x * cosAng + vCtlPt[i].y * sinAng,
-vCtlPt[i].x * sinAng + vCtlPt[i].y * cosAng) + constTerm).GetCPoint();
}
// Create Ellipse
// 创建椭圆
CRect rect; GetClientRect(&rect);
CPoint ellipsePts[13];
EllipseToBezier(ellipseR, ellipsePts);
// Rotate
// 旋转
Rotate(m_Radians, midPoint, ellipsePts, 13);
填充椭圆
当然,无论是不是旋转,四条贝塞尔曲线只完成了椭圆的轮廓。幸运的是,Win32路径功能可用于填充椭圆。你只在需要调用PolyBezier(...)来封闭路径。完成的路径是一笔画出的,而且能被让人满意的填充。假如有人觉得还不够,比如更特殊的填充,比如斜线、用户位图或不规则碎片等。这些能由SelectClipPath(...)来把剪贴区域设置到路径上来而获得。
dc.BeginPath();
dc.PolyBezier(ellipsePts);
dc.EndPath();
dc.StrokePath;
// or FillPath();
// or StrokeAndFillPath();
// or PathToRegion(dc.m_hDC);
//
//或者 FillPath();
//或者StrokeAndFillPath();
//或者PathToRegion(dc.m_hDC);
在Win95/8下宽的虚线或点椭圆轮廓。Win95/8只支持实体宽线。然而,虚线或点椭圆轮廓能容易的由一系列贝塞尔曲线段模拟。
分享到:
相关推荐
画图vc 画直线 曲线 圆形 椭圆 矩形,有重绘功能,欢迎下载。
VC的旋转双线性插值算法 * 该函数用来以图像中心为中心旋转DIB 图像
图形学的作业 有画直线,画圆,画椭圆,画矩形,本来还有画多边形,但是我没有实现,还有每个图元都有热点,可以根据热点来改变图元的大小和形状。
分享2维,VC对椭圆自由旋转。解决旋转的难题,可围绕一个中心点自由旋转。
vc 画曲线vc 画曲线vc 画曲线vc 画曲线vc 画曲线vc 画曲线vc 画曲线vc 画曲线vc 画曲线vc 画曲线vc 画曲线vc 画曲线vc 画曲线vc 画曲线vc 画曲线vc 画曲线
VC 画表格VC 画表格VC 画表格VC 画表格VC 画表格VC 画表格VC 画表格VC 画表格VC 画表格VC 画表格VC 画表格VC 画表格
内容索引:VC/C++源码,图形处理,图形绘制 Graphic 用VC画直线、画椭圆、画矩形、画点,选择所要绘制的图形,拖动鼠标即可完成绘制,同时程序还演示了如何读取和写入TXT文件。
VC程序, 通过运算公式,将图像旋转一定角度,可实现图像的旋转功能,并最后保存出图片来
该函数用来以图像中心为中心旋转DIB图像,返回新生成DIB的句柄。调用该函数会自动扩大图像以显示所有的象素。函数中采用最邻近插值算法进行插值。
VC实现的线性立方体旋转特效,一个可控的透视型立方体盒子旋转模型,鼠标拖动右侧滑块,可改变立方体的三维角度,上边的滑块改变旋转角度,下边的滑块主要是让立方体在Y轴上移动。
用给定的几个点的坐标,可以模拟出距离这些点最近的椭圆方程
此时用VC++编写的基于VC的双线性的图像旋转
使用VC画点,线,圆,填充 还有可以画箭头,然后填充颜色
VC++实现的非线性方程求根,界面美观,调试通过
计算机图形学椭圆算法实现,本人在VS2015下,MFC实现的Bresanham算法画椭圆,分享VC++源码.
用API写的旋转的风车,用API写的旋转的风车,用API写的旋转的风车
VC画菱形 圆形 三角 椭圆 多边形 用各种刷子 和 线条 4段
vc实现旋转字体的简单例子vc实现旋转字体的简单例子vc实现旋转字体的简单例子
VC画虚线矩形,实线矩形和点画线矩形的小demo!
vc画动态曲线图,就任务管理器中的cpu利用率图一样