Chinaunix首页 | 论坛 | 博客
  • 博客访问: 336761
  • 博文数量: 79
  • 博客积分: 2466
  • 博客等级: 大尉
  • 技术积分: 880
  • 用 户 组: 普通用户
  • 注册时间: 2006-02-07 16:47
文章分类

全部博文(79)

文章存档

2014年(3)

2012年(7)

2011年(14)

2010年(2)

2009年(2)

2008年(2)

2007年(18)

2006年(31)

分类: C/C++

2012-01-24 16:28:29

列举多边形的顶点的时候,规则是一定要按照反时针顺序依次列举,也就是说,如果一个人沿着多边形的边界前进,依次访问多边形的各个定点,多边形的“内部”始终是在这个人的左边。

----------------------------

如果abc(注意顺序)是一个三角形的三个顶点,令向量A=b-a,B=c-a,三角形的面积数值上是向量AB叉积的一半。即
2A(T) = (b0-a0)(c1-a1) - (c0-a0)(b1-a1)
定义
#define    X 0
#define    Y 1
#define    DIM 2               /* Dimension of points */
typedef    int tPointi[DIM];   /* Type integer point */
则计算三角形面积的代码可以写成
int     Area2( tPointi a, tPointi b, tPointi c ) {
   return (b[X] - a[X]) * (c[Y] - a[Y]) -
          (c[X] - a[X]) * (b[Y] - a[Y]);
}

----------------------------

平面上有任意简单多边形(不相邻的两个边没有交点),它的顶点是v0,v1,v2...vn。在平面上任取一点p,多边形的面积可以通过计算n个三角形的面积再求和得出:
A=A(p,v0,v1)+A(p,v1,v2)+A(p,v2,v3)+...+A(p,v[n-2],v[n-1])+A(p,v[n-1],v0)
定义
typedef    struct tVertexStructure tsVertex;    /* Used only in NEW(). */
typedef    tsVertex *tVertex;
struct    tVertexStructure {
   int        vnum;        /* Index */
   tPointi    v;        /* Coordinates */
   bool     ear;        /* TRUE iff an ear */
   tVertex     next,prev;
};
tVertex    vertices  = NULL;    /* "Head" of circular list. */
int    nvertices = 0;        /* Total number of polygon vertices. */
规定:存储一个多边形各顶点的数据结构是一个双向循环链表。
求多边形面积的的代码是:
int    AreaPoly2( void ) {
   int     sum = 0;
   tVertex p, a;

   p = vertices;   /* Fixed. */
   a = p->next;    /* Moving. */
   do {
      sum += Area2( p->v, a->v, a->next->v );
      a = a->next;
   } while ( a->next != vertices );
   return sum;
}

------------------------------

注意到有向线段ab可以确定一条直线,如果点c在直线ab左侧,那么三角形abc的面积就是正值(因为此时abc是按反时针顺序排列的),如果c在直线ab上,三角形abc的面积就是0,如果c在直线ab右边,三角形abc的面积就是负值(此时abc是按顺时针顺序出现的)。
定义
int     AreaSign( tPointi a, tPointi b, tPointi c )
{
    double area2;

    area2 = ( b[0] - a[0] ) * (double)( c[1] - a[1] ) -
            ( c[0] - a[0] ) * (double)( b[1] - a[1] );

    /* The area should be an integer. */
    if      ( area2 >  0.5 ) return  1;
    else if ( area2 < -0.5 ) return -1;
    else                     return  0;
}
(这个函数为什么这样定义,以后会说到。)
由此得到判断一个点c是否在一个直线ab左侧的方法:
bool    Left( tPointi a, tPointi b, tPointi c ) {
   return  AreaSign( a, b, c ) > 0;
}
判断一个点c是否在直线ab左侧或其上:
bool    LeftOn( tPointi a, tPointi b, tPointi c ) {
   return  AreaSign( a, b, c ) >= 0;
}
判断点abc是否共线:
bool    Collinear( tPointi a, tPointi b, tPointi c ) {
   return  AreaSign( a, b, c ) == 0;
}

------------------------------

判断线段相交时,如果用斜截式联立方程组求根的方式,一者斜截式有斜率90度、两直线平行等特殊情况;二者方程组的解很可能不是整数,出现浮点计算误差影响结果。因此换用别的方式。
如果两条线段ab和cd内相交,那么cd就被ab所确定的直线切割为两部分。所以对直线ab来说,点c和d一个在左,一个在右。类似地,对直线cd来说,点a和b也是一个在左,一个在右。如果这两个条件都满足,就可以判定两条线段相交。即:
bool    IntersectProp( tPointi a, tPointi b, tPointi c, tPointi d )
{
   if (Collinear(a,b,c) || Collinear(a,b,d) ||
       Collinear(c,d,a) || Collinear(c,d,b))
      return FALSE;

   return Xor( Left(a,b,c), Left(a,b,d) )
      && Xor( Left(c,d,a), Left(c,d,b) );
}
这里Xor要单独写成一个函数,是因为纯C不支持bool类型,C++完全可以定义成bool类型然后直接用^操作符,这个细节就不展示了,它和计算几何本身无关。
阅读(654) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~