//
|
// 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;
|
}
|
|
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);
|
}
|
|
|