toxi::geom::Vec2D toxi::geom::Polygon2D::getCentroid() { Vec2D res = Vec2D(); for (int i = 0, num = vertices.size(); i < num; i++) { Vec2D a = vertices.at(i); Vec2D b = vertices.at( ( i + 1 ) % num ); double crossP = a.getX() * b.getY() - b.getX() * a.getY(); res.set( res.getX() + (a.getX() + b.getX()) * crossP, res.getY() + (a.getY() + b.getY()) * crossP ); } return res.scale(1 / (6 * getArea())); }
bool toxi::geom::Polygon2D::toOutLine() { int corners = vertices.size(); int maxSegs = corners * 3; std::vector<Vec2D> newVerts; std::vector< Vec2D > segments( maxSegs ); std::vector< Vec2D > segEnds( maxSegs ); std::vector< double > segAngles( maxSegs ); //Vec2D * segments; //segments = ( Vec2D* ) malloc( sizeof( Vec2D ) * maxSegs); //Vec2D * segEnds; //segEnds = (Vec2D * ) malloc(sizeof( Vec2D ) * maxSegs ); //float * segAngles; //segAngles = (float * ) malloc( sizeof( float ) * maxSegs ); //Vec2D[] segments = new Vec2D[maxSegs]; //Vec2D[] segEnds = new Vec2D[maxSegs]; //float[] segAngles = new float[maxSegs]; Vec2D start = vertices.at(0); double lastAngle = toxi::math::MathUtils::PI; float a, b, c, d, e, f; double angleDif, bestAngleDif; int i, j = corners - 1, segs = 0; if (corners > maxSegs) { return false; } // 1,3. Reformulate the polygon as a set of line segments, and choose a // starting point that must be on the perimeter. for (i = 0; i < corners; i++) { Vec2D pi = vertices.at(i); Vec2D pj = vertices.at(j); if (!( pi == pj )) { segments[segs] = pi; segEnds[segs++] = pj; } j = i; if (pi.getY() > start.getY() || (pi.getY() == start.getY() && pi.getX() < start.getX())) { start.set( pi); } } if (segs == 0) { return false; } // 2. Break the segments up at their intersection points. for (i = 0; i < segs - 1; i++) { for (j = i + 1; j < segs; j++) { Line2D li = toxi::geom::Line2D( segments[i], segEnds[i]); Line2D lj = toxi::geom::Line2D( segments[j], segEnds[j]); LineIntersection isec = li.intersectLine( lj ); if (isec.getType() == toxi::geom::LineIntersection::Type::INTERSECTING) { Vec2D ipos = isec.getPos(); if (!( ipos == segments[i] ) && !( ipos == segEnds[i])) { if (segs == maxSegs) { return false; } segments[segs] = segments[i]; segEnds[segs++] = ipos; segments[i] = ipos; } if (!( ipos == segments[j] ) && !( ipos == segEnds[ j ] ) ) { if (segs == maxSegs) { return false; } segments[segs] = segments[j]; segEnds[segs++] = ipos; segments[j] = ipos; } } } } // Calculate the angle of each segment. for (i = 0; i < segs; i++) { segAngles[i] = segEnds[i].sub( segments[i] ).positiveHeading(); } // 4. Build the perimeter polygon. c = static_cast< float > ( start.getX() ); d = static_cast< float > ( start.getY() ); a = c - 1; b = d; e = 0; f = 0; newVerts.push_back(Vec2D(c, d)); corners = 1; while (true) { bestAngleDif = toxi::math::MathUtils::TWO_PI; for (i = 0; i < segs; i++) { if (segments[i].getX() == c && segments[i].getY() == d && (segEnds[i].getX() != a || segEnds[i].getY() != b)) { angleDif = lastAngle - segAngles[i]; while (angleDif >= toxi::math::MathUtils::TWO_PI) { angleDif -= toxi::math::MathUtils::TWO_PI; } while (angleDif < 0) { angleDif += toxi::math::MathUtils::TWO_PI; } if (angleDif < bestAngleDif) { bestAngleDif = angleDif; e = static_cast< float > ( segEnds[i].getX() ); f = static_cast< float > ( segEnds[i].getY() ); } } if (segEnds[i].getX() == c && segEnds[i].getY() == d && (segments[i].getX() != a || segments[i].getY() != b)) { angleDif = lastAngle - segAngles[i] + toxi::math::MathUtils::PI; while (angleDif >= toxi::math::MathUtils::TWO_PI) { angleDif -= toxi::math::MathUtils::TWO_PI; } while (angleDif < 0) { angleDif += toxi::math::MathUtils::TWO_PI; } if (angleDif < bestAngleDif) { bestAngleDif = angleDif; e = static_cast< float > ( segments[i].getX() ); f = static_cast< float > ( segments[i].getY() ); } } } if (corners > 1 && c == newVerts.at(0).getX() && d == newVerts.at(0).getY() && e == newVerts.at(1).getX() && f == newVerts.at(1).getY()) { corners--; vertices = newVerts; return true; } if (bestAngleDif == toxi::math::MathUtils::TWO_PI || corners == maxSegs) { return false; } lastAngle -= bestAngleDif + toxi::math::MathUtils::PI; newVerts.push_back(Vec2D(e, f)); corners++; a = c; b = d; c = e; d = f; } }