计算几何_半平面交

来源:互联网 发布:农村淘宝召集令答案 编辑:程序博客网 时间:2024/06/05 18:19

计算几何_半平面交

题意:求是否存在一个平面,平面内的所有点能够旋转360度之后,能够扫到整个多边形,既可以是凹多边形,也可以是凸多边形~

接题报告:

求半交平面。

O(n^2)

用直线切割多边形,剩下的多边形就是半交平面。

 

POJ 1279:

竟然我拿 G++交了不过,拿C++能够过!!!

 

 

template:

#include "stdio.h"
#include "math.h"
#define N 1800
#define eps 1e-10
struct Point{
       double x;
       double y;
};
struct CC{
    int n;
    Point P[N];
};

double xmult(Point p0,Point p1,Point p2)    //叉积
{
      return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
}   

Point intersectL(double a1,double b1,double c1,double a2,double b2,double c2) //用两直线方程求两直线交点
{
      Point p;
      p.y=(a2*c1-a1*c2)/(b1*a2-b2*a1);
      if(fabs(a2)<eps)
         p.x=(p.y*b1-c1)/a1;
      else
         p.x=(p.y*b2-c2)/a2;
      return p;
}       

void Getline(Point p1,Point p2,double &a,double &b,double &c)   //求直线方程
{
      a=p2.y-p1.y;
      b=p2.x-p1.x;
      c=p1.y*(p2.x-p1.x)-p1.x*(p2.y-p1.y);
}

bool Isame(Point p1,Point p2)     //点的判重
{
      return fabs(p1.x-p2.x)<eps && fabs(p1.y-p2.y)<eps;
}

CC cut(Point A,Point B,CC rc)                       //直线AB顺时针方向切割多边形rc
{
    CC ret;
    double r1,r2,a1,b1,c1,a2,b2,c2;                                 
    ret.n=0;
    for(int i=0;i<rc.n;i++)                  
    {
         r1=xmult(A,B,rc.P[i]);
         r2=xmult(A,B,rc.P[i+1]);
         if(r1<eps&&r2<eps)                   //当该线段在AB的顺时针方向时,说明该线段的端点都是切割后多边形的顶点
         {                                    //这里要注意精度问题
            ret.P[ret.n++]=rc.P[i];
            ret.P[ret.n++]=rc.P[i+1];
         }
         else if(r1>eps&&r2>eps)              //当该线段在AB的逆时针方向时,舍去该线段,判断下一条线段
             continue;
         else
         {                                    //当该线段的端点在AB的两侧时要把顺时针方向上的端点及它们交点作为切割后的顶点
              Getline(A,B,a1,b1,c1);           
              Getline(rc.P[i],rc.P[i+1],a2,b2,c2);
              Point crospoint=intersectL(a1,b1,c1,a2,b2,c2);
              if(r1<eps)
              {
                  ret.P[ret.n++]=rc.P[i];
                  ret.P[ret.n++]=crospoint;
              }
              else
              {
                  ret.P[ret.n++]=crospoint;
                  ret.P[ret.n++]=rc.P[i+1];
              }
         }
    }
    if(ret.n==0)                        //区域为空集
      return ret;
    int j=1;
    for(int i=1;i<ret.n;i++)            //排除重复点
      if(!Isame(ret.P[i],ret.P[i-1]))
           ret.P[j++]=ret.P[i];
    ret.n=j;
    if(ret.n!=1&&Isame(ret.P[ret.n-1],ret.P[0]))
        ret.n--;
     ret.P[ret.n]=ret.P[0];                
     return ret;                   // 返回切割后的区域
}

int main()
{
     
      int test,v;
      CC cp,ret;
      scanf("%d",&test);
      while(test--)
      {
          scanf("%d",&v);
          for(int i=0;i<v;i++)
             scanf("%lf%lf",&cp.P[i].x,&cp.P[i].y);
          cp.P[v]=cp.P[0];
          cp.n=v;
          ret=cp;
          for(int i=0;i<cp.n;i++)
             ret=cut(cp.P[i],cp.P[i+1],ret);     //枚举每条边切割当前的区域
          double area=0.0;  
          for(int i=1;i<ret.n-1;i++)
              area+=xmult(ret.P[0],ret.P[i],ret.P[i+1]);     //叉积求面积
          printf("%.2lf/n",fabs(area)/2.0);    
      }
            return 0;
}