std::vector<std::shared_ptr<MultipolygonProcessor::CoordinateSequence>> MultipolygonProcessor::createRings( CoordinateSequences &sequences) const { CoordinateSequences closedRings; std::shared_ptr<MultipolygonProcessor::CoordinateSequence> currentRing = nullptr; while (!sequences.empty()) { if (currentRing==nullptr) { // start a new ring with any remaining node sequence auto lastIndex = sequences.size() - 1; currentRing = sequences[lastIndex]; sequences.erase(sequences.begin() + lastIndex); } else { // try to continue the ring by appending a node sequence bool isFound = false; for (auto it = sequences.begin(); it!=sequences.end(); ++it) { if (!currentRing->tryAdd(**it)) continue; isFound = true; sequences.erase(it); break; } if (!isFound) return CoordinateSequences(); } // check whether the ring under construction is closed if (currentRing!=nullptr && currentRing->isClosed()) { // TODO check that it isn't self-intersecting! closedRings.push_back(currentRing); currentRing = nullptr; } } return std::move(closedRings); }
void MultipolygonProcessor::complexCase(CoordinateSequences& sequences) { CoordinateSequences rings = createRings(sequences); if (rings.empty()) return; fillRelation(rings); }
void MultipolygonProcessor::fillRelation(CoordinateSequences& rings) { while (!rings.empty()) { // find an outer ring std::shared_ptr<CoordinateSequence> outer = nullptr; for (auto candidate = rings.begin(); candidate != rings.end(); ++candidate) { bool containedInOtherRings = false; for (auto other = rings.begin(); other != rings.end(); ++other) { if (other != candidate && (*other)->containsRing((*candidate)->coordinates)) { containedInOtherRings = true; break; } } if (containedInOtherRings) continue; outer = *candidate; rings.erase(candidate); break; } // find inner rings of that ring CoordinateSequences inners; for (auto ring = rings.begin(); ring != rings.end();) { if (outer->containsRing((*ring)->coordinates)) { bool containedInOthers = false; for (auto other = rings.begin(); other != rings.end(); ++other) { if (other != ring && (*other)->containsRing((*ring)->coordinates)) { containedInOthers = true; break; } } if (!containedInOthers) { inners.push_back(*ring); ring = rings.erase(ring); continue; } } ++ring; } // outer auto outerArea = std::make_shared<Area>(); outerArea->id = outer->id; insertCoordinates(outer->coordinates, outerArea->coordinates, true); relation_.elements.push_back(outerArea); // inner: create a new area and remove the used rings for (const auto& innerRing : inners) { auto innerArea = std::make_shared<Area>(); insertCoordinates(innerRing->coordinates, innerArea->coordinates, false); relation_.elements.push_back(innerArea); } } }