/// For algorithm details, see http://wiki.openstreetmap.org/wiki/Relation:multipolygon/Algorithm void MultipolygonProcessor::process() { bool allClosed = true; // NOTE do not count multipolygon tag itself bool hasNoTags = relation_.tags.size() < 2; Ints outerIndecies; Ints innerIndecies; CoordinateSequences sequences; for (const auto &member : members_) { if (member.type!="w") continue; Coordinates coordinates; auto wayPair = context_.wayMap.find(member.refId); if (wayPair!=context_.wayMap.end()) { coordinates = wayPair->second->coordinates; } else { auto areaPair = context_.areaMap.find(member.refId); if (areaPair!=context_.areaMap.end()) { coordinates = areaPair->second->coordinates; // NOTE make coordinates to be closed ring coordinates.push_back(coordinates[0]); // NOTE merge tags to relation // hasNoTags prevents the case where relation has members with their own tags // which should be processed independently (geometry reusage) if (member.role=="outer" && hasNoTags) mergeTags(areaPair->second->tags); } else { auto relationPair = context_.relationMap.find(member.refId); if (relationPair==context_.relationMap.end()) return; // NOTE cannot fill relation: incomplete data resolve_(*relationPair->second); } } if (coordinates.empty()) continue; if (member.role=="outer") outerIndecies.push_back(static_cast<int>(sequences.size())); else if (member.role=="inner") innerIndecies.push_back(static_cast<int>(sequences.size())); else continue; auto sequence = std::make_shared<CoordinateSequence>(member.refId, coordinates); if (!sequence->isClosed()) allClosed = false; sequences.push_back(sequence); } if (outerIndecies.size()==1 && allClosed) simpleCase(sequences, outerIndecies, innerIndecies); else complexCase(sequences); }
// see http://wiki.openstreetmap.org/wiki/Relation:multipolygon/Algorithm void MultipolygonProcessor::process() { bool allClosed = true; Ints outerIndecies; Ints innerIndecies; CoordinateSequences sequences; for (const auto& member : members_) { if (member.type != "way") continue; Coordinates coordinates; auto wayPair = context_.wayMap.find(member.refId); if (wayPair != context_.wayMap.end()) { coordinates = wayPair->second->coordinates; } else { auto areaPair = context_.areaMap.find(member.refId); if (areaPair != context_.areaMap.end()) { coordinates = areaPair->second->coordinates; // NOTE merge tags to relation if (member.role == "outer") mergeTags(areaPair->second->tags); } else { auto relationPair = context_.relationMap.find(member.refId); if (relationPair == context_.relationMap.end()) return; // NOTE cannot fill relation: incomplete data resolve_(*relationPair->second); } } if (coordinates.empty()) continue; if (member.role == "outer") outerIndecies.push_back(static_cast<int>(sequences.size())); else if (member.role == "inner") innerIndecies.push_back(static_cast<int>(sequences.size())); else continue; auto sequence = std::make_shared<CoordinateSequence>(member.refId, coordinates); if (!sequence->isClosed()) allClosed = false; sequences.push_back(sequence); } if (outerIndecies.size() == 1 && allClosed) simpleCase(sequences, outerIndecies, innerIndecies); else complexCase(sequences); }
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); }