#include "geometry.h" #include #include #include 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; else return 0; } 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; else return 1; } 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; else return 1; } 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; else return 0; } int vertexInRect(const Vertex *v, const RECTANGLE *rect) { int ret = EDGE_NONE; if(v->getX() < rect->x) ret |= EDGE_LEFT; else if(v->getX() >= rect->x+rect->width) ret |= EDGE_RIGHT; if(v->getY() < rect->y) ret |= EDGE_TOP; else if(v->getY() >= rect->y+rect->height) ret |= EDGE_BOTTOM; return ret; } int lineRectIntersection(const LINE *l, const RECTANGLE *rect, int edge, Vertex *v) { const double minX = rect->x, maxX = rect->x+rect->width; const double minY = rect->y, maxY = rect->y+rect->height; 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)}; 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; v->setLocation(0, 0); return EDGE_NONE; } int lineRectIntersections(const LINE *line, const RECTANGLE *rect, int edge, Vertex *v1, Vertex *v2) { int ret = EDGE_NONE; ret |= lineRectIntersection(line, rect, edge, v1); ret |= lineRectIntersection(line, rect, EDGE_ALL^edge, v2); return ret; } static void edgeVertex(Vertex *v, int edge, const RECTANGLE *rect) { if(edge == EDGE_NONE) edge = vertexInRect(v, rect); if(edge & EDGE_LEFT) v->setX(rect->x); else if(edge & EDGE_RIGHT) v->setX(rect->x+rect->width); if(edge & EDGE_TOP) v->setY(rect->y); else if(edge & EDGE_BOTTOM) v->setY(rect->y+rect->height); } static int simplifyVertex(Vertex *v, const Vertex *to, const RECTANGLE *rect) { LINE l = {*v, *to}; int edge, edge2; 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; } 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)}; LINE l = {*v1, *v2}; Vertex v, vi; int edge1, edge2; v = *v1; if((edge1 = simplifyVertex(&v, v2, rect)) != EDGE_NONE) out->push_back(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); out->push_back(vi); } else if(lineIntersection(&l, &d2, &vi) == INTERSECTION_SEGMENT_LINE) { edgeVertex(&vi, 0, rect); out->push_back(vi); } } if(!last) out->push_back(v); } void simplifyPolygon(const Polygon *in, const RECTANGLE *rect, Polygon *out) { Vertex v; if(in->empty()) return; else if(in->size() == 1) { out->push_back(in->front()); return; } v = in->front(); simplifyVertex(&v, &in->back(), rect); out->push_back(v); for(Polygon::const_iterator it = in->begin(); it != in->end(); it++) { Polygon::const_iterator it2 = it+1; if(it2 == in->end()) it2 = in->begin(); addSimplifiedLine(&*it, &*it2, rect, (it2 == in->begin()), out); } }