1.必須逆時針給出多邊形頂點
2.面積並 = 面積和 - 面積交
#include <bits/stdc++.h>
using namespace std;
const int maxn = 300;
const double eps = 1e-8;
int dcmp(double x){ //精度誤差比較
if(x > eps) return 1;
return x < -eps ? -1 : 0;
}
struct Point{double x, y;}; //點結構體
double cross(Point a,Point b,Point c){return (a.x-c.x)*(b.y-c.y)-(b.x-c.x)*(a.y-c.y);}//叉積
Point intersection(Point a,Point b,Point c,Point d){//傳入四點即兩直線,輸出交點
Point p = a;
double t =((a.x-c.x)*(c.y-d.y)-(a.y-c.y)*(c.x-d.x))/((a.x-b.x)*(c.y-d.y)-(a.y-b.y)*(c.x-d.x));
p.x +=(b.x-a.x)*t;
p.y +=(b.y-a.y)*t;
return p;//輸出交點,證明用數學方法易證
}
double PolygonArea(Point p[], int n){//計算多邊形面積,三角剖分
if(n < 3) return 0.0;
double s = p[0].y * (p[n - 1].x - p[1].x);
p[n] = p[0];
for(int i = 1; i < n; ++ i)
s += p[i].y * (p[i - 1].x - p[i + 1].x);
return fabs(s * 0.5);//叉乘出來是平行四邊形面積故/2,且順逆方向不定,故取ABS變正
}
double CPIA(Point a[], Point b[], int na, int nb){//傳入兩個三角形,求相交部分的凸包
Point p[20], tmp[20]; //複製點集與臨時點集(P其實可以用B來做
int tn, sflag, eflag; //每輪相交凸包的點,叉乘符號
a[na] = a[0], b[nb] = b[0]; //末點用初點複製方便首末點連邊
memcpy(p,b,sizeof(Point)*(nb + 1)); //把B複製到P
for(int i=0;i<na&&nb>2;i++){ //掃一次A
sflag=dcmp(cross(a[i+1],p[0],a[i])); //取A兩點與B第一點求叉乘符號
for(int j=tn=0;j<nb;j++,sflag=eflag){ //掃一次B,更新TMP,TN是點數
if(sflag>=0)tmp[tn++]=p[j]; //叉乘爲正就是B數組的那個點壓入
eflag=dcmp(cross(a[i+1],p[j+1],a[i]));//求叉乘符號
if((sflag^eflag)==-2) //1異或-1等於-2
tmp[tn++]=intersection(a[i],a[i+1],p[j],p[j+1]);//求交點
}
memcpy(p, tmp, sizeof(Point) * tn); //把TMP複製到P
nb = tn, p[nb] = p[0];//TN即TMP點數記到NB
}//其實該是NP表示P數組個數,這裏省了個變量就用NB表示,下面第二行做參數而已
if(nb < 3) return 0.0; //相交部分凸包不夠三個點,面積就是0
return PolygonArea(p, nb); //求出相交凸包部分的面積
}
double SPIA(Point a[], Point b[], int na, int nb){//傳入兩個多邊形的點
int i,j; //循環變量
Point t1[4],t2[4]; //其實T13與T23沒用上
double res=0,num1,num2; //答案初始化,及叉乘符號
a[na]=t1[0]=a[0],b[nb]=t2[0]=b[0]; //初始化T1,T2和ANA,BNB
for(i=2;i<na;i++){ //掃一次第一個多邊形全部點
t1[1]=a[i-1],t1[2]=a[i]; //每次在第一個多邊形取兩個點賦給T11,T12
num1=dcmp(cross(t1[1],t1[2],t1[0]));//求出叉乘符號
if(num1<0)swap(t1[1],t1[2]); //小於0則改變T11,T12可使叉乘符號變正,實即改變T1三個點的順逆
for(j=2;j<nb;j++){ //掃一次第二個多邊形全部點
t2[1]=b[j-1],t2[2]=b[j]; //然後再在第二個多邊形取兩個點賦給T21,T22
num2=dcmp(cross(t2[1],t2[2],t2[0]));//求出叉乘符號
if(num2<0)swap(t2[1],t2[2]);//小於0則改變T11,T12可使叉乘符號變正,實即改變T1三個點的順逆
res+=CPIA(t1,t2,3,3); //累加相交部分面積
}
}
return res;
}
Point p1[maxn], p2[maxn];//兩個數組存讀入點集
int main(){
int n1, n2; //定義
while(cin>>n1>>n2){ //輸入兩個多邊形的點數
for(int i=0;i<n1;i++)scanf("%lf%lf",&p1[i].x,&p1[i].y);//輸入點數
for(int i=0;i<n2;i++)scanf("%lf%lf",&p2[i].x,&p2[i].y);//輸入點數
cout<<SPIA(p1,p2,n1,n2)<<endl;//輸出面積交
}//如果要求面積並,則先用三角剖分分別求兩個多邊形的面積S1,S2,然後S1+S2-面積交即可
return 0;
}
/*
in
4 4
0 0 1 0 1 1 0 1
0.5 0.5 -1 0.5 -1 -1 0.5 -1
out
0.25
int
4 4
0 0 5 0 5 5 0 5
-1 -1 4 -1 4 4 -1 4
out
16
*/