// ============================================================================ /// Splits polygon in two QList<QPolygonF> splitPolygonRandomly( const QPolygonF& polygon, QLineF* pdebugout ) { QRectF br = polygon.boundingRect(); // get random angle on cutting double angle = random01()* 6.28; // cut throught the center QPointF center = br.center(); double upper = br.width() + br.height(); // upper bound for any of the polygon's dimensions QPointF p1( center.x() - upper*sin(angle), center.y() - upper*cos(angle) ); QPointF p2( center.x() + upper*sin(angle), center.y() + upper*cos(angle) ); // debug if ( pdebugout ) *pdebugout = QLineF( p1, p2 ); return splitPolygon( polygon, QLineF( p1, p2 ) ); }
/*! * Note that this has complexity O(n^2) but should not count since * triangulation has O(n^3). * * \param globalverts the global vertices vector * \param polylist the global list of polygons * \return zero on success, and a negative integer if some error occured. */ int SimplePolygon::fixAndTriangulate( DCTPVec2dvector &globalverts, simplepolygonvector &polylist ) { Vec2d min, max; if( getMinMax( globalverts, min, max ) ) { // std::cerr << "Ignoring degenerate polygon..." << std::endl; return -1; } // while( removeLinearPoints( globalverts, min, max ) ) { } while( splitPolygon( globalverts, polylist, min, max ) ) { } while( intersectPolygon( globalverts, polylist ) ) { } if( isReversed( globalverts ) ) { // std::cerr << "Ignoring reversed polygon." << std::endl; return 0; // no error here... } // Ok, we have a valid polygon, so triangulate it. triangulate( globalverts, polylist ); return 0; }
void ConvexPolygon::booleanDifference(const ConvexPolygon &hole, std::vector<ConvexPolygon> &list) const { // Special case: this polygon is entirely swallowed by the hole if(hole.envelopes(*this)) return; // Special case: the hole is entirely inside this polygon if(envelopes(hole)) { Points p1, p2; splitPolygon(*this, hole, p1, p2); ConvexPolygon::make(p1, list); ConvexPolygon::make(p2, list); return; } // Common case: hole intersects with this polygon. std::vector<bool> visited(vertexCount()); std::queue<unsigned int> queue; queue.push(0); // Perform intersection unsigned int oldsize = list.size(); Points poly; while(!queue.empty()) { int i = queue.front(); while(i < vertexCount()) { // Stop if we've already been here if(visited[i]) break; visited[i] = true; // Include point if it is not inside the hole bool inhole = hole.hasPoint(vertex(i)); if(!inhole) poly.push_back(vertex(i)); // Check for intersections Point isect[2]; int isectv[2]; findIntersections(*this, i, i+1, hole, isect, isectv); if(isectv[0] >= 0) { // Intersection found: this is the start of a hole, // except when this edge started inside the hole. poly.push_back(isect[0]); if(!inhole) { // Start tracing the hole int j = isectv[0]; do { // Check for intersections // The first hole edge may intersect with another edges Point hisect[2]; int hisectv[2]; findIntersections(hole, j+1, j, *this, hisect, hisectv); // There is always one intersection (the one that got us here) if((j == isectv[0] && hisectv[1] >= 0) || (j != isectv[0] && hisectv[0] >= 0)) { // Pick the intersection that is not the one we came in on Point ip; int iv; if(hisectv[1] < 0 || glm::distance2(hisect[0],isect[0]) > glm::distance(hisect[1],isect[0])) { ip = hisect[0]; iv = hisectv[0]; } else { ip = hisect[1]; iv = hisectv[1]; } queue.push(i+1); // Avoid adding duplicate point of origin if(glm::distance2(poly.front(), ip) > 0.0001) poly.push_back(ip); i = iv; break; } else { // No intersections? Just add the hole vertex then poly.push_back(hole.vertex(j)); } if(--j < 0) j = hole.vertexCount() - 1; } while(j != isectv[0]); } } ++i; } // Partition the generated polygon into convex polygons // and add them to the list. if(poly.size() >= 3) { try { ConvexPolygon::make(poly, list); } catch(const algorithm::GeometryException &e) { // Bad polygons generated... The algorithm works well // enough most of the time, let's just roll back the error. int changes = list.size() - oldsize; #ifndef NDEBUG cerr << "booleanDifference error: " << e.what() << " (" << changes << " change(s) rolled back)\n"; #endif while(changes-->0) list.pop_back(); list.push_back(*this); return; } } poly.clear(); queue.pop(); } }