区分这四种不同的情况:
第一个是合法的,第二个是非简单多边形,第三个是多重嵌套,第四个是相交。
点在多边形内和简单多边形的判定,是很基础的东西呢。
之前想用数据结构,但是没什么想法。
#include <algorithm>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <stdio.h>
#include <math.h>
using namespace std;
#define MAXN 60
#define eps 1e-18
#define INF 1000100
//const double pi = acos(-1.0);
inline double sig(double x) { return (x > eps) - (x < -eps); };
template <class T> inline T sqr(T a) { return a * a; }
struct Point
{
double x, y;
Point() {}
Point(double _x, double _y): x(_x), y(_y) {}
void in();
void out() const;
double len() const;
double len2() const;
double dis(const Point &argu) const;
double dis2(const Point &argu) const;
bool operator <(const Point &argu) const;
Point operator -(const Point &argu) const;
bool operator ==(const Point &argu) const;
bool operator !=(const Point &argu) const;
double operator ^(const Point &argu) const;
double operator *(const Point &argu) const;
};
struct Segment
{
Point s, e;
Segment() {}
Segment(Point _s, Point _e): s(_s), e(_e) {}
void in();
Point d() const;
void out() const;
double len() const;
double len2() const;
int sgn(const Segment &argu) const;
bool qrt(const Segment &argu) const;
double dis(const Point &argu) const;
double dis2(const Point &argu) const;
double dis(const Segment &argu) const;
double dis2(const Segment &argu) const;
double operator ^(const Segment &argu) const;
};
struct Line
{
Segment s;
Line() {}
Line(Segment _s): s(_s) {}
Line(Point _s, Point _e): s(Segment(_s, _e)) {}
double dis(const Line &argu) const;
double dis2(const Line &argu) const;
double dis(const Point &argu) const;
double dis2(const Point &argu) const;
double dis(const Segment &argu) const;
double dis2(const Segment &argu) const;
};
inline double Cross(const Point &o, const Point &a, const Point &b) { return (a - o) ^ (b - o); }
void Point::in() { scanf("%lf%lf", &x, &y); }
double Point::len() const { return sqrt(len2()); }
double Point::len2() const { return x * x + y * y; }
void Point::out() const{ printf("%.0lf %.0lf\n", x, y); }
double Point::dis(const Point &argu) const { return sqrt(dis2(argu)); }
bool Point::operator !=(const Point &argu) const { return !((*this) == argu); }
double Point::operator ^(const Point &argu) const { return x * argu.y - y * argu.x; }
double Point::operator *(const Point &argu) const { return x * argu.x + y * argu.y; }
bool Point::operator ==(const Point &argu) const { return x == argu.x && y == argu.y; }
Point Point::operator -(const Point &argu) const { return Point(x - argu.x, y - argu.y); }
bool Point::operator <(const Point &argu) const { return sig(x - argu.x) == 0 ? y < argu.y : x < argu.x; }
double Point::dis2(const Point &argu) const { return (x - argu.x) * (x - argu.x) + (y - argu.y) * (y - argu.y); }
void Segment::in() { s.in(), e.in(); }
Point Segment::d() const { return e - s; }
double Segment::len2() const { return d().len2(); }
double Segment::len() const { return sqrt(len2()); }
void Segment::out() const { s.out(), e.out(); }
double Segment::dis2(const Segment &argu) const
{
if(~sgn(argu)) return 0;
return min(min(dis2(argu.s), dis2(argu.e)), min(argu.dis2(s), argu.dis2(e)));
}
double Segment::dis2(const Point &argu) const
{
Point ps = argu - s, pe = argu - e;
if(sig(d() * ps) <= 0) return ps.len2();
if(sig(d() * pe) >= 0) return pe.len2();
Line l = Line((*this)); return l.dis2(argu);
}
int Segment::sgn(const Segment &argu) const
{
if(!qrt(argu)) return -1;
return sig(Cross(s, e, argu.s)) * sig(Cross(s, e, argu.e)) <= 0 &&
sig(Cross(argu.s, argu.e, s)) * sig(Cross(argu.s, argu.e, e)) <= 0 ? 1 : -1;
}
//快速排斥实验
bool Segment::qrt(const Segment &argu) const
{
return min(s.x, e.x) <= max(argu.s.x, argu.e.x) && min(s.y, e.y) <= max(argu.s.y, argu.e.y) &&
min(argu.s.x, argu.e.x) <= max(s.x, e.x) && min(argu.s.y, argu.e.y) <= max(s.y, e.y);
}
double Segment::dis(const Point &argu) const { return sqrt(dis2(argu)); }
double Segment::dis(const Segment &argu) const { return sqrt(dis2(argu)); }
double Line::dis(const Point &argu) const { return sqrt(dis2(argu)); }
double Line::dis2(const Point &argu) const { return sqr(fabs(s.d() ^ (argu - s.s))) / s.len2(); }
double Line::dis(const Segment &argu) const { return sqrt(dis2(argu)); }
double Line::dis2(const Segment &argu) const
{
Point v1 = argu.s - s.s, v2 = argu.e - s.e; double d1 = s.d() ^ v1, d2 = s.d() ^ v2;
return sig(d1) != sig(d2) ? 0 : sqr(min(fabs(d1), fabs(d2))) / s.len2();
}
bool issimple(int n, Point p[])
{
int cn;
Segment l1, l2;
for(int j, i = 0; i < n; i++)
{
l1 = Segment(p[i], p[i + 1]);
cn = n - 3, j = i;
while(cn)
{
l2 = Segment(p[(j + 2) % n], p[(j + 3) % n]);
if(~l1.sgn(l2)) break;
cn--, j++;
}
if(cn) return false;
}
return true;
}
bool intersect(const Segment &ss, int n, Point p[])
{
for(int i = 0; i < n; i++)
{
Segment s = Segment(p[i], p[i + 1]);
if(~ss.sgn(s)) return true;
}
return false;
}
int cal_pos(const Segment &ss, int n, Point p[])
{
int ret = 0;
for(int i = 0; i < n; i++)
{
Segment s = Segment(p[i], p[i + 1]);
if(sig(s.dis2(ss)) == 0)
{
ret++;
if((s.d() ^ ss.d()) == 0) ret++;
}
}
return ret;
}
void simplify(int &n, Point p[])
{
int cnt = 1;
for(int i = 2; i <= n; i++)
{
Segment s1 = Segment(p[cnt - 1], p[cnt]);
Segment s2 = Segment(p[cnt], p[i]);
if(cnt > 0 && sig(s1.d() ^ s2.d()) == 0) cnt--;
p[++cnt] = p[i];
}
n = cnt + 1;
p[n] = p[0];
}
Point pp[MAXN][MAXN];
int n[MAXN];
//INVALID POLYGON
//INTERSECTING POLYGONS
//INVALID NESTING
bool c1, c2, c3;
bool in[MAXN];
int main()
{
// freopen("I.in", "r", stdin);
int cas; scanf("%d", &cas);
while(cas--)
{
c1 = c2 = c3 = false;
int p; scanf("%d", &p);
for(int k = 0; k < p; k++)
{
scanf("%d", &n[k]); n[k]--;
for(int i = 0; i <= n[k]; i++) pp[k][i].in();
if(c1) continue;
if(pp[k][0] != pp[k][n[k]]) c1 = true;
if(!issimple(n[k], pp[k])) c1 = true;
}
if(c1) { puts("INVALID POLYGON"); continue; }
for(int k = 0; k < p; k++) simplify(n[k], pp[k]);
// for(int k = 0; k < p; k++)
// {
// for(int i = 0; i < n[k]; i++) pp[k][i].out();
// cout << endl;
// }
for(int k = 0; !c2 && k < p; k++)
{
for(int i = 0; !c2 && i < n[k]; i++)
{
Segment s = Segment(pp[k][i], pp[k][i + 1]);
for(int j = k + 1; !c2 && j < p; j++) if(intersect(s, n[j], pp[j])) c2 = true;
}
}
if(c2) { puts("INTERSECTING POLYGONS"); continue; }
memset(in, false, sizeof(in));
for(int k = 0; !c3 && k < p; k++)
{
for(int j = 0; !c3 && j < p; j++)
{
if(k == j) continue;
bool flag = true;
for(int i = 0; flag && i < n[k]; i++)
{
//判断pp[k][i]是否在多边形j内
Point _p = Point(INF, pp[k][i].y);
Segment s = Segment(pp[k][i], _p);
if(cal_pos(s, n[j], pp[j]) % 2 == 0) flag = false;
}
if(flag)
{
if(in[k]) c3 = true;
in[k] = true;
}
}
}
if(c3) { puts("INVALID NESTING"); continue; }
puts("CORRECT");
}
return 0;
}