您的当前位置:首页正文

计算几何初步

2020-01-06 来源:步旅网
计算几何初步

alex4814*March 26,2012

计算几何,简单来讲就是适合于计算机处理的几何方法。

1位置与方向

首先要处理的就是计算几何中最基本的问题——判断线段相交与否以及

求交点的方法。

1.1点、线、面的位置关系

首先提出这样一个最基本的问题:如何判断两线段相交?以此来看看

计算几何的优点。方法1:解析几何

一条线段其实也就是一条直线,我们可以用解析几何的

方法,列出方程组求出交点来判断它们是否相交。 但是弊端非常明显不说斜率有时候无法表示,还有很大的浮点误差。不过用一般方程如Ax+By=

C可以减少一部分麻烦,但还是免不了判断的麻烦。方法2:点积与叉积

从解析几何的算法中我们看到,要判断两线段是否相

交,就得先求他们的交点。但是思考后我们发现,我们并不关注他们的交点在哪,而仅仅只是想知道,这两条线段是否相交。

现在我们来看看线段相交的各种情况。 (示)

*

alex4814.fu@gmail.com

1

acm@njust1位置与方向

Figure1:Judge the side

线段相交⇔每条线段两个端点都在另一条线段所在直线的异侧(非特殊相交的情况)1.1.1

叉积

看看叉积如何解决这样的问题。

叉积对应正弦,点积对应余弦。象限的正负刚好对应了左右和前后。(示)

我们可以不将线段看作单独的两个点,而是考虑有序实数对的概念,给

()()

之一个序。 同样是(0,0),(0,1)这两个点,(0,0),(0,1)和(0,1),(0,0)是两条不同的线段,称之为有向线段。

叉积是这样一个运算,它可以清楚的判断一个向量与另一个向量的方向关系,而且这个运算的结果显而易见,而且容易实现,但也不是能完全避免浮点误差1。

1231

structpoint{

doublex,y;

};

如果题目中全是int型输入,那么更不允许有误差,在数据量大的情况下,要尽量用int或long long来处理。

2

acm@njust1位置与方向

45678910111213141516171819

#defineeps1e-6intsgn(doubled){

if(fabs(d)0?1:-1;

}

doubledet(doublex1,doubley1,doublex2,doubley2){

returnx1*y2-x2*y1;

}

//judgewhichsidepistowardsdirected-segab//posforleft,negforright

doubleside(pointa,pointb,pointp){

returndet(b.x-a.x,b.y-a.y,p.x-a.x,p.y-a.y);

}

让我们看看如何在已知相交的情况下,方便的求得他们的交点。定比分点

xP=

线性方程组

S△ABD·xc+S△ABC·xD

S△ABD+S△ABC

DxD

xP=

要特别注意浮点误差。 再来看看相交的一些特殊情况。(示)1.1.2

点积

−→−−→

要看P是否在线段AB上,只需要看PA·PB的符号即可。 这样虽然方便,不过还是需要乘法,有些许的误差。 让我们看看另一个方法。坐标比较

在已知P在AB直线上的情况下,我们只需考虑x轴或y轴的坐标分

量即可。 尽量减少误差,选择跨度大的那一维。

3

acm@njust1位置与方向

用点积还可以求两个有向线段之间的夹角。

−1

θ=cos

⃗·B⃗A⃗|·|B⃗||A

如果说线段有向比较容易理解的话,那么有向面积就不那么明显了,但是它将有巨大的作用,待后文介绍。

看个例子:Pipe(离散化)Pipe.cpp

1.2点与多边形的位置关系判断

多边形其实就是一些首尾相接的闭合的线段组成的图形。但

简单多边形

是它有很多不同的类型。我们常见的也是讨论最多的是简单多边形,即对于所有非相邻的线段它们没有交点。凸多边形

直观上我们可以看的出来,对于任意一条凸多边形上的边而言,

整个凸多边形在该边的一侧。如果给这个多边形定上正方向的话,那么就是在左侧。 数学上定义则是:

∀x,y∈D,

x+y

∈D2

根据这个定义我们可以得到,x,y上的任意一点均在多边形内的结论。

让我们来看看如何判断一个点,是在多边形内,还是形外。

A·dS=0

Σ

回顾一下对曲面的回路积分,我们知道积分为零。之所以称之为无源,是因为进出相衡。 同理,一个点如果在多边形的外面,如果它穿越这个多边形,那么进出的次数应当相同。所以我们想到根据从它出发的一条射线,与多边形相交2的次数来判断,它到底是在形内还是形外。 很容易理解,奇数次在内,偶数次在外。 为了处理方便,我们往往取与x轴正方向平行的一条射线。 (示)

2

对于和射线有交点的线段来说,如果该交点两侧线段异侧,才真正视为相交

4

acm@njust1位置与方向

当然我们要注意一些特殊情况,如在边上的点。平移法

我们把这条射线向上或向下平移一小段位移,并不会影响结果(改

变的是偶数个交点)。 而且在也判断条件的时候,并没有真正意义上的平移,而只需要修改判断的条件。

每条线段,只要一个点高于(>),另一个点不高于(⩽),交点在P右侧即可。 这就相当于向上平移了一样,本来恰好相交的点。

12345678910111213141516171819202122232425

//whetherthegivenpointisinsideoroutsideofthepolygon//0foroutside//1forinside

//2foronedge(exceptvertices)//3forvertex

//pointsorderedbyinputpolygondirectionintpointDir(point*pg,pointp){

intis,ps,cnt=0;pg[n]=pg[0];pointup,low;

for(i=0;iif(pg[i].y>pg[i+1].y){

up=pg[i];low=pg[i+1];

}else{

up=pg[i+1];low=pg[i];

}

if(up.y>p.y&&low.y<=p.y){

is=sgn(side(p,low,up));if(is>0)++cnt;elseif(is==0){

ps=between(low,up,p);if(ps==0)return3;

5

acm@njust2凸包

26272829303132

elseif(ps==-1)return2;

}

}

}

if(cnt&1)return1;return0;

}

2凸包

definition.

2.1Graham

求凸包方法的简单概括就是:序+方向。 当然共线的问题一直是不可忽

视的。

Figure2:convex hull

algorithm:

1

凸包的求解算法如下

push(p[0]);

6

acm@njust2凸包

234567

push(p[1]);fori=2ton-1

whilep[i]istherightsideofsegment(stack[top-1],stack[top])

pop();

push(p[i]);

有两个序可以选择,一个极角序,一是水平序。当我们改成水平序的时候,只需要分两链进行即可。Melkman

它是一个求简单多边形凸包的精妙算法,可以在线性时间内求

得。 它最大的特点在于采用了双端队列,可以理解为两头都可以增减的栈。 只要在栈顶维护右手系,栈底维护左手系,就能在线的生成凸包。

算法如下:

1.初始的三个点组成的三角形即凸包。此时栈里为3−1−2−3。2.要保证栈顶右手,栈底左手,即为此有必要交换1、2。3.分别对栈顶和栈底维护。

2.2property:

凸包的性质就是凸性。圆就是凸性的极限。任意一条弦均在圆内。 如果

凸包上每条边只有2个点,那么它不能唯一的确定一个多边形。 至少三个点心上即可。

2.3applications:

点集分割最长直径最小外接矩形

7

acm@njust4半平面交

离散化覆盖m点中的n点的最小面积矩形Finding the Rectangle

3

3.1

多边形的面积、核

再现叉积

运用最简单的三角剖分,我们可以分而治之。 这里我们将看到有向面积

的神奇之处,简单多边形的面积可统一为一个通式。 通过简单的三角剖分可以得到

󰀃󰀃

󰀃

󰀃xiyi󰀃1󰀃󰀃A=󰀃󰀃2

i=1󰀃xi+1yi+1󰀃

n󰀃∑

3.2全视角

多边形的核其实也就是能看得见多边形内任何角落的区域,可以没有也

可以是全部(凸包的核即为本身)。 我们可以发现,只要把每条边对应的内侧半平面求交集即可得到该区域。

4半平面交

求多边形核的方法。

4.1仅水平和竖直的情况

我们只需求核的上下左右的边界值lx,rx,by,ay就可以了。 对于(x1,y)→

(x2,y)with(x18

acm@njust4半平面交

operations:

往右by=max(by,y)往上rx=min(rx,x)往左ay=min(rx,x)往下

lx=max(lx,x)

4.2nlgn的求交算法(Zeyuan Zhu)

111

将平面以极角分成(−12π,2π]和(−π,−2π]∪(2π,π)两部分1考虑其中一个(−π,−2π]∪(12π,π)的半平面(另一个类似), 对它

Step 1:Step 2:

们极角排序。若是极角上同的,选择左侧的那一个Step 3:

从排序后极角最小的两个开始,将它们入栈。 每次按排序的顺序加

入一个半平面,算出该平面与栈顶平面的交点。 如果当前交点在 栈顶两个半平面交点的右边,则出栈。 跟Graham类似,出栈直至交点在左边。Step 4:

该一半给出上半个凸多边形,另一半则会给出下一半。

这里我们又用到了双端队列。 核心代码:

1234567891011121314

deq[0]=vec[0];deq[1]=vec[1];fori=2ton-1

ifparallel(tail,tail-1)orparallel(head,head+1)return;while(headside(vec[i].s,vec[i].e,theintersectionpointoftailtwo)<0)

pop(tail);

while(headside(vec[i].s,vec[i].e,theintersectionpointofheadtwo)<0)

pop(head);

push(tail,vec[i]);

while(headistheleftsideofhead)pop(tail);

9

acm@njust4半平面交

151617

while(headistheleftsideoftail)pop(head);

applications:半平面交也就是求一系列线性规划问题的解。 例如两个凸包

求交也可以用半平面交的方法来求。

10

因篇幅问题不能全部显示,请点此查看更多更全内容