void Poly::draw(int gl_type, double z, bool randomized) const { Vector2d v; uint count = vertices.size(); if (!closed && gl_type == GL_LINE_LOOP) { gl_type = GL_LINES; count--; } glBegin(gl_type); for (uint i=0; i < count; i++){ v = getVertexCircular(i); if (randomized) v = random_displaced(v); glVertex3f(v.x(),v.y(),z); if ( gl_type == GL_LINES ) { Vector2d vn = getVertexCircular(i+1); if (randomized) vn = random_displaced(vn); glVertex3f(vn.x(),vn.y(),z); } } glEnd(); // if (hole) { // glBegin(GL_LINES); // for (uint i=0; i < count; i++){ // glVertex3d(center.x(),center.y(),z); // Vector2d vn = vertices[i]; // if (randomized) vn = random_displaced(vn); // glVertex3d(vn.x(),vn.y(),z); // } // glEnd(); // } }
void Poly::calcHole() { if(vertices.size() == 0) return; // hole is undefined Vector2d p(-6000, -6000); int v=0; center = Vector2d(0,0); Vector2d q; for(size_t vert=0;vert<vertices.size();vert++) { q = vertices[vert]; center += q; if(q.x > p.x) { p = q; v=vert; } else if(q.x == p.x && q.y > p.y) { p.y = q.y; v=vert; } } center /= vertices.size(); // we have the x-most vertex (with the highest y if there was a contest), v Vector2d V1 = getVertexCircular(v-1); Vector2d V2 = getVertexCircular(v); Vector2d V3 = getVertexCircular(v+1); Vector2d Va=V2-V1; Vector2d Vb=V3-V2; hole = Va.cross(Vb) > 0; holecalculated = true; }
// Remove vertices that are on a straight line void Poly::cleanup(double maxerror) { if (vertices.size()<1) return; for (size_t v = 0; v < vertices.size() + 1; ) { Vector2d p1 = getVertexCircular(v-1); Vector2d p2 = getVertexCircular(v); Vector2d p3 = getVertexCircular(v+1); Vector2d v1 = (p2-p1); Vector2d v2 = (p3-p2); if (v1.lengthSquared() == 0 || v2.lengthSquared() == 0) { vertices.erase(vertices.begin()+(v % vertices.size())); if (vertices.size() < 1) break; } else { v1.normalize(); v2.normalize(); if ((v1-v2).lengthSquared() < maxerror) { vertices.erase(vertices.begin()+(v % vertices.size())); if (vertices.size() < 1) break; } else v++; } } }
/* * Iterate the vertices, and calculate whether this * shape is a hole or enclosed, based on whether the * segment normals point outward (a hole) or inward * (enclosing) */ void Poly::calcHole() const // hole is mutable { if(vertices.size() < 3) return; // hole is undefined Vector2d p(-INFTY, -INFTY); int v=0; center = Vector2d(0,0); Vector2d q; for(size_t vert=0;vert<vertices.size();vert++) { q = vertices[vert]; center += q; if(q.x() > p.x()) { p = q; v=vert; } else if(q.x() == p.x() && q.y() > p.y()) { p.y() = q.y(); v=vert; } } center /= vertices.size(); // we have the x-most vertex (with the highest y if there was a contest), v Vector2d V1 = getVertexCircular(v-1); Vector2d V2 = getVertexCircular(v); Vector2d V3 = getVertexCircular(v+1); // Vector2d Va=V2-V1; // Vector2d Vb=V3-V2; hole = isleftof(V2, V3, V1); //cross(Vb,Va) > 0; holecalculated = true; }
// add to lines starting with given index // closed lines sequence if number of vertices > 2 void Poly::getLines(vector<Vector2d> &lines, uint startindex) const { size_t count = vertices.size(); if (count<2) return; // one point no line if (count<3) count--; // two points one line for(size_t i=0;i<count;i++) { lines.push_back(getVertexCircular(i+startindex)); lines.push_back(getVertexCircular(i+startindex+1)); } }
vector<InFillHit> Poly::lineIntersections(const Vector2d P1, const Vector2d P2, double maxerr) const { vector<InFillHit> HitsBuffer; Vector2d P3,P4; for(size_t i = 0; i < vertices.size(); i++) { P3 = getVertexCircular(i); P4 = getVertexCircular(i+1); InFillHit hit; if (IntersectXY (P1,P2,P3,P4,hit,maxerr)) HitsBuffer.push_back(hit); } return HitsBuffer; }
vector<Vector2d> Poly::getCenterline() const { vector<Vector2d> line; for (uint i=0; i < vertices.size(); i++){ Vector2d abp = angle_bipartition(vertices[i], getVertexCircular(i-1), getVertexCircular(i+1)); // int intersect2D_Segments( const Vector2d &p1, const Vector2d &p2, // const Vector2d &p3, const Vector2d &p4, // Vector2d &I0, Vector2d &I1, // double &t0, double &t1, // double maxerr) } return line; }
bool Poly::vertexInside2(const Vector2d &point, double maxoffset) const { // Shoot a ray along +X and count the number of intersections. // If n_intersections is even, return false, else return true Vector2d EndP(point.x()+10000, point.y()); int intersectcount = 1; // we want to test if uneven double maxoffsetSq = maxoffset*maxoffset; Vector2d dummy; for(size_t i=0; i<vertices.size();i++) { const Vector2d P1 = getVertexCircular(i-1); const Vector2d P2 = vertices[i]; if (point_segment_distance_Sq(point, P1, P2, dummy) <= maxoffsetSq) return true; // Skip horizontal lines, we can't intersect with them, // because the test line is horizontal if(P1.y() == P2.y()) continue; Intersection hit; if(IntersectXY(point,EndP,P1,P2,hit,maxoffset)) intersectcount++; } return (intersectcount%2==0); }
// add to lines starting with given index // closed lines sequence if number of vertices > 2 and poly is closed void Poly::makeLines(vector<Vector2d> &lines, uint startindex) const { size_t count = vertices.size(); if (count<2) return; // one point no line bool closedlines = closed; if (count<3) closedlines = false; // two points one line vector<Vector2d> mylines; for(size_t i = startindex; i < count+startindex; i++) { if (!closedlines && i == count-1) continue; mylines.push_back(getVertexCircular(i)); mylines.push_back(getVertexCircular(i+1)); } if (!closedlines && startindex == count-1) lines.insert(lines.end(),mylines.rbegin(),mylines.rend()); else lines.insert(lines.end(),mylines.begin(),mylines.end()); }
// returns length and two points double Poly::shortestConnectionSq(const Poly &p2, Vector2d &start, Vector2d &end) const { double min1 = 100000000, min2 = 100000000; int minindex1=0, minindex2=0; Vector2d onpoint1, onpoint2; // test this vertices for (uint i = 0; i < vertices.size(); i++) { for (uint j = 0; j < p2.vertices.size(); j++) { Vector2d onpoint; // on p2 // dist from point i to lines on p2 const double mindist = point_segment_distance_Sq(p2.vertices[j], p2.getVertexCircular(j+1), vertices[i], onpoint); if (mindist < min1) { min1 = mindist; onpoint1 = onpoint; minindex1 = i; } } } // test p2 vertices for (uint i = 0; i < p2.vertices.size(); i++) { for (uint j = 0; j < vertices.size(); j++) { Vector2d onpoint; // on this // dist from p2 point i to lines on this const double mindist = point_segment_distance_Sq(vertices[j], getVertexCircular(j+1), p2.vertices[i], onpoint); if (mindist < min2) { min2 = mindist; onpoint2 = onpoint; minindex2 = i; } } } if (min1 < min2) { // this vertex, some point on p2 lines start = getVertexCircular(minindex1); end = onpoint1; } else { // p2 vertex, some point of this lines start = p2.getVertexCircular(minindex2); end = onpoint2; } return (end-start).squared_length(); }
vector<Vector2d> Poly::getPathAround(const Vector2d &from, const Vector2d &to) const { double dist; vector<Vector2d> path1, path2; // Poly off = Clipping::getOffset(*this, 0, jround).front(); //cerr << size()<< " Off " << off.size()<< endl; int nvert = size(); if (nvert==0) return path1; int fromind = (int)nearestDistanceSqTo(from, dist); int toind = (int)nearestDistanceSqTo(to, dist); if (fromind==toind) { path1.push_back(vertices[fromind]); return path1; } //calc both direction paths if(fromind < toind) { for (int i=fromind; i<=toind; i++) path1.push_back(getVertexCircular(i)); for (int i=fromind+nvert; i>=toind; i--) path2.push_back(getVertexCircular(i)); } else { for (int i=fromind; i>=toind; i--) path1.push_back(getVertexCircular(i)); for (int i=fromind; i<=toind+nvert; i++) path2.push_back(getVertexCircular(i)); } // find shorter one double len1=0,len2=0; for (uint i=1; i<path1.size(); i++) len1+=(path1[i]-path1[i-1]).squared_length(); for (uint i=1; i<path2.size(); i++) len2+=(path2[i]-path2[i-1]).squared_length(); if (len1 < len2) { // path1.insert(path1.begin(),from); // path1.push_back(to); return path1; } else{ // path2.insert(path2.begin(),from); // path2.push_back(to); return path2; } }
vector<Intersection> Poly::lineIntersections(const Vector2d P1, const Vector2d P2, double maxerr) const { vector<Intersection> HitsBuffer; Vector2d P3,P4; for(size_t i = 0; i < vertices.size(); i++) { P3 = getVertexCircular(i); P4 = getVertexCircular(i+1); Intersection hit; if (IntersectXY(P1,P2,P3,P4,hit,maxerr)) HitsBuffer.push_back(hit); } // std::sort(HitsBuffer.begin(),HitsBuffer.end()); // vector<Vector2d> v(HitsBuffer.size()); // for(size_t i = 0; i < v.size(); i++) // v[i] = HitsBuffer[i].p; return HitsBuffer; }
void Poly::draw(int gl_type, double z) const { Vector2d v; uint count = vertices.size(); glBegin(gl_type); for (uint i=0;i < count;i++){ v = getVertexCircular(i); glVertex3f(v.x,v.y,z); } glEnd(); }
void Poly::draw(int gl_type, double z, bool randomized) const { Vector2d v; uint count = vertices.size(); glBegin(gl_type); for (uint i=0;i < count;i++){ v = getVertexCircular(i); if (randomized) v = random_displace(v); glVertex3f(v.x,v.y,z); } glEnd(); }
// http://paulbourke.net/geometry/insidepoly/ // not really working bool Poly::vertexInside2(const Vector2d p, double maxoffset) const { uint c = false; //Poly off = Clipping::getOffset(*this,maxoffset).front(); for (uint i = 0; i < vertices.size(); i++) { Vector2d Pi = vertices[i]; Vector2d Pj = getVertexCircular(i+1); if ( ((Pi.y > p.y) != (Pj.y > p.y)) && (abs(p.x - (Pj.x-Pi.x) * (p.y-Pi.y) / (Pj.y-Pj.y) + Pi.x) > maxoffset) ) c = !c; } if (!c) for (uint i = 0; i < vertices.size(); i++) if ((vertices[i]-p).length() < maxoffset) return true; // on a vertex return c; }
// http://paulbourke.net/geometry/insidepoly/ bool Poly::vertexInside(const Vector2d &p, double maxoffset) const { #define POLYINSIDEVERSION 0 #if POLYINSIDEVERSION==0 // this one works uint N = size(); if (N < 2) return false; uint counter = 0; uint i; double xinters; const Vector2d *p1, *p2; p1 = &(vertices[0]); for (i=1;i<=N;i++) { p2 = &(vertices[i % N]); if (p.y() > min(p1->y(), p2->y())) { if (p.y() <= max(p1->y(), p2->y())) { if (p.x() <= max(p1->x(), p2->x())) { if (p1->y() != p2->y()) { xinters = (p.y()-p1->y())*(p2->x()-p1->x())/(p2->y()-p1->y())+p1->x(); if (p1->x() == p2->x() || p.x() <= xinters) counter++; } } } } p1 = p2; } return (counter % 2 != 0); #else // not really working? bool c = false; //Poly off = Clipping::getOffset(*this,maxoffset).front(); for (uint i = 0; i < vertices.size(); i++) { const Vector2d Pi = vertices[i]; const Vector2d Pj = getVertexCircular(i+1); if ( ((Pi.y() > p.y()) != (Pj.y() > p.y())) && (abs(p.x() - (Pj.x()-Pi.x()) * (p.y()-Pi.y()) / (Pj.y()-Pi.y()) + Pi.x()) > maxoffset) ) c = !c; } if (!c) for (uint i = 0; i < vertices.size(); i++) if ((vertices[i]-p).length() < maxoffset) return true; // on a vertex return c; #endif }
bool Poly::vertexInside(const Vector2d point, double maxoffset) const { // Shoot a ray along +X and count the number of intersections. // If n_intersections is even, return false, else return true Vector2d EndP(point.x+10000, point.y); int intersectcount = 1; // we want to test if uneven for(size_t i=0; i<vertices.size();i++) { Vector2d P1 = getVertexCircular(i-1); Vector2d P2 = vertices[i]; // Skip horizontal lines, we can't intersect with them, // because the test line is horizontal if(P1.y == P2.y) continue; Intersection hit; if(IntersectXY(point,EndP,P1,P2,hit,maxoffset)) intersectcount++; } return intersectcount%2; }
Vector3d Poly::getVertexCircular3(int pointindex) const { Vector2d v = getVertexCircular(pointindex); return Vector3d(v.x(),v.y(),z); }
double Poly::angleAtVertex(uint i) const { return angleBetween(getVertexCircular(i)-getVertexCircular(i-1), getVertexCircular(i+1)-getVertexCircular(i)); }
// length of the line starting at startindex double Poly::getLinelengthSq(uint startindex) const { const double length = (getVertexCircular(startindex+1) - getVertexCircular(startindex)).squared_length(); return length; }