void limitHoles(GeometryCollection& polygon, uint32_t maxHoles) { if (polygon.size() > 1 + maxHoles) { std::nth_element(polygon.begin() + 1, polygon.begin() + 1 + maxHoles, polygon.end(), [] (const auto& a, const auto& b) { return signedArea(a) > signedArea(b); }); polygon.resize(1 + maxHoles); } }
std::vector<GeometryCollection> classifyRings(const GeometryCollection& rings) { std::vector<GeometryCollection> polygons; std::size_t len = rings.size(); if (len <= 1) { polygons.push_back(rings); return polygons; } GeometryCollection polygon; int8_t ccw = 0; for (std::size_t i = 0; i < len; i++) { double area = signedArea(rings[i]); if (area == 0) continue; if (ccw == 0) ccw = (area < 0 ? -1 : 1); if (ccw == (area < 0 ? -1 : 1) && !polygon.empty()) { polygons.push_back(polygon); polygon.clear(); } polygon.push_back(rings[i]); } if (!polygon.empty()) polygons.push_back(polygon); return polygons; }
static void processPolynodeBranch(ClipperLib::PolyNode* polynode, GeometryCollection& rings) { // Exterior ring. rings.push_back(fromClipperPath(polynode->Contour)); assert(signedArea(rings.back()) > 0); // Interior rings. for (auto * ring : polynode->Childs) { rings.push_back(fromClipperPath(ring->Contour)); assert(signedArea(rings.back()) < 0); } // PolyNodes may be nested in the case of a polygon inside a hole. for (auto * ring : polynode->Childs) { for (auto * subRing : ring->Childs) { processPolynodeBranch(subRing, rings); } } }
void antipodalPairs(std::list<Point2D> &Q, std::list<std::pair<Point2D, Point2D> > &pairs) { std::list<Point2D>::iterator p = Q.begin(), q = Q.begin(), nextp, nextq, q0, p0 = Q.begin(); pairs.clear(); //si tengo pocos elementos if(Q.size() < 3) { for(std::list<Point2D>::iterator pp = Q.begin(); pp != Q.end(); pp++) { for( std::list<Point2D>:: iterator qq = pp; qq != Q.end(); ++qq) { pairs.push_back(std::make_pair(*pp,*qq)); } } return; } nextp = p; nextp++; //el siguiente de p q++; //q es el next de p nextq = q; nextq++; //el siguiente de q //revisar while(nextq != Q.end() && (signedArea(*p, *nextp, *nextq) > signedArea(*p, *nextp, *q))) { q = nextq; nextq++; } q0 = q; //revisar si no va Q.end() while( q != p0) { p = nextp; std::pair<Point2D,Point2D> pq = std::make_pair(*p,*q); pairs.push_back(pq); //bucle infinito while(signedArea(*p, *nextp, *nextq) > signedArea(*p, *nextp, *q)) { q = nextq; nextq++; if(q == Q.end()) q = Q.begin(); pq = std::make_pair(*p,*q); if(pq != std::make_pair(*q0, *p0)) pairs.push_back(pq); else return; } if(compareEqualFloat( signedArea(*p, *nextp, *nextq), signedArea(*p, *nextp, *q))) { if(pq != std::make_pair(*q0,Q.back())) pairs.push_back(std::make_pair(*p, *nextq)); else pairs.push_back(std::make_pair(*nextp, *q)); } } }
bool isClockwise(const Points2D& points) { return (signedArea(points) >= 0); }
std::shared_ptr<TileData> ClientGeoJsonSource::parse(const Tile& _tile, std::vector<char>& _rawData) const { if (!m_store) { return nullptr; } auto data = std::make_shared<TileData>(); auto id = _tile.getID(); auto tile = m_store->getTile(id.z, id.x, id.y); // uses a mutex lock internally for thread-safety Layer layer(""); // empty name will skip filtering by 'collection' for (auto& it : tile.features) { Feature feat(m_id); const auto& geom = it.tileGeometry; const auto type = it.type; switch (type) { case geojsonvt::TileFeatureType::Point: { feat.geometryType = GeometryType::points; for (const auto& pt : geom) { const auto& point = pt.get<geojsonvt::TilePoint>(); feat.points.push_back(transformPoint(point)); } break; } case geojsonvt::TileFeatureType::LineString: { feat.geometryType = GeometryType::lines; for (const auto& r : geom) { Line line; for (const auto& pt : r.get<geojsonvt::TileRing>().points) { line.push_back(transformPoint(pt)); } feat.lines.emplace_back(std::move(line)); } break; } case geojsonvt::TileFeatureType::Polygon: { feat.geometryType = GeometryType::polygons; for (const auto& r : geom) { Line line; for (const auto& pt : r.get<geojsonvt::TileRing>().points) { line.push_back(transformPoint(pt)); } // Polygons are in a flat list of rings, with ccw rings indicating // the beginning of a new polygon if (signedArea(line) >= 0 || feat.polygons.empty()) { feat.polygons.emplace_back(); } feat.polygons.back().push_back(std::move(line)); } break; } default: break; } feat.props = *it.tags.map; layer.features.emplace_back(std::move(feat)); } data->layers.emplace_back(std::move(layer)); return data; }
float my::AbstractPolygon::area()const { return std::abs( signedArea(glm::cross(edgeVector(0), edgeVector(1))) ); }
std::vector<Vec3d> ClosedPolygon::getEqualDistancePoints(int numSides, const Vec3d& center) { std::vector<Vec3d> result; int N = closedPoints.size(); if(N < 1) return result; // empty polygon for(int i = 0; i < N; i++) lines.push_back(Line(closedPoints[i], closedPoints[(i+1) % N], i)); this->computeLengths(); // Distance to walk on polygon double segmentLength = this->closedLength / numSides; // Locate start point using vecUp Vec3d startPoint; int startIndex = 0; Plane halfPlane(vecUp, center); //testPlanes1.push_back(halfPlane); double minDist = DBL_MAX; // Test intersection with all lines and remember minimum one for(int i = 0; i < N; i++) { Vec3d pointIntersect; int res = halfPlane.LineIntersect(lines[i], pointIntersect); if(res == INTERSECT || res == ENDPOINT_INTERSECT) { Vec3d toIntsect = pointIntersect - center; if(toIntsect.norm() < minDist && dot(toIntsect, vecB) > 0) { minDist = toIntsect.norm(); startPoint = pointIntersect; startIndex = i; } } } double t = lines[startIndex].timeAt(startPoint); int index = startIndex; // Compute equal-dist points on polygon for(int s = 0; s < numSides; s++) { // Add new point result.push_back(lines[index].pointAt(t)); walk(segmentLength, t, index, &t, &index); } // if polygon is opposite direction then reverse if( signedArea(result, plane.n, center) < 0 ) { std::reverse(result.begin(), result.end()); std::rotate(result.begin(), result.begin()+result.size()-1 , result.end()); } return closedPoints = result; }
double signedArea(const P2Vector &points) { return signedArea(points, p2_adapt_ident()); }