1. 程式人生 > >PSLG,直線切割凸多邊形,和判斷圓與多邊形相交

PSLG,直線切割凸多邊形,和判斷圓與多邊形相交

分析:

除了圓盤之外,本題的輸入也是一個PSLG,因此可以按照前面敘述的演算法求出各個區域。但由於本題的特殊性,不難發現把線段改成直線後答案不變,因此每個塊都是凸多邊形,

可以用切割凸多邊形的方法求解:每讀入一條線段,都把它當做直線,切割所有塊。這樣,我們最終得到了若干凸多邊形,需要分別判斷是否與圓盤相交。

如何讓判斷多邊形是否和圓盤相交?,顯然,如果多邊形的邊和圓周規範相交,圓盤和多變性一定相交,但反過來卻不成立——圓盤和多邊形相交,多邊形的邊和圓周不一定規範相交。

(1)即使完全沒有公共點的時候,圓盤和多邊形也可以相交,原因是二者可以相互內含。因此,需要判斷多邊形是否有頂點在圓內,還需要判斷圓心是否在多邊形內。

(2)如果是非規範相交,需要分情況討論。在圖中,待判斷的線段(用粗線表示)完全在圓外;在圖中待判斷的線段則是完全在內部。判斷方法很簡單,只需判斷線段中點是否在圓內即可。

直接切割多邊形~    判斷多邊形和園盤是否有公共點(面積>0) 

1  內含的情況--只要多邊形poly[0] 在圓內、或者圓心在多邊形內

2  相交的情況-如果不是規範相交,那麼不是內含,卻有非零公共面積只有一種情況,就是兩個點都在圓上,只有判斷中點在圓上即可。

 每一個案例忘記輸出空行  並不提示Presentation Error ,wa每次pieces更新的時候,newpieces 需要清零

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cctype>
#include<string>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<vector>
using namespace std;
const double eps=1e-6;
int dcmp(double x)
{
    if(fabs(x)<eps) return 0;
    return x>0?1:-1;
    //return fabs(x) < eps ? 0 : (x > 0 ? 1 : -1);
}

struct point
{
  double x;
  double y;
  point(){}
  point(double x,double  y):x(x),y(y){}
  void in()
  {
      cin>>x>>y;
  }
  void out()
  {
      cout<<x<<' '<<y<<endl;
  }
  point operator + (const point &t) const
  {
      return point(x+t.x,y+t.y);
  }
  point operator - (const point &t) const
  {
      return point(x-t.x,y-t.y);
  }
  point operator * (const double &t) const
  {
      return point(x*t,y*t);
  }
  point operator / (const double &t) const
  {
      return point(x/t,y/t);
  }
  bool operator < (const point &t) const
  {
      return (dcmp(x-t.x)<0||(dcmp(x-t.x)==0&&dcmp(y-t.y)<0));
  }
  bool operator == (const point &t) const
  {
      return dcmp(x-t.x) ==0 &&dcmp(y-t.y)==0;
  }
};
double cross(point a,point b)
{
    return a.x*b.y-a.y*b.x;
}
double dot(point a,point b)
{
    return a.x*b.x+a.y*b.y;
}
double length(point a)
{
    return sqrt(dot(a,a));
}
point nomal(point t)
{
    double l=length(t);
    return  point(-t.y/l,t.x/l);
}
struct line
{
    point p;
    point v;
    double ang;
    line() {}
    line(point p,point v):p(p),v(v){
        ang=atan2(v.y,v.x);
    }
    bool operator < (const line &l) const
    {
        return ang<l.ang;
    }
    point ppoint(double t)
    {
        return point(p+v*t);
    }
};
struct Circle
{
    point c;
    double r;
    Circle(point c=point(0,0),double r=0):c(c),r(r) {}

    point ppoint(double a)
    {
        return point(c.x+r*cos(a),c.y+r*sin(a));
    }
};
int getLineCircleIntersection(line l,Circle C,double &t1,double &t2,vector<point> &sol)
{
    double a=l.v.x;
    double b=l.p.x-C.c.x;
    double c=l.v.y;
    double d=l.p.y-C.c.y;

    double e=a*a+c*c;
    double f=2*(a*b+c*d);
    double g=b*b+d*d-C.r*C.r;

    double  delta=f*f-4*e*g;

    if(dcmp(delta)<0) return 0;
    if(dcmp(delta)==0)
    {
        t1=t2=-f/(2*e);
        sol.push_back(l.ppoint(t1));
        return 1;
    }
    else
    {
        t1=(-f-sqrt(delta))/(2*e);
        t2=(-f+sqrt(delta))/(2*e);

        sol.push_back(l.ppoint(t1));
        sol.push_back(l.ppoint(t2));

        return 2;
    }
}
bool onleft(line l,point p)
{
    return cross(l.v,p-l.p)>0;
}
point getintersection(line a,line b)
{
    point u=a.p-b.p;
    double t=cross(b.v,u)/cross(a.v,b.v);
    return a.p+a.v*t;
}
bool sgementproperintersection(point a1,point a2,point b1,point b2)
{
    double c1=cross(a2-a1,b1-a1),c2=cross(a2-a1,b2-a1),
           c3=cross(b2-b1,a1-b1),c4=cross(b2-b1,a2-b1);
    return dcmp(c1)*dcmp(c2)<0&&dcmp(c3)*dcmp(c4)<0;
}
bool onsegment(point p,point a1,point a2)
{
    return dcmp(cross(a1-p,a2-p))==0&&dcmp(dot(a1-p,a2-p))<0;
}
typedef vector<point> Polygon;
double PolygonArea(Polygon poly)
{
    double area=0;
    int n=poly.size();
    for(int i=1;i<n-1;i++)
    {
        area+=cross(poly[i]-poly[0],poly[(i+1)%n]-poly[0]);
    }
    return area/2;
}

vector<Polygon> pieces,newpieces;

Polygon CutPolygon(Polygon poly,point a,point b)
{
    Polygon newPoly;
    int n=poly.size();

    for(int i=0;i<n;i++)
    {
        point c=poly[i];
        point d=poly[(i+1)%n];
        if(dcmp(cross(b-a,c-a))>=0) newPoly.push_back(c);
        if(dcmp(cross(b-a,d-c))!=0)
        {
            point ip=getintersection(line(c,d-c),line(a,b-a));
            if(onsegment(ip,c,d)) newPoly.push_back(ip); //此時必須用不含端點的“線上段上"
        }
    }

    return newPoly;
}

void cut(point a,point b)
{
    newpieces.clear();  //僅僅是一個temp 記得清空
    for(int i=0;i<pieces.size();i++)
    {
        Polygon poly=pieces[i];

        Polygon left=CutPolygon(poly,a,b);
        Polygon right=CutPolygon(poly,b,a);
        if(left.size()>=3) newpieces.push_back(left);
        if(right.size()>=3) newpieces.push_back(right);
    }

    pieces=newpieces;
}

bool isPointInPolygon(point p,Polygon poly)
{
    int wn=0;
    int n=poly.size();
    for(int i=0;i<n;i++)
    {
        if(onsegment(p,poly[i],poly[(i+1)%n])) return -1;
        int  k=dcmp(cross(poly[(i+1)%n]-poly[i],p-poly[i]));
        int  d1=dcmp(poly[i].y-p.y);
        int  d2=dcmp(poly[(i+1)%n].y-p.y);

        if(k>0&&d1<=0&&d2>0) wn++;
        if(k<0&&d2<=0&&d1>0) wn--;
    }

    if(wn!=0) return 1;
    else return 0;
}
double length2(point a)
{
    return dot(a,a);
}
bool inCircle(Circle  C,point p) //圓周不算
{
    if(dcmp(length2(p-C.c)-C.r*C.r)<0) return 1;
    else return 0;
}
bool CircleSegIntersection(Circle C,point a,point b) //線段端點不算
{
    double t1,t2;
    vector<point> sol;
    if(getLineCircleIntersection(line(a,b-a),C,t1,t2,sol)<=1) return 0;
    if(dcmp(t1)>0&&dcmp(t1-1)<0) return 1;
    if(dcmp(t2)>0&&dcmp(t2-1)<0) return 1;

    return 0;
}
bool CirclePolyIntersection(Circle C,Polygon poly)
{
    if(isPointInPolygon(C.c,poly)) return 1;
    if(inCircle(C,poly[0]))  return 1;

    point a,b;
    int n=poly.size();
    for(int i=0;i<n;i++)
    {
        a=poly[i];
        b=poly[(i+1)%n];
        if(CircleSegIntersection(C,a,b)) return 1;
        if(inCircle(C,(a+b)/2)) return 1;
    }
    return 0;
}
void Query(Circle circle)
{
    vector<double> ans;
    for(int i=0;i<pieces.size();i++)
        if(CirclePolyIntersection(circle,pieces[i]))
    {
        ans.push_back(fabs(PolygonArea(pieces[i])));
    }
    sort(ans.begin(),ans.end());

    cout<<ans.size();
    for(int i=0;i<ans.size();i++)
    {
        printf(" %.2f",ans[i]);
    }
    cout<<endl;
}

int main()
{
    int n,m,l,w;
    Circle C;
    while(cin>>n>>m>>l>>w)
    {
        if(!n) break;

        pieces.clear();

        Polygon bbox;
        bbox.push_back(point(0,0));
        bbox.push_back(point(l,0));
        bbox.push_back(point(l,w));
        bbox.push_back(point(0,w));

        pieces.push_back(bbox);

        point a,b;
        for(int i=0;i<n;i++)
        {
            a.in();
            b.in();
            cut(a,b);
        }
        for(int i=0;i<m;i++)
        {
            cin>>C.c.x>>C.c.y>>C.r;
            Query(C);
        }
        printf("\n");
    }
    return 0;
}