1015 - 計算幾何之點與多邊形的關係 - Points Within(ZOJ1081)
阿新 • • 發佈:2018-11-10
分析
射線法
雖然這個射線法有很多需要特判的情況,但總的來說還是蠻好用的
判斷點與多邊形的關係,若使用射線法,就是說從這個點往右做一條與 x 軸平行的射線,看它與多邊形相交了幾次
若相交了偶數次,則不在多邊形內部(相當於從這個多邊形中穿過去,沒有留在裡面)
若相交了奇數次,則在多邊形內部
1.要特殊考慮一下這種情況
若剛好穿過一個點,照我們的方法,會被計算兩次(上面的邊一次,下面的邊一次),而這明顯不對
所以我們就要強制規定,經過一條邊的左端點(或右端點)才能被計算
2.如果這個點剛好落在多邊形的邊上,(由於這道題我們是把這種情況當做落在裡面)我們需要判斷一下
3.由於射線法是往一個方向延伸,所以當一條邊一條邊的加入,邊轉到這個點的左邊(或右邊)時,就不能納入計數了
在程式碼中實現就是這樣的:
int d1=a[i].y-b.y;int d2=a[j].y-b.y;
if((det>=0&&d1<0&&d2>=0)||(det<=0&&d1>=0&&d2<0)) cnt++;
d1記錄 i 這個頂點與 b 縱座標之差,d2記錄下一個 i+1 這個頂點與 b 的縱座標之差。
程式碼
#include<bits/stdc++.h> using namespace std; const double eps=1e-7; struct point{ int x,y; point (int _x=0.0,int _y=0.0):x(_x),y(_y){} friend inline point operator +(const point &a,const point &b){ return point(a.x+b.x,a.y+b.y); } friend inline point operator -(const point &a,const point &b){ return point(a.x-b.x,a.y-b.y); } friend inline point operator *(double k,const point &a){ return point(k*a.x,k*a.y); } friend inline int dot(const point &a,const point &b){ return (a.x*b.x+a.y*b.y); } friend inline int cross(const point &a,const point &b){ return (a.x*b.y-b.x*a.y); } friend inline double len(const point &a){ return sqrt(dot(a,a)); } friend inline double dis (const point &a,const point &b){ return len(a-b); }//向量常見的運算 }a[105],b; int n,m; bool check(){ int cnt=0; for(int i=1;i<=n;++i){ int j=i+1; if(j>n) j=1; int det=cross(a[i]-b,a[j]-b); if(det==0) if(dot(a[i]-b,a[j]-b)<=0) return 1; int d1=a[i].y-b.y;int d2=a[j].y-b.y; if((det>=0&&d1<0&&d2>=0)||(det<=0&&d1>=0&&d2<0)) cnt++; } return cnt&1; } int main(){ for(int tt=1;;tt++){ scanf("%d",&n); if(n==0) break; scanf("%d",&m); int i,j,k; for(i=1;i<=n;++i) scanf("%d%d",&a[i].x,&a[i].y); if(tt!=1) printf("\n"); printf("Problem %d:\n",tt); for(i=1;i<=m;++i){ scanf("%d%d",&b.x,&b.y); if(check()) printf("Within\n"); else printf("Outside\n"); } } return 0; }