荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: kaman (Devil Aspire), 信区: ACMICPC
标  题: Computing Geometry Std Algorithms
发信站: 荔园晨风BBS站 (Tue May  9 10:53:53 2006), 站内

/*********************************************\
*                                             *
*         计算几何学库函数                      *
*                                             *
*                   copyright starfish        *
*                           2000/10/24        *
*                                             *
\*********************************************/

#include <stdlib.h>

#define infinity 1e20
#define EP 1e-10

struct TPoint{
*float x,y;
*};

struct TLineSeg{
*TPoint a,b;
*};

//求平面上两点之间的距离
float max(float x,float y)
{
*if(x>y)return x;else return y;
}
float min(float x,float y)
{
*if(x<y)return x;else return y;
}
float distance(TPoint p1,TPoint p2)
{
*return(sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y)));*
}


/********************************************************

 返回(P1-P0)*(P2-P0)的叉积。
 若结果为正,则<P0,P1>在<P0,P2>的顺时针方向;
 若为0则<P0,P1><P0,P2>共线;
 若为负则<P0,P1>在<P0,P2>的在逆时针方向;
 可以根据这个函数确定两条线段在交点处的转向,
 比如确定p0p1和p1p2在p1处是左转还是右转,只要求
 (p2-p0)*(p1-p0),若<0则左转,>0则右转,=0则共线

*********************************************************/

float multiply(TPoint p1,TPoint p2,TPoint p0)
{
*return((p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y));*
}



//确定两条线段是否相交
int intersect(TLineSeg u,TLineSeg v)
{
*return( (max(u.a.x,u.b.x)>=min(v.a.x,v.b.x))&&
*        (max(v.a.x,v.b.x)>=min(u.a.x,u.b.x))&&
*        (max(u.a.y,u.b.y)>=min(v.a.y,v.b.y))&&
*        (max(v.a.y,v.b.y)>=min(u.a.y,u.b.y))&&
*        (multiply(v.a,u.b,u.a)*multiply(u.b,v.b,u.a)>=0)&&
*        (multiply(u.a,v.b,v.a)*multiply(v.b,u.b,v.a)>=0));
}

//判断点p是否在线段l上
int online(TLineSeg l,TPoint p)
{
*return( (multiply(l.b,p,l.a)==0)&&( ((p.x-l.a.x)*(p.x-l.b.x)<0 )||( (p.y
-l.a.
y)*(p.y-l.b.y)<0 )) );
}


//判断两个点是否相等
int Euqal_Point(TPoint p1,TPoint p2)
{
return((abs(p1.x-p2.x)<EP)&&(abs(p1.y-p2.y)<EP));
}

//一种线段相交判断函数,当且仅当u,v相交并且交点不是u,v的端点时函数为true;
int intersect_A(TLineSeg u,TLineSeg v)
{
*return((intersect(u,v))&&
*       (!Euqal_Point(u.a,v.a))&&
*       (!Euqal_Point(u.a,v.b))&&
*       (!Euqal_Point(u.b,v.a))&&
*       (!Euqal_Point(u.b,v.b)));
}


/*===============================================

   判断点q是否在多边形Polygon内,
   其中多边形是任意的凸或凹多边形,
   Polygon中存放多边形的逆时针顶点序列

================================================*/

int InsidePolygon(int vcount,TPoint Polygon[],TPoint q)
{
*int c=0,i,n;
*TLineSeg l1,l2;
**
*l1.a=q;
*l1.b=q;
*l1.b.x=infinity;
*n=vcount;
*for (i=0;i<vcount;i++)
*{
**l2.a=Polygon[i];
**l2.b=Polygon[(i+1)%n];
**if (  (intersect_A(l1,l2))||
**      (
**        (online(l1,Polygon[(i+1)%n]))&&
**        (
**         (!online(l1,Polygon[(i+2)%n]))&&
**         (multiply(Polygon[i],Polygon[(i+1)%n],l1.a)*multiply(Po
lygon[(i+1)%
n],Polygon[(i+2)%n],l1.a)>0)
**         ||
**         (online(l1,Polygon[(i+2)%n]))&&
**         (multiply(Polygon[i],Polygon[(i+2)%n],l1.a)*multiply(Po
lygon[(i+2)%
n],Polygon[(i+3)%n],l1.a)>0)**
**        )
**      )
**   ) c++;
**}
**return(c%2!=0);
}


/********************************************\
*                                            *
*      计算多边形的面积                        *
*                                            *
*     要求按照逆时针方向输入多边形顶点           *
*     可以是凸多边形或凹多边形                  *
*                                            *
\********************************************/

float area_of_polygon(int vcount,float x[],float y[])
{
  int i;
  float s;
  if (vcount<3) return 0;
  s=y[0]*(x[vcount-1]-x[1]);
  for (i=1;i<vcount;i++)
     s+=y[i]*(x[(i-1)]-x[(i+1)%vcount]);
  return s/2;
  }


/*============================================================================
========
   寻找凸包 graham 扫描法

  PointSet为输入的点集;
  ch为输出的凸包上的点集,按照逆时针方向排列;
  n为PointSet中的点的数目
  len为输出的凸包上的点的个数;

*   设下一个扫描的点PointSet[i]=P2,当前栈顶的两个点ch[top]=P1,ch[top-1]=P
0,
     如果P1P2相对于P0P1在点P1向左旋转(共线也不行),则P0,P1一定是凸包上的点;

     否则P1一定不是凸包上的点,应该将其出栈。
     比如下面左图中点1就一定是凸包上的点,右图中点1就一定不是凸包上的点,因为

     可以连接点0,2构成凸包的边
           2
           |
           |                 _____2
           1               1
          /               /
    ____0/          ____0/

==============================================================================
======*/

void Graham_scan(TPoint PointSet[],TPoint ch[],int n,int &len)
{
*int i,j,k=0,top=2;
*TPoint tmp;
*
*//选取PointSet中y坐标最小的点PointSet[k],如果这样的点右多个,则取最左边
的一个

*for(i=1;i<n;i++)
**if ((PointSet[i].y<PointSet[k].y)||((PointSet[i].y==PointSet[k].
y)&&(PointSe
t[i].x<PointSet[k].x)))
*    k=i;
*tmp=PointSet[0];
*PointSet[0]=PointSet[k];
*PointSet[k]=tmp; //现在PointSet中y坐标最小的点在PointSet[0]
*for (i=1;i<n-1;i++) //对顶点按照相对PointSet[0]的极角从小到大进行排序,
极角相
同的按照距离PointSet[0]从近到远进行排序
**{*k=i;
***for (j=i+1;j<n;j++)
****if ( (multiply(PointSet[j],PointSet[k],PointSet[
0])>0)
****     ||
****     ( (multiply(PointSet[j],PointSet[k],PointSe
t[0])==0)
****      &&(distance(PointSet[0],PointSet[j])<dista
nce(PointSet[0],PointSet[k
])) )
****   ) k=j;
***tmp=PointSet[i];
***PointSet[i]=PointSet[k];
***PointSet[k]=tmp;
**}
*ch[0]=PointSet[0];
*ch[1]=PointSet[1];
*ch[2]=PointSet[2];*
*for (i=3;i<n;i++)
**{
***while (multiply(PointSet[i],ch[top],ch[top-1])>=0) top--
;
***ch[++top]=PointSet[i];
***}
*len=top+1;
}

--
                              睡个好觉
                              吃餐好饭
                              发个好梦
                              做个好人
          我需要看见世界的尽头!----kaman  用汗水承载着希望……
※ 来源:·荔园晨风BBS站 bbs.szu.edu.cn·*[[From:210.39.3.50]hhhhhhhhhhhhhhhhhhhh


※ 来源:·荔园晨风BBS站 bbs.szu.edu.cn·[FROM: 192.168.20.225]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店