计算几何与图形学有关的几种常用算法Word格式.docx

上传人:b****4 文档编号:16663240 上传时间:2022-11-25 格式:DOCX 页数:18 大小:86.55KB
下载 相关 举报
计算几何与图形学有关的几种常用算法Word格式.docx_第1页
第1页 / 共18页
计算几何与图形学有关的几种常用算法Word格式.docx_第2页
第2页 / 共18页
计算几何与图形学有关的几种常用算法Word格式.docx_第3页
第3页 / 共18页
计算几何与图形学有关的几种常用算法Word格式.docx_第4页
第4页 / 共18页
计算几何与图形学有关的几种常用算法Word格式.docx_第5页
第5页 / 共18页
点击查看更多>>
下载资源
资源描述

计算几何与图形学有关的几种常用算法Word格式.docx

《计算几何与图形学有关的几种常用算法Word格式.docx》由会员分享,可在线阅读,更多相关《计算几何与图形学有关的几种常用算法Word格式.docx(18页珍藏版)》请在冰豆网上搜索。

计算几何与图形学有关的几种常用算法Word格式.docx

153 

doubleyr=(p.y-rc.p1.y)*(p.y-rc.p2.y);

154 

155 

return((xr<

=0.0)&

&

(yr<

=0.0));

156 

}

看看IsPointInRect()函数的实现是否和你想象的不一样?

有时候硬件实现乘法有困难或受限制于CPU乘法指令的效率,可以考虑用下面的函数替换,代码繁琐了一点,但是避免了乘法运算:

120 

121 

122 

doublexl,xr,yt,yb;

123 

124 

if(rc.p1.x<

rc.p2.x)

125 

{

126 

 

xl=rc.p1.x;

127 

xr=rc.p2.x;

128 

}

129 

else

130 

131 

xl=rc.p2.x;

132 

xr=rc.p1.x;

133 

134 

135 

if(rc.p1.y<

rc.p2.y)

136 

137 

yt=rc.p2.y;

138 

yb=rc.p1.y;

139 

140 

141 

142 

yt=rc.p1.y;

143 

yb=rc.p2.y;

144 

145 

146 

return((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 

//计算欧氏几何空间内平面两点的距离

114 

doublePointDistance(constPoint&

p1,constPoint&

p2)

115 

116 

returnstd:

:

sqrt((p1.x-p2.x)*(p1.x-p2.x)

117 

+(p1.y-p2.y)*(p1.y-p2.y));

118 

判断点是否在多边形内

现在再考虑复杂一点的,如果按钮是个不规则的多边形区域怎么办?

别以为这个考虑没有意义,很多多媒体软件和游戏,通常都是用各种形状的不规则图案作为热点(HotSpot),Windows也提供了PtInRegion()API,用于判断点是否在一个不规则区域中。

我们对问题做一个简化,就判断一个点是否在多边形内?

判断点P是否在多边形内是计算几何中一个非常基本的算法,最常用的方法是射线法。

以P点为端点,向左方做射线L,然后沿着L从无穷远处开始向P点移动,当遇到多边形的某一条边时,记为与多边形的第一个交点,表示进入多边形内部,继续移动,当遇到另一个交点时,表示离开多边形内部。

由此可知,当L与多边形的交点个数是偶数时,表示P点在多边形外,当L与多边形交点个数是奇数时,表示P点在多边形内部。

由此可见,要实现判断点是否在多边形内的算法,需要知道直线段求交算法,而求交算法又涉及到矢量的一些基本概念,因此在实现这个算法之前,先讲一下矢量的基本概念以及线段求交算法。

3.1矢量的基础知识

什么是矢量?

简单地讲,就是既有大小又有方向的量,数学中又常被称为向量。

矢量有几何表示、代数表示和坐标表示等多种表现形式,本文讨论的是几何表示。

如果一条线段的端点是有次序之分的,我们把这种线段成为有向线段(DirectedSegment),比如线段P1P2,如果起始端点P1就是坐标原点(0,0),P2的坐标是(x,y),则线段P1P2的二维矢量坐标表示就是P=(x,y)。

3.2矢量的加法和减法

现在来看几个与矢量有关的重要概念,首先是矢量的加减法。

假设有二维矢量P=(x1,y1),Q=(x2,y2),则矢量加法定义为:

P+Q=(x1+x2,y1+y2)

同样的,矢量减法定义为:

P-Q=(x1-x2,y1-y2)

根据矢量加减法的定义,矢量的加减法满足以下性质:

P+Q=Q+P

P-Q=-(Q-P)

图2演示了矢量加法和减法的几何意义,由于几何中直线段的两个点不可能刚好在原点,因此线段P1P2的矢量其实就是OP2-OP1的结果,如图2(b)所示:

3.3矢量的叉积(外积)

另一个比较重要的概念是矢量的叉积(外积)。

计算矢量的叉积是判断直线和线段、线段和线段以及线段和点的位置关系的核心算法。

假设有二维矢量P=(x1,y1),Q=(x2,y2),则矢量的叉积定义为:

Q=x1*y2-x2*y1

向量叉积的几何意义可以描述为由坐标原点(0,0)、P、Q和P+Q所组成的平行四边形的面积,而且是个带符号的面积,由此可知,矢量的叉积具有以下性质:

Q=-(Q×

P)

叉积的结果P×

Q是P和Q所在平面的法矢量,它的方向是垂直与P和Q所在的平面,并且按照P、Q和P×

Q的次序构成右手系,所以叉积的另一个非常重要性质是可以通过它的符号可以判断两矢量相互之间位置关系是顺时针还是逆时针关系,具体说明如下:

1)如果P×

Q>

0,则Q在P的逆时针方向;

2)如果P×

Q<

0,则Q在P的顺时针方向;

3)如果P×

Q=0,则Q与P共线(但可能方向是反的);

3.4矢量的点积(内积)

最后要介绍的概念是矢量的点积(内积)。

假设有二维矢量P=(x1,y1),Q=(x2,y2),则矢量的点积定义为:

Q=x1*x2+y1*y2

向量点积的结果是一个标量,它的代数表示是:

Q=|P||Q|cos(P,Q)

(P,Q)表示向量P和Q的夹角,如果P和Q不共线,则根据上式可以得到向量点积的一个非常重要的性质,具体说明如下:

1)如果P·

0,则P和Q的夹角是钝角(大于90度);

2)如果P·

0,则P和Q的夹角是锐角(小于90度);

3)如果P·

Q=0,则P和Q的夹角是90度;

了解了矢量的概念以及矢量的各种运算的几何意义和代数意义后,就可以开始解决各种计算几何的简单问题了,回想本文开始提到的点与多边形的关系问题,首先要解决的就是判断点和直线段的位置关系问题。

3.5用矢量的叉积判断点和直线的关系

根据矢量叉积的几何意义,如果线段所表示的矢量和点的矢量的叉积是0,就说明点在线段所在的直线上,相对于坐标原点O来说,线段的矢量其实就是线段终点P2=[x2,y2]的矢量OP2减线段起点P1=[x1,y1]的矢量OP1的结果,因此线段P1P2的矢量可以表示为P1P2=(x2–x1,y2–y1)。

如果要判断点P是否在线段P1P2上,就要判断矢量P1P2和矢量OP的叉积是否是0。

需要注意的是,叉积为0只能说明点P与线段P1P2所在的直线共线,并不能说明点P一定会落在P1P2区间上,因此只是一个必要条件。

要正确判断P在线段P1P2上,还需要做一个排斥试验,就是检查点P是否在以直线段为对角线的矩形空间内,如果以上两个条件都为真,即可判定点在线段上。

有了上述原理,算法实现就比较简单了,以下就是判断点是否在线段上的算法:

174 

boolIsPointOnLineSegment(constLineSeg&

ls,constPoint&

pt)

175 

176 

Rectrc;

177 

178 

GetLineSegmentRect(ls,rc);

179 

doublecp=CrossProduct(ls.pe.x-ls.ps.x,ls.pe.y-ls.ps.y,

180 

pt.x-ls.ps.x,pt.y-ls.ps.y);

//计算叉积

181 

182 

return((IsPointInRect(rc,pt))//排除实验

183 

&

IsZeroFloatValue(cp));

//1E-8精度

184 

185 

【未完,下篇继续介绍用矢量叉积判断直线和直线段的位置关系,以及判断点与多边形关系的完整算法】

计算几何与图形学有关的几种常用算法

(二)

算法系列2011-12-2523:

042346人阅读评论(9)收藏举报

3.6用矢量的叉积判断直线段是否有交 

矢量叉积计算的另一个常用用途是直线段求交。

求交算法是计算机图形学的核心算法,也是体现速度和稳定性的重要标志,高效并且稳定的求交算法是任何一个CAD软件都必需要重点关注的。

求交包含两层概念,一个是判断是否相交,另一个是求出交点。

直线(段)的求交算法相对来说是比较简单的,首先来看看如何判断两直线段是否相交。

常规的代数计算通常分三步,首先根据线段还原出两条线段所在直线的方程,然后联立方程组求出交点,最后再判断交点是否在线段区间上。

常规的代数方法非常繁琐,每次都要解方程组求交点,特别是交点不在线段区间的情况,计算交点就是做无用功。

计算几何方法判断直线段是否有交点通常分两个步骤完成,这两个步骤分别是快速排斥试验和跨立试验。

假设要判断线段P1P2和线段Q1Q2是否有交点,则:

(1) 

快速排斥试验

设以线段P1P2为对角线的矩形为R1,设以线段Q1Q2为对角线的矩形为R2,如果R1和R2不相交,则两线段不会有交点;

(2) 

跨立试验。

如果两线段相交,则两线段必然相互跨立对方,所谓跨立,指的是一条线段的两端点分别位于另一线段所在直线的两边。

判断是否跨立,还是要用到矢量叉积的几何意义。

以图3为例,若P1P2跨立Q1Q2,则矢量(P1-Q1)和(P2-Q1)位于矢量(Q2-Q1)的两侧,即:

(P1-Q1)×

(Q2-Q1)*(P2-Q1)×

(Q2-Q1)<

0

上式可改写成:

(Q2-Q1)*(Q2-Q1)×

(P2-Q1)>

当(P1-Q1)×

(Q2-Q1)=0时,说明线段P1P2和Q1Q2共线(但是不一定有交点)。

同理判断Q1Q2跨立P1P2的依据是:

(Q1-P1)×

(P2-P1)*(Q2-P1)×

(P2-P1)<

具体情况如下图所示:

图3直线段跨立试验示意图

根据矢量叉积的几何意义,跨立试验只能证明线段的两端点位于另一个线段所在直线的两边,但是不能保证是在另一直线段的两端,因此,跨立试验只是证明两条线段有交点的必要条件,必需和快速排斥试验一起才能组成直线段相交的充分必要条件。

根据以上分析,两条线段有交点的完整判断依据就是:

1)以两条线段为对角线的两个矩形有交集;

2)两条线段相互跨立。

判断直线段跨立用计算叉积算法的CrossProduct()函数即可,还需要一个判断两个矩形是否有交的算法。

矩形求交也是最简单的求交算法之一,原理就是根据两个矩形的最大、最小坐标判断。

图4展示了两个矩形没有交集的各种情况:

图4矩形没有交集的几种情况

图5展示了两个矩形有交集的各种情况:

图5矩形有交集的几种情况

从图4和图5可以分析出来两个矩形有交集的几何坐标规律,就是在x坐标方向和y坐标方向分别满足最大值最小值法则,简单解释这个法则就是每个矩形在每个方向上的坐标最大值都要大于另一个矩形在这个坐标方向上的坐标最小值,否则在这个方向上就不能保证一定有位置重叠。

由以上分析,判断两个矩形是否相交的算法就可以如下实现:

186 

boolIsRectIntersect(constRect&

rc1,constRect&

rc2)

187 

188 

return((std:

max(rc1.p1.x,rc1.p2.x)>

=std:

min(rc2.p1.x,rc2.p2.x))

189 

(std:

max(rc2.p1.x,rc2.p2.x)>

min(rc1.p1.x,rc1.p2.x))

190 

max(rc1.p1.y,rc1.p2.y)>

min(rc2.p1.y,rc2.p2.y))

191 

max(rc2.p1.y,rc2.p2.y)>

min(rc1.p1.y,rc1.p2.y)));

192 

完成了排斥试验和跨立试验的算法,最后判断直线段是否有交点的算法就水到渠成了:

204 

boolIsLineSegmentIntersect(constLineSeg&

ls1,constLineSeg&

ls2)

205 

206 

if(IsLineSegmentExclusive(ls1,ls2))//排斥实验

207 

208 

returnfalse;

209 

210 

//(P1-Q1)×

'

a1?

(Q2-Q1)

211 

doublep1xq=CrossProduct(ls1.ps.x-ls2.ps.x,ls1.ps.y-ls2.ps.y,

212 

ls2.pe.x-ls2.ps.x,ls2.pe.y-ls2.ps.y);

213 

//(P2-Q1)×

214 

doublep2xq=CrossProduct(ls1.pe.x-ls2.ps.x,ls1.pe.y-ls2.ps.y,

215 

216 

217 

//(Q1-P1)×

(P2-P1)

218 

doubleq1xp=CrossProduct(ls2.ps.x-ls1.ps.x,ls2.ps.y-ls1.ps.y,

219 

ls1.pe.x-ls1.ps.x,ls1.pe.y-ls1.ps.y);

220 

//(Q2-P1)×

221 

doubleq2xp=CrossProduct(ls2.pe.x-ls1.ps.x,ls2.pe.y-ls1.ps.y,

222 

223 

224 

//跨立实验

225 

return((p1xq*p2xq<

(q1xp*q2xp<

226 

IsLineSegmentExclusive()函数就是调用IsRectIntersect()函数根据结果做排斥判断,此处不再列出代码。

3.7点和多边形关系的算法实现

好了,现在我们已经了解了矢量叉积的意义,以及判断直线段是否有交点的算法,现在回过头看看文章开始部分的讨论的问题:

如何判断一个点是否在多边形内部?

根据射线法的描述,其核心是求解从P点发出的射线与多边形的边是否有交点。

注意,这里说的是射线,而我们前面讨论的都是线段,好像不适用吧?

没错,确实是不适用,但是我要介绍一种用计算机解决问题时常用的建模思想,应用了这种思想之后,我们前面讨论的方法就适用了。

什么思想呢?

就是根据问题域的规模和性质抽象和简化模型的思想,这可不是故弄玄虚,说说具体的思路吧。

计算机是不能表示无穷大和无穷小,计算机处理的每一个数都有确定的值,而且必须有确定的值。

我们面临的问题域是整个实数空间的坐标系,在每个维度上都是从负无穷到正无穷,比如射线,就是从坐标系中一个明确的点到无穷远处的连线。

这就有点为难计算机了,为此我们需要简化问题的规模。

假设问题中多边形的每个点的坐标都不会超过(-10000.0,+10000.0)区间(比如我们常见的图形输出设备都有大小的限制),我们就可以将问题域简化为(-10000.0,+10000.0)区间内的一小块区域,对于这块区域来说,>

=10000.0就意味着无穷远。

你肯定已经明白了,数学模型经过简化后,算法中提到的射线就可以理解为从模型边界到内部点P之间的线段,前面讨论的关于线段的算法就可以使用了。

射线法的基本原理是判断由P点发出的射线与多边形的交点个数,交点个数是奇数表示P点在多边形内(在多边形的边上也视为在多边形内部的特殊情况),正常情况下经过点P的射线应该如图6(a)所示那样,但是也可能碰到多种非正常情况,比如刚好经过多边形一个定点的情况,如图6(b),这会被误认为和两条边都有交点,还可能与某一条边共线如图6(c)和(d),共线就有无穷多的交点,导致判断规则失效。

还要考虑凹多边形的情况,如图6(e)。

图6射线法可能遇到的各种交点情况

针对这些特殊情况,在对多边形的每条边进行判断时,要考虑以下这些特殊情况,假设当前处理的边是P1P2,则有以下原则:

1)如果点P在边P1P2上,则直接判定点P在多边形内;

2)如果从P发出的射线正好穿过P1或者P2,那么这个交点会被算作2次(因为在处理以P1或P2为端点的其它边时可能已经计算过这个点了),对这种情况的处理原则是:

如果P的y坐标与P1、P2中较小的y坐标相同,则忽略这个交点;

3)如果从P发出的射线与P1P2平行,则忽略这条边;

对于第三个原则,需要判断两条直线是否平行,通常的方法是计算两条直线的斜率,但是本算法因为只涉及到直线段(射线也被模型简化为长线段了),就简化了很多,判断直线是否水平,只要比较一下线段起始点的y坐标是否相等就行了

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 经管营销 > 金融投资

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1