计算几何

设一在在 2D 空间中的三角形 △ABC ,三个顶点向量 A(ax, ay)、B(bx, by)、C(cx, cy),三条有向边 AB、BC、CA,有一点 P(px, py)。


矢量运算:

   在计算几何问题中,经常要用到矢量的运算。设二维矢量 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 ) 。

矢量点乘(dot product) 也叫做向量内积(inner product). 设三维空间中两个向量,P(a1,a2,a3) , Q(b1,b2,b3), P·Q = a1b1 + a2b2 + a3b3. 几何意义是|P||Q| cos(PQ夹角)。
     两向量点乘为0时,即这两向量互相垂直

矢量叉积(cross product)  设矢量 P = ( x1, y1 ) , Q = ( x2, y2 ) ,则矢量叉积定义为由 (0,0) 、 p1 、 p2 和 p1+p2 所组成的平行四边形的带符号的面积,即: P × Q = x1*y2 - x2*y1 ,其结果是一个标量(更高维数的叉积参阅数学书),几何意义为|P||Q| sin(PQ夹角)。显然有性质 P × Q = - ( Q × P ) 和 P × ( - Q ) = - ( P × Q ) 。一般在不加说明的情况下,下述算法中所有的点都看作矢量,两点的加减法就是矢量相加减,而点的乘法则看作矢量叉积。

  叉积的一个非常重要性质是可以通过它的符号判断两矢量相互之间的顺逆时针关系:若P×Q > 0 , 则P在Q的顺时针方向。若小于0, 为逆时针。若等于0, 可能同向/反向。

判断点在线段上

    设点为 Q ,线段为 AB ,判断点 Q 在直线上的依据是∠QAB = 0180 ( Q - A ) × ( B - A ) = 0。再判断点是否在线段内,min(xA,xB) <= xQ <= max(xA,xB)min(yA,yB) <= yQ <= max(yA,yB)(考虑垂直和水平线段,所以要两个条件同时成立).

线段/直线交点
    设线段两点坐标 P1(x1,y1), P2(x2,y2).  此线段构成的直线方程可表示为 :
     Ax + By = C
    其中
A = y2-y1
B = x1-x2
C = A*x1+B*y1
因此两条线段可确定两条直线方程
A1x + B1y = C1
A2x + B2y = C2
则解直线方程即可求出直线交点
det = A1*B2 – A2*B1
if (det == 0)
线段平行  }
    else   //  求出交点坐标
      { x = B2*C1 – B1*C2 / det
         y = A1*C2 – A2*C1 / det
      }
     对于线段,只需判断交点坐标是否都在两线段中即可。

点到线段距离

    设点为C,线段ABCAB距离为三角形CAB的高,假设CAB或延长线上的投影为H。我们知道三角形面积有两种计算方法: (1) 1/2 AB*CH还可以1/2 AC*sinCAB = 1/2 |AC×AB| . 因此距离CH = |AC×AB| / |AB| 

点在线段的垂足

   接上一个话题,寻找H的坐标,线段AB确定直线PxQy = R, 则其垂线方程为-Qx+Py = T. C点坐标带入算出T的值得出方程,再求出直线交点即可。若想求C关于AB的轴对称点S,则 S = H – (C – H)

点到线段最近点

     C 到线段 AB 的最近点,首先应判断 C 是否在线段 AB 若是则最近点为 C 。再判断 C AB 的哪一侧。可用点乘判断夹角的方法。
If (AB · BC >= 0)   //  ABC  钝角
 {  B 侧,最近点为 B }
if (BA · AC >= 0 ) //  BAC 钝角
 {  A 侧,最近点为 A }
else   //H AB
 {  最近点为垂足 H ,按上面的方法求 H }
 

线段拐向问题

   设折线段ABC,求拐向。用叉乘可以判断方向,若AC×AB 大于0,则线段右拐,小于0左拐,等于0共线。

多边形面积

    给出一个点集序列,按顺序把各点连起来组合一个多边形, 求多边形面积。一个多边形可以分割成若干个三角形面积的和。上面求点到直线距离时提到三角形面积可以用向量叉乘计算。由于线段拐向改变使叉乘的正负号改变,而闭合图形的拐向改变次数必为偶数,因此该方法对于凹多边形同样适用(正负抵消,读者可自行证明)。
    假设多边形由点集Ai顺序连成,则多边形面积 S = | ∑(Ai+1-Ai)×(Ai+2-Ai+1) | / 2 . 即选取第一个点开始,按顺序把相邻向量叉乘(注意向量方向,后一个点减前一个点)再求和。
   for ( i from 0~N )
   { 
 vecP <-- A[i+1] – A[i]
         vecQ <-- A[i+2] – A[i+1]
       cross <-- vecP × vecQ
       area <-- area + cross
}
polygon picture

判断点在多边形内

    判断点P是否在顺序点集Ai确定的多边形内。过点P作一条足够长(远长于任一条边)的线段模拟过P点的射线,可随机产生一个足够大的数Q。 判断 PQ与多边形边相交的次数,若偶数则P在多边形外,奇数在多边形内(读者自己证明)。还要判断点P是否在边上。

    Q <-- random()*1000+1000
    for( i from 0~N)
    {
       vec = A[i+1] – A[i]
       if ( IsOnSegment(P, vec) == TRUE) //在线段上
         { return 边上 }
       if ( Intersect ( PQ, vec) == TRUE) //相交
         { cnt <-- cnt + 1 }
     } //结束循环
      if ( cnt 是偶数) { return 外面 }
      if (cnt 是奇数) { return 里面 }

凸包(convex hull)

   一个有序点集 Ai,  求出最小的凸多边形,把所有点都包含在内,这个多边形叫做凸包 (convex hull) 求凸包的方法很多,这里仅介绍一种。
     对于一个有三个或以上点的点集  Q   Graham  扫描法的过程如下:
  令  p0   Q   Y-X  坐标排序下最小的点    
    <p1,p2,...pm>  为对其余点按以  p0  为中心的极角逆时针排序所得的点集(如果有多个点有相同的极角,除了距  p0  最远的点外全部移除  
    p0  进栈  S 
    p1  进栈  S 
    p2  进栈  S 
    for i ← 3 to m 
      do while 
 S  的栈顶元素的下一个元素、  S  的栈顶元素以及  pi  构成的折线段不拐向左侧  
        
 S  弹栈  
       
 pi  进栈  S 
    return S;
  此过程执行后,栈  S  由底至顶的元素就是  Q  的凸包顶点按逆时针排列的点序列。需要注意的是,我们对点按极角逆时针排序时,并不需要真正求出极角,只需要求出任意两点的次序就可以了。而这个步骤可以用前述的矢量叉积性质实现。
 

另外一些论题

   1 正交区域查找 ( 数据库查询 ) 。数据库貌似与几何风马牛不相及。其实我们可以把数据库记录字段对应一个维度,每一条记录看作是 K 维空间中的一个点。假设数据表有两个字段,则构成 2D 空间,正交区间查询就是给定一个条件区间,查找符合条件的记录。其实质是按条件生成的正方形,求正方形内的点 ( 如果有 3D 空间,则是一个立方体 ).  其方法是构造一个查找树,具体见计算几何书籍。
2 。三角剖分。把区域剖分成三角形集,有着广泛应用。例如用于无线传感网络 (sensor network) 中的路由算法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值