2007-06-23 19:00:05 +00:00
|
|
|
#include "geometry.h"
|
|
|
|
#include <math.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
|
|
|
|
2007-09-16 14:07:03 +00:00
|
|
|
void addVertex(VERTEX_LIST *list, const Vertex *v) {
|
2007-06-23 19:00:05 +00:00
|
|
|
list->nVertices++;
|
2007-09-16 14:07:03 +00:00
|
|
|
list->vertices = (Vertex*)realloc(list->vertices, list->nVertices*sizeof(Vertex));
|
2007-06-23 19:00:05 +00:00
|
|
|
list->vertices[list->nVertices-1] = *v;
|
|
|
|
}
|
|
|
|
|
2007-09-16 14:07:03 +00:00
|
|
|
void insertVertex(VERTEX_LIST *list, const Vertex *v, unsigned int n) {
|
2007-06-23 19:00:05 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
if(n > list->nVertices)
|
|
|
|
n = list->nVertices;
|
|
|
|
|
|
|
|
list->nVertices++;
|
2007-09-16 14:07:03 +00:00
|
|
|
list->vertices = (Vertex*)realloc(list->vertices, list->nVertices*sizeof(Vertex));
|
2007-06-23 19:00:05 +00:00
|
|
|
|
|
|
|
for(i = list->nVertices-1; i > n; i--)
|
|
|
|
list->vertices[i] = list->vertices[i-1];
|
|
|
|
|
|
|
|
list->vertices[n] = *v;
|
|
|
|
}
|
|
|
|
|
|
|
|
void deleteVertex(VERTEX_LIST *list, unsigned int n) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
list->nVertices--;
|
|
|
|
|
|
|
|
for(i = n; i < list->nVertices; i++)
|
|
|
|
list->vertices[i] = list->vertices[i+1];
|
|
|
|
|
2007-09-16 14:07:03 +00:00
|
|
|
list->vertices = (Vertex*)realloc(list->vertices, list->nVertices*sizeof(Vertex));
|
2007-06-23 19:00:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-09-16 14:07:03 +00:00
|
|
|
int vertexOnLine(const Vertex *v, const LINE *l) {
|
|
|
|
if(l->v1.getX() == l->v2.getX() && l->v1.getY() == l->v2.getY()) {
|
|
|
|
if(l->v1.getX() == v->getX() && l->v1.getY() == v->getY()) return 1;
|
2007-09-15 17:54:02 +00:00
|
|
|
else return 0;
|
|
|
|
}
|
|
|
|
|
2007-09-16 14:07:03 +00:00
|
|
|
if(l->v1.getX() == l->v2.getX()) {
|
|
|
|
if(l->v1.getX() != v->getX()) return 0;
|
|
|
|
else if(v->getY() >= MIN(l->v1.getY(), l->v2.getY()) && v->getY() <= MAX(l->v1.getY(), l->v2.getY())) return 1;
|
2007-09-15 17:54:02 +00:00
|
|
|
else return 1;
|
|
|
|
}
|
|
|
|
|
2007-09-16 14:07:03 +00:00
|
|
|
if(l->v1.getY() == l->v2.getY()) {
|
|
|
|
if(l->v1.getY() != v->getY()) return 0;
|
|
|
|
else if(v->getX() >= MIN(l->v1.getX(), l->v2.getX()) && v->getX() <= MAX(l->v1.getX(), l->v2.getX())) return 1;
|
2007-09-15 17:54:02 +00:00
|
|
|
else return 1;
|
|
|
|
}
|
2007-09-16 14:07:03 +00:00
|
|
|
if((v->getX()-l->v1.getX())/(l->v2.getX()-l->v1.getX()) - (v->getY()-l->v1.getY())/(l->v2.getY()-l->v1.getY()) == 0) return 1;
|
2007-09-15 17:54:02 +00:00
|
|
|
else return 0;
|
|
|
|
}
|
|
|
|
|
2007-09-16 14:07:03 +00:00
|
|
|
int vertexInRect(const Vertex *v, const RECTANGLE *rect) {
|
2007-06-23 19:00:05 +00:00
|
|
|
int ret = EDGE_NONE;
|
|
|
|
|
2007-09-16 14:07:03 +00:00
|
|
|
if(v->getX() < rect->x) ret |= EDGE_LEFT;
|
|
|
|
else if(v->getX() >= rect->x+rect->width) ret |= EDGE_RIGHT;
|
2007-06-23 19:00:05 +00:00
|
|
|
|
2007-09-16 14:07:03 +00:00
|
|
|
if(v->getY() < rect->y) ret |= EDGE_TOP;
|
|
|
|
else if(v->getY() >= rect->y+rect->height) ret |= EDGE_BOTTOM;
|
2007-06-23 19:00:05 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2007-09-16 14:07:03 +00:00
|
|
|
static int quadrant(Vertex *v) {
|
|
|
|
if(v->getX() > 0 && v->getY() >= 0) return 1;
|
|
|
|
if(v->getX() >= 0 && v->getY() < 0) return 2;
|
|
|
|
if(v->getX() < 0 && v->getY() <= 0) return 3;
|
|
|
|
if(v->getX() <= 0 && v->getY() > 0) return 4;
|
2007-06-25 16:55:01 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-09-16 14:07:03 +00:00
|
|
|
gboolean vertexInPolygon(const Vertex *v, const POLYGON *p) {
|
2007-06-25 16:55:01 +00:00
|
|
|
int d = 0, i, li;
|
|
|
|
int q, ql, q2;
|
2007-09-16 14:07:03 +00:00
|
|
|
LINE d1 = {Vertex(-1, -1), Vertex(1, 1)};
|
|
|
|
LINE d2 = {Vertex(-1, 1), Vertex(1, -1)};
|
2007-06-25 16:55:01 +00:00
|
|
|
LINE l;
|
2007-09-16 14:07:03 +00:00
|
|
|
Vertex v2;
|
2007-06-25 16:55:01 +00:00
|
|
|
|
|
|
|
|
|
|
|
if(p->nVertices == 0) return FALSE;
|
|
|
|
|
2007-09-16 14:07:03 +00:00
|
|
|
v2 = p->vertices[p->nVertices-1] - *v;
|
2007-06-25 16:55:01 +00:00
|
|
|
q = quadrant(&v2);
|
|
|
|
|
|
|
|
if(q == 0) return TRUE;
|
|
|
|
|
|
|
|
for(i = 0; i < p->nVertices; i++) {
|
|
|
|
ql = q;
|
|
|
|
|
2007-09-16 14:07:03 +00:00
|
|
|
|
|
|
|
v2 = p->vertices[i] - *v;
|
2007-06-25 16:55:01 +00:00
|
|
|
|
|
|
|
if(q == 0) return TRUE;
|
|
|
|
|
|
|
|
switch(q-ql) {
|
|
|
|
case 0:
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
case -3:
|
|
|
|
d++;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
case -1:
|
|
|
|
d--;
|
|
|
|
break;
|
|
|
|
default:
|
2007-09-16 14:07:03 +00:00
|
|
|
l.v1 = p->vertices[(i>0)?i-1:p->nVertices-1] - *v;
|
2007-06-25 16:55:01 +00:00
|
|
|
l.v2 = v2;
|
|
|
|
|
|
|
|
if(q == 1 || q == 3) {
|
|
|
|
if(!(lineIntersection(&l, &d2, &v2) & INTERSECTION_LINE)) return FALSE;
|
|
|
|
|
|
|
|
q2 = quadrant(&v2);
|
|
|
|
if(q2 == 0) return TRUE;
|
|
|
|
|
|
|
|
if((q == 1 && q2 == 2) || (q == 3 && q2 == 4)) d -= 2;
|
|
|
|
else d += 2;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if(!(lineIntersection(&l, &d1, &v2) & INTERSECTION_LINE)) return FALSE;
|
|
|
|
|
|
|
|
q2 = quadrant(&v2);
|
|
|
|
if(q2 == 0) return TRUE;
|
|
|
|
|
|
|
|
if((q == 2 && q2 == 3) || (q == 4 && q2 == 1)) d -= 2;
|
|
|
|
else d += 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (d == 0) ? FALSE : TRUE;
|
|
|
|
}
|
|
|
|
|
2007-08-29 19:54:05 +00:00
|
|
|
double polygonPerimeter(const POLYGON *p) {
|
|
|
|
int i;
|
|
|
|
double d = 0.0;
|
|
|
|
|
|
|
|
for(i = 0; i < p->nVertices; i++)
|
2007-09-16 14:07:03 +00:00
|
|
|
d += p->vertices[i].distance(p->vertices[(i+1)%p->nVertices]);
|
2007-08-29 19:54:05 +00:00
|
|
|
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
|
|
|
double polygonArea(const POLYGON *p) {
|
|
|
|
int i;
|
|
|
|
double d = 0.0;
|
|
|
|
|
|
|
|
for(i = 0; i < p->nVertices; i++)
|
2007-09-16 14:07:03 +00:00
|
|
|
d += (p->vertices[(i+1)%p->nVertices].getX()+p->vertices[i].getX())*(p->vertices[(i+1)%p->nVertices].getY()-p->vertices[i].getY());
|
2007-08-29 19:54:05 +00:00
|
|
|
|
2007-09-15 17:54:02 +00:00
|
|
|
return fabs(d/2);
|
2007-08-29 19:54:05 +00:00
|
|
|
}
|
|
|
|
|
2007-09-16 14:07:03 +00:00
|
|
|
int lineIntersection(const LINE *la, const LINE *lb, Vertex *v) {
|
|
|
|
double xa1 = la->v1.getX(), ya1 = la->v1.getY();
|
|
|
|
double xa2 = la->v2.getX(), ya2 = la->v2.getY();
|
|
|
|
double xb1 = lb->v1.getX(), yb1 = lb->v1.getY();
|
|
|
|
double xb2 = lb->v2.getX(), yb2 = lb->v2.getY();
|
2007-06-23 19:00:05 +00:00
|
|
|
double temp;
|
|
|
|
int switched = 0;
|
2007-09-16 14:07:03 +00:00
|
|
|
Vertex v2;
|
2007-06-26 19:30:01 +00:00
|
|
|
|
2007-06-23 19:00:05 +00:00
|
|
|
|
2007-06-26 19:30:01 +00:00
|
|
|
if(v == NULL) v = &v2;
|
2007-06-23 19:00:05 +00:00
|
|
|
|
|
|
|
if(xa1 == xa2 && ya1 == ya2) return INTERSECTION_ERROR;
|
|
|
|
if(xb1 == xb2 && yb1 == yb2) return INTERSECTION_ERROR;
|
|
|
|
|
|
|
|
if(xa1 == xa2 || xb1 == xb2) {
|
|
|
|
temp = xa1; xa1 = ya1; ya1 = temp;
|
|
|
|
temp = xa2; xa2 = ya2; ya2 = temp;
|
|
|
|
temp = xb1; xb1 = yb1; yb1 = temp;
|
|
|
|
temp = xb2; xb2 = yb2; yb2 = temp;
|
|
|
|
|
|
|
|
switched = 1;
|
|
|
|
}
|
|
|
|
|
2007-09-15 17:54:02 +00:00
|
|
|
if(xa1 == xa2 && xb1 == xb2)
|
|
|
|
return (xa1 == xb1) ? INTERSECTION_IDENTICAL : INTERSECTION_NONE;
|
2007-06-23 19:00:05 +00:00
|
|
|
|
2007-09-15 17:54:02 +00:00
|
|
|
if(xa1 == xa2) {
|
2007-09-16 14:07:03 +00:00
|
|
|
v->setX(xa1);
|
|
|
|
v->setY(yb1);
|
2007-06-23 19:00:05 +00:00
|
|
|
}
|
2007-09-15 17:54:02 +00:00
|
|
|
else if(xb1 == xb2) {
|
2007-09-16 14:07:03 +00:00
|
|
|
v->setX(xb1);
|
|
|
|
v->setY(ya1);
|
2007-06-23 19:00:05 +00:00
|
|
|
}
|
|
|
|
else {
|
2007-09-15 17:54:02 +00:00
|
|
|
double ma = (ya2-ya1)/(xa2-xa1);
|
|
|
|
double mb = (yb2-yb1)/(xb2-xb1);
|
|
|
|
double ba = ya1 - ma*xa1;
|
|
|
|
double bb = yb1 - mb*xb1;
|
|
|
|
|
|
|
|
if(ma == mb) return (ba == bb) ? INTERSECTION_IDENTICAL : INTERSECTION_NONE;
|
|
|
|
|
2007-09-16 14:07:03 +00:00
|
|
|
v->setX((bb-ba)/(ma-mb));
|
|
|
|
v->setY(ma*v->getX() + ba);
|
2007-06-23 19:00:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(switched) {
|
2007-09-16 14:07:03 +00:00
|
|
|
temp = v->getX(); v->setX(v->getY()); v->setY(temp);
|
2007-06-23 19:00:05 +00:00
|
|
|
|
|
|
|
//switch back everything for segment tests
|
|
|
|
temp = xa1; xa1 = ya1; ya1 = temp;
|
|
|
|
temp = xa2; xa2 = ya2; ya2 = temp;
|
|
|
|
temp = xb1; xb1 = yb1; yb1 = temp;
|
|
|
|
temp = xb2; xb2 = yb2; yb2 = temp;
|
|
|
|
}
|
|
|
|
|
2007-09-16 14:07:03 +00:00
|
|
|
if(v->getX() < MIN(xa1,xa2) || v->getX() > MAX(xa1, xa2) || v->getY() < MIN(ya1,ya2) || v->getY() > MAX(ya1, ya2)) {
|
|
|
|
if(v->getX() < MIN(xb1,xb2) || v->getX() > MAX(xb1, xb2) || v->getY() < MIN(yb1,yb2) || v->getY() > MAX(yb1, yb2))
|
2007-06-23 19:00:05 +00:00
|
|
|
return INTERSECTION_LINE_LINE;
|
|
|
|
else
|
|
|
|
return INTERSECTION_LINE_SEGMENT;
|
|
|
|
}
|
2007-09-16 14:07:03 +00:00
|
|
|
else if(v->getX() < MIN(xb1,xb2) || v->getX() > MAX(xb1, xb2) || v->getY() < MIN(yb1,yb2) || v->getY() > MAX(yb1, yb2))
|
2007-06-23 19:00:05 +00:00
|
|
|
return INTERSECTION_SEGMENT_LINE;
|
|
|
|
else
|
|
|
|
return INTERSECTION_SEGMENT_SEGMENT;
|
|
|
|
}
|
|
|
|
|
2007-09-16 14:07:03 +00:00
|
|
|
int lineRectIntersection(const LINE *l, const RECTANGLE *rect, int edge, Vertex *v) {
|
2007-06-23 19:00:05 +00:00
|
|
|
const double minX = rect->x, maxX = rect->x+rect->width;
|
|
|
|
const double minY = rect->y, maxY = rect->y+rect->height;
|
2007-09-16 14:07:03 +00:00
|
|
|
const LINE top = {Vertex(minX, minY), Vertex(maxX, minY)};
|
|
|
|
const LINE bottom = {Vertex(minX, maxY), Vertex(maxX, maxY)};
|
|
|
|
const LINE left = {Vertex(minX, minY), Vertex(minX, maxY)};
|
|
|
|
const LINE right = {Vertex(maxX, minY), Vertex(maxX, maxY)};
|
2007-06-23 19:00:05 +00:00
|
|
|
|
|
|
|
if((edge & EDGE_TOP) && (lineIntersection(&top, l, v) == INTERSECTION_SEGMENT_SEGMENT))
|
|
|
|
return EDGE_TOP;
|
|
|
|
if((edge & EDGE_BOTTOM) && (lineIntersection(&bottom, l, v) == INTERSECTION_SEGMENT_SEGMENT))
|
|
|
|
return EDGE_BOTTOM;
|
|
|
|
if((edge & EDGE_LEFT) && (lineIntersection(&left, l, v) == INTERSECTION_SEGMENT_SEGMENT))
|
|
|
|
return EDGE_LEFT;
|
|
|
|
if((edge & EDGE_RIGHT) && (lineIntersection(&right, l, v) == INTERSECTION_SEGMENT_SEGMENT))
|
|
|
|
return EDGE_RIGHT;
|
|
|
|
|
2007-09-16 14:07:03 +00:00
|
|
|
v->setLocation(0, 0);
|
2007-06-23 19:00:05 +00:00
|
|
|
|
|
|
|
return EDGE_NONE;
|
|
|
|
}
|
|
|
|
|
2007-09-16 14:07:03 +00:00
|
|
|
int lineRectIntersections(const LINE *line, const RECTANGLE *rect, int edge, Vertex *v1, Vertex *v2) {
|
2007-06-23 19:00:05 +00:00
|
|
|
int ret = EDGE_NONE;
|
|
|
|
|
|
|
|
ret |= lineRectIntersection(line, rect, edge, v1);
|
|
|
|
ret |= lineRectIntersection(line, rect, EDGE_ALL^edge, v2);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2007-06-26 19:30:01 +00:00
|
|
|
gboolean linePolygonIntersection(const LINE *l, const POLYGON *p) {
|
|
|
|
int i;
|
|
|
|
LINE line;
|
|
|
|
|
|
|
|
for(i = 0; i < p->nVertices; i++) {
|
|
|
|
line.v1 = p->vertices[i];
|
|
|
|
line.v2 = p->vertices[(i+1)%p->nVertices];
|
|
|
|
|
|
|
|
if(lineIntersection(l, &line, NULL) == INTERSECTION_SEGMENT_SEGMENT)
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2007-09-16 00:50:01 +00:00
|
|
|
|
2007-09-16 14:07:03 +00:00
|
|
|
static void edgeVertex(Vertex *v, int edge, const RECTANGLE *rect) {
|
2007-09-16 00:50:01 +00:00
|
|
|
if(edge == EDGE_NONE)
|
|
|
|
edge = vertexInRect(v, rect);
|
2007-06-23 19:00:05 +00:00
|
|
|
|
2007-09-16 14:07:03 +00:00
|
|
|
if(edge & EDGE_LEFT) v->setX(rect->x);
|
|
|
|
else if(edge & EDGE_RIGHT) v->setX(rect->x+rect->width);
|
2007-06-23 19:00:05 +00:00
|
|
|
|
2007-09-16 14:07:03 +00:00
|
|
|
if(edge & EDGE_TOP) v->setY(rect->y);
|
|
|
|
else if(edge & EDGE_BOTTOM) v->setY(rect->y+rect->height);
|
2007-09-16 00:50:01 +00:00
|
|
|
}
|
|
|
|
|
2007-09-16 14:07:03 +00:00
|
|
|
static int simplifyVertex(Vertex *v, const Vertex *to, const RECTANGLE *rect) {
|
2007-09-16 00:50:01 +00:00
|
|
|
LINE l = {*v, *to};
|
|
|
|
int edge, edge2;
|
2007-06-23 19:00:05 +00:00
|
|
|
|
2007-09-16 00:50:01 +00:00
|
|
|
|
|
|
|
edge = vertexInRect(v, rect);
|
|
|
|
if(edge == EDGE_NONE) return EDGE_NONE;
|
|
|
|
|
|
|
|
edge2 = lineRectIntersection(&l, rect, edge, v);
|
|
|
|
if(edge2 != EDGE_NONE) return edge2;
|
|
|
|
|
|
|
|
edgeVertex(v, edge, rect);
|
|
|
|
return edge;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2007-09-16 14:07:03 +00:00
|
|
|
static void addSimplifiedLine(const Vertex *v1, const Vertex *v2, const RECTANGLE *rect, int last, POLYGON *out) {
|
|
|
|
const LINE d1 = {Vertex(rect->x, rect->y), Vertex(rect->x+rect->width, rect->y+rect->height)};
|
|
|
|
const LINE d2 = {Vertex(rect->x, rect->y+rect->height), Vertex(rect->x+rect->width, rect->y)};
|
2007-09-16 00:50:01 +00:00
|
|
|
|
|
|
|
LINE l = {*v1, *v2};
|
2007-09-16 14:07:03 +00:00
|
|
|
Vertex v, vi;
|
2007-09-16 00:50:01 +00:00
|
|
|
int edge1, edge2;
|
|
|
|
|
|
|
|
|
|
|
|
v = *v1;
|
|
|
|
if((edge1 = simplifyVertex(&v, v2, rect)) != EDGE_NONE)
|
|
|
|
addVertex(out, &v);
|
|
|
|
|
|
|
|
v = *v2;
|
|
|
|
edge2 = simplifyVertex(&v, v1, rect);
|
|
|
|
|
|
|
|
if(edge1 != EDGE_NONE && edge2 != EDGE_NONE && !(edge1 & edge2)) {
|
|
|
|
if(lineIntersection(&l, &d1, &vi) == INTERSECTION_SEGMENT_LINE) {
|
|
|
|
edgeVertex(&vi, 0, rect);
|
|
|
|
addVertex(out, &vi);
|
2007-06-23 19:00:05 +00:00
|
|
|
}
|
2007-09-16 00:50:01 +00:00
|
|
|
else if(lineIntersection(&l, &d2, &vi) == INTERSECTION_SEGMENT_LINE) {
|
|
|
|
edgeVertex(&vi, 0, rect);
|
|
|
|
addVertex(out, &vi);
|
2007-06-23 19:00:05 +00:00
|
|
|
}
|
|
|
|
}
|
2007-09-16 00:50:01 +00:00
|
|
|
|
|
|
|
if(!last)
|
|
|
|
addVertex(out, &v);
|
|
|
|
}
|
|
|
|
|
|
|
|
void simplifyPolygon(const POLYGON *in, const RECTANGLE *rect, POLYGON *out) {
|
2007-09-16 14:07:03 +00:00
|
|
|
Vertex v;
|
2007-09-16 00:50:01 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
if(in->nVertices == 0) return;
|
|
|
|
else if(in->nVertices == 1) {
|
|
|
|
addVertex(out, &in->vertices[0]);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
v = in->vertices[0];
|
|
|
|
simplifyVertex(&v, &in->vertices[in->nVertices-1], rect);
|
|
|
|
addVertex(out, &v);
|
|
|
|
|
|
|
|
for(i = 0; i < in->nVertices; i++) {
|
|
|
|
addSimplifiedLine(&in->vertices[i], &in->vertices[(i+1)%in->nVertices], rect, (i == in->nVertices-1), out);
|
|
|
|
}
|
2007-06-23 19:00:05 +00:00
|
|
|
}
|