计算几何与图形学有关的几种常用算法
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
算法系列之九:计算几何与图形学有关的几种常用算法(一)
分类:算法系列2011-12-18 23:13 8182人阅读评论(41) 收藏举报
我的专业是计算机辅助设计(CAD),算是一半机械一半软件,《计算机图形学》是必修课,也是我最喜欢的课程。热衷于用代码摆平一切的我几乎将这本教科书上的每种算法都实现了一遍,这种重复劳动虽然意义不大,但是收获很多,特别是丢弃了多年的数学又重新回到了脑袋中,算是最大的收获吧。尽管已经毕业多年了,但是每次回顾这些算法的代码,都觉得内心十分澎湃,如果换成现在的我,恐怕再也不会有动力去做这些事情了。
在学习《计算机图形学》之前,总觉得很多东西高深莫测,但实际掌握了之后,却发现其中了无神秘可言,就如同被原始人像神一样崇拜的火却被现代人叼在嘴上玩弄一样的感觉。图形学的基础之一就是计算几何,但是没有理论数学那么高深莫测,它很有实践性,有时候甚至可以简单到匪夷所思。计算几何是随着计算机和CAD的应用而诞生的一门新兴学科,在国外被称为“计算机辅助几何设计(Computer Aided Geometric Design,CAGD)”。“算法系列”接下来的几篇文章就会介绍一些图形学中常见的计算几何算法(顺便晒晒我的旧代码),都是一些图形学中的基础算法,需要一些图形学的知识和数学知识,但是都不难。不信?那就来看看到底有多难。
本文是第一篇,主要是一些图形学常用的计算几何方法,涉及到向量、点线关系以及点与多边形关系求解等数学知识,还有一些平面几何的基本原理。事先声明一下,文中涉及的算法实现都是着眼于解释原理以及揭示算法实质的目的,在算法效率和可读性二者的考量上,更注重可读性,有时候为了提高可读性会刻意采取“效率不高”的代码形式,实际工程中使用的代码肯定更紧凑更高效,但是算法原理都是一样的,请读者们对此有正确的认识。
一、判断点是否在矩形内
计算机图形学和数学到底有什么关系?我们先来看几个例子,增加一些感性认识。首先是判断一个点是否在矩形内的算法,这是一个很简单的算法,但是
却非常重要。比如你在一个按钮上点击鼠标,系统如何知道你要触发这个按钮对应的事件而不是另一个按钮?对了,就是一个点是否在矩形内的判断处理。Windows 的API提供了PtInRect()函数,实现方法其实就是判断点的x坐标和y坐标是否同时落在矩形的x坐标范围和y坐标范围内,算法实现也很简单:
150bool IsPointInRect(const Rect& rc,const Point& p)
151{
152double xr =(p.x - rc.p1.x)*(p.x - rc.p2.x);
153double yr =(p.y - rc.p1.y)*(p.y - rc.p2.y);
154
155return((xr <=0.0)&&(yr <=0.0));
156}
看看IsPointInRect()函数的实现是否和你想象的不一样?有时候硬件实现乘法有困难或受限制于CPU乘法指令的效率,可以考虑用下面的函数替换,代码繁琐了一点,但是避免了乘法运算:
120bool IsPointInRect(const Rect& rc,const Point& p)
121{
122double xl,xr,yt,yb;
123
124if(rc.p1.x < rc.p2.x)
125{
126 xl = rc.p1.x;
127 xr = rc.p2.x;
128}
129else
130{
131 xl = rc.p2.x;
132 xr = rc.p1.x;
133}
134
135if(rc.p1.y < rc.p2.y)
136{
137 yt = rc.p2.y;
138 yb = rc.p1.y;
139}
140else
141{
142 yt = rc.p1.y;
143 yb = rc.p2.y;
144}
145
146return((p.x >= xl && p.x <= xr)&&(p.y >= yb && p.y <= yt));
147}
由于IsPointInRect()函数并不假设矩形的两个定点是按照坐标轴升序排列的,所以算法实现时就考虑了所有可能的坐标范围。IsPointInRect()函数使用的是平面直角坐标系,如果不特别说明,本文所有的算法都是基于平面直角坐标系设计的。另外,IsPointInRect()函数没有指定特别的浮点数精度范围,默认是系统浮点数的最大精度,只在某些必须要与0比较的情况下,采用10-8次方精度,如无特别说明,本文的所有算法都这样处理。
一、判断点是否在圆内
现在考虑复杂一点,如果图形界面的按钮不是矩形而是圆形的怎么办呢?当然就是判断点是否在圆内部。判断算法的原理就是计算点到圆心的距离d,然后与圆半径r进行比较,若d < r则说明点在圆内,若d = r则说明点在圆上,若d > r则说明点在圆外。这就要提到计算平面上两点距离的算法。以下图为例,计算平面上任意两点之间的距离主要依据著名的勾股定理:
图1 平面两点距离计算示意图
113//计算欧氏几何空间内平面两点的距离
114double PointDistance(const Point& p1,const Point& p2)
115{
116return std::sqrt((p1.x-p2.x)*(p1.x-p2.x)
117+(p1.y-p2.y)*(p1.y-p2.y));
118}
一、判断点是否在多边形内
现在再考虑复杂一点的,如果按钮是个不规则的多边形区域怎么办?别以为这个考虑没有意义,很多多媒体软件和游戏,通常都是用各种形状的不规则图案作为热点(Hot Spot),Windows也提供了PtInRegion() API,用于判断点是否在一个不规则区域中。我们对问题做一个简化,就判断一个点是否在多边形内?判断点P是否在多边形内是计算几何中一个非常基本的算法,最常用的方法是射线法。以P点为端点,向左方做射线L,然后沿着L从无穷远处开始向P 点移动,当遇到多边形的某一条边时,记为与多边形的第一个交点,表示进入多边形内部,继续移动,当遇到另一个交点时,表示离开多边形内部。由此可知,当L与多边形的交点个数是偶数时,表示P点在多边形外,当L与多边形交点个数是奇数时,表示P点在多边形内部。
由此可见,要实现判断点是否在多边形内的算法,需要知道直线段求交算法,而求交算法又涉及到矢量的一些基本概念,因此在实现这个算法之前,先讲一下矢量的基本概念以及线段求交算法。
3.1 矢量的基础知识
什么是矢量?简单地讲,就是既有大小又有方向的量,数学中又常被称为向量。矢量有几何表示、代数表示和坐标表示等多种表现形式,本文讨论的是几何表示。如果一条线段的端点是有次序之分的,我们把这种线段成为有向线段(Directed Segment),比如线段P1P2,如果起始端点P1就是坐标原点(0, 0),P2的坐标是(x, y),则线段P1P2的二维矢量坐标表示就是P=(x, y)。