//
|
// Created by Scheaven on 2020/5/31.
|
//
|
|
#include "geometry_util.h"
|
using namespace std;
|
|
|
SPoint::_Point() {}
|
SPoint::_Point(float x, float y)
|
{
|
this->x = x;
|
this->y = y;
|
}
|
|
float calDistance(SPoint A, SPoint B)
|
{
|
float x_d, y_d;
|
x_d = A.x - B.x;
|
y_d = A.y - B.y;
|
float len = sqrt(x_d * x_d + 4*y_d * y_d);
|
return len;
|
}
|
|
/*
|
如果从点P作水平向左的射线的话,假设P在多边形内部,那么这条射线与多边形的交点必为奇数,如果P在多边形外部,则交点个数必为偶数(0也在内)。所以,我们可以顺序(顺时针或逆时针)考虑多边形的每条边,求出交点的总个数。还有一些特殊情况要考虑。假如考虑边(P1,P2),
|
1) 如果射线正好穿过P1或者P2,那么这个交点会被算作2次,处理办法是如果P的从坐标与P1,P2中较小的纵坐标相同,则直接忽略这种情况
|
2) 如果射线水平,则射线要么与其无交点,要么有无数个,这种情况也直接忽略。
|
3) 如果射线竖直,而P的横坐标小于P1,P2的横坐标,则必然相交。
|
4) 再判断相交之前,先判断P是否在边(P1,P2)的上面,如果在,则直接得出结论:P再多边形内部。
|
* */
|
//bool Pt_in_Polygon(SPoint point, RegInfo* polygon)
|
//{
|
// int nCross = 0;
|
// for (int i = 0; i < polygon->count; ++i)
|
// {
|
// SPoint p1 = polygon[i];
|
// SPoint p2 = polygon[(i+1)%polygon->count];
|
//
|
// if ( p1.y == p2.y )
|
// continue;
|
// if ( p.y < min(p1.y, p2.y) )
|
// continue;
|
// if ( p.y >= max(p1.y, p2.y) )
|
// continue;
|
//
|
// // 求交点的x坐标(由直线两点式方程转化而来)
|
// float x = (float)(p.y - p1.y) * (float)(p2.x - p1.x) / (float)(p2.y - p1.y) + p1.x;
|
//
|
// // 只统计p1p2与p向右射线的交点
|
// if ( x > p.x )
|
// {
|
// nCross++;
|
// }
|
//
|
// }
|
//
|
// // 交点为偶数,点在多边形之外
|
// // 交点为奇数,点在多边形之内
|
// if ((nCross % 2) == 1)
|
// {
|
// return true; //在内部
|
// }
|
// else
|
// {
|
// return false; //在外部
|
// }
|
|
//}
|
|
|
/*
|
* 多边形部分,判断多边形重叠率的计算
|
*/
|
|
float computeArea(const SPoint * pt,int n ) {
|
float area0 = 0.f;
|
for (int i = 0 ; i < n ; i++ )
|
{
|
int j = (i+1)%n;
|
area0 += pt[i].x * pt[j].y;
|
area0 -= pt[i].y * pt[j].x;
|
}
|
return 0.5f * fabs(area0);
|
}
|
|
struct PointAngle{
|
SPoint p;
|
float angle;
|
};
|
|
float Polygon::area() const {
|
return computeArea(pt,n);
|
}
|
|
static inline int cross(const SPoint* a,const SPoint* b) {
|
return a->x * b->y - a->y * b->x;
|
}
|
|
static inline SPoint* vsub(const SPoint* a,const SPoint* b, SPoint* res) {
|
res->x = a->x - b->x;
|
res->y = a->y - b->y;
|
return res;
|
}
|
|
|
static int line_sect(const SPoint* x0,const SPoint* x1,const SPoint* y0,const SPoint* y1, SPoint* res) {
|
SPoint dx, dy, d;
|
vsub(x1, x0, &dx);
|
vsub(y1, y0, &dy);
|
vsub(x0, y0, &d);
|
float dyx = (float)cross(&dy, &dx);
|
if (!dyx) return 0;
|
dyx = cross(&d, &dx) / dyx;
|
if (dyx <= 0 || dyx >= 1) return 0;
|
res->x = int(y0->x + dyx * dy.x);
|
res->y = int(y0->y + dyx * dy.y);
|
return 1;
|
}
|
|
static int left_of(const SPoint* a,const SPoint* b,const SPoint* c) {
|
SPoint tmp1, tmp2;
|
int x;
|
vsub(b, a, &tmp1);
|
vsub(c, b, &tmp2);
|
x = cross(&tmp1, &tmp2);
|
return x < 0 ? -1 : x > 0;
|
}
|
|
static void poly_edge_clip(const Polygon* sub,const SPoint* x0,const SPoint* x1, int left, Polygon* res) {
|
int i, side0, side1;
|
SPoint tmp;
|
const SPoint* v0 = sub->pt+ sub->n - 1;
|
const SPoint* v1;
|
res->clear();
|
|
side0 = left_of(x0, x1, v0);
|
if (side0 != -left) res->add(*v0);
|
|
for (i = 0; i < sub->n; i++) {
|
v1 = sub->pt + i;
|
side1 = left_of(x0, x1, v1);
|
if (side0 + side1 == 0 && side0)
|
/* last point and current straddle the edge */
|
if (line_sect(x0, x1, v0, v1, &tmp))
|
res->add(tmp);
|
if (i == sub->n - 1) break;
|
if (side1 != -left) res->add(*v1);
|
v0 = v1;
|
side0 = side1;
|
}
|
}
|
|
static int poly_winding(const Polygon* p) {
|
return left_of(p->pt, p->pt + 1, p->pt + 2);
|
}
|
|
|
void intersectPolygonSHPC(const Polygon * sub, const Polygon* clip, Polygon* res)
|
{
|
int i;
|
Polygon P1,P2;
|
Polygon *p1 = &P1;
|
Polygon *p2 = &P2;
|
Polygon *tmp;
|
|
int dir = poly_winding(clip);
|
poly_edge_clip(sub, clip->pt + clip->n - 1, clip->pt, dir, p2);
|
for (i = 0; i < clip->n - 1; i++) {
|
tmp = p2; p2 = p1; p1 = tmp;
|
if(p1->n == 0) {
|
p2->n = 0;
|
break;
|
}
|
poly_edge_clip(p1, clip->pt + i, clip->pt + i + 1, dir, p2);
|
}
|
res->clear();
|
for (i = 0 ; i < p2->n ; i++) res->add(p2->pt[i]);
|
}
|
|
void intersectPolygonSHPC(const Polygon & sub,const Polygon& clip,Polygon& res) {
|
intersectPolygonSHPC(&sub, &clip, &res);
|
}
|
|
|