コード例 #1
0
/// 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);
}
コード例 #2
0
void MultipolygonProcessor::complexCase(CoordinateSequences& sequences)
{
    CoordinateSequences rings = createRings(sequences);
    if (rings.empty()) return;

    fillRelation(rings);
}
コード例 #3
0
// 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);
}
コード例 #4
0
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);
}
コード例 #5
0
void MultipolygonProcessor::fillRelation(CoordinateSequences &rings) const {
  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);
    }
  }
}