Skip to content

v0.2.50..v0.2.51 changeset BuildingMatchCreator.cpp

Garret Voltz edited this page Jan 15, 2020 · 1 revision
diff --git a/hoot-core/src/main/cpp/hoot/core/conflate/polygon/BuildingMatchCreator.cpp b/hoot-core/src/main/cpp/hoot/core/conflate/polygon/BuildingMatchCreator.cpp
index 546f165..23f6ef6 100644
--- a/hoot-core/src/main/cpp/hoot/core/conflate/polygon/BuildingMatchCreator.cpp
+++ b/hoot-core/src/main/cpp/hoot/core/conflate/polygon/BuildingMatchCreator.cpp
@@ -42,6 +42,8 @@
 #include <hoot/core/visitors/IndexElementsVisitor.h>
 #include <hoot/core/util/StringUtils.h>
 #include <hoot/core/util/CollectionUtils.h>
+#include <hoot/core/algorithms/extractors/OverlapExtractor.h>
+#include <hoot/core/schema/OsmSchema.h>
 
 // Standard
 #include <fstream>
@@ -130,7 +132,6 @@ public:
     int neighborCount = 0;
 
     std::vector<MatchPtr> tempMatches;
-
     for (std::set<ElementId>::const_iterator it = neighbors.begin(); it != neighbors.end(); ++it)
     {
       const ElementId neighborId = *it;
@@ -150,13 +151,16 @@ public:
         }
       }
     }
+    LOG_VART(neighborCount);
 
-    if (ConfigOptions().getBuildingReviewMatchesOtherThanOneToOne() && neighborCount > 1)
+    if (neighborCount > 1 && ConfigOptions().getBuildingReviewMatchesOtherThanOneToOne())
     {
       _markNonOneToOneMatchesAsReview(tempMatches);
     }
+    _adjustForOverlappingAdjoiningBuildingMatches(tempMatches);
 
-    for (std::vector<MatchPtr>::const_iterator it = tempMatches.begin(); it != tempMatches.end(); ++it)
+    for (std::vector<MatchPtr>::const_iterator it = tempMatches.begin(); it != tempMatches.end();
+         ++it)
     {
       _result.push_back(*it);
     }
@@ -282,7 +286,7 @@ private:
   int _taskStatusUpdateInterval;
 
   void _markNonOneToOneMatchesAsReview(std::vector<MatchPtr>& matches)
-  {
+  {      
     for (std::vector<MatchPtr>::iterator it = matches.begin(); it != matches.end(); ++it)
     {
       MatchPtr match = *it;
@@ -294,6 +298,88 @@ private:
       match->setExplain("Match involved in multiple building relationships.");
     }
   }
+
+  void _adjustForOverlappingAdjoiningBuildingMatches(std::vector<MatchPtr>& matches)
+  {
+    // If we have matches or reviews between adjoining houses (building=terrace; townhouses and
+    // the like), check for many to one relationships. From the many to one, keep only the match
+    // with the highest overlap. Convert all others to misses by removing the matches completely.
+    //
+    // The argument could be made that this overlap check could be done for all buildings, not just
+    // adjoining buildings, to reduce bad matches/reviews. Not sure how much havoc that might wreak,
+    // but maybe worth trying.
+
+    LOG_VART(matches);
+
+    QMap<ElementId, double> highestOverlapScores;
+    QMap<ElementId, MatchPtr> highestOverlapMatches;
+    const double tagScoreThreshold = ConfigOptions().getBuildingAdjoiningTagScoreThreshold();
+    bool adjoiningBuildingEncountered = false;
+
+    for (std::vector<MatchPtr>::const_iterator matchItr = matches.begin();
+         matchItr != matches.end(); ++matchItr)
+    {
+      MatchPtr match = *matchItr;
+      LOG_VART(match->getType());
+      assert(match->getType() != MatchType::Miss);
+
+      std::set<std::pair<ElementId, ElementId>> matchPairs = match->getMatchPairs();
+      LOG_VART(matchPairs.size());
+      assert(matchPairs.size() == 1);
+      std::pair<ElementId, ElementId> matchPair = *matchPairs.begin();
+
+      ConstElementPtr element1 = _map->getElement(matchPair.first);
+      ConstElementPtr element2 = _map->getElement(matchPair.second);
+
+      const QString adjoiningBuildingKvp = "building=terrace";
+      if (element1->getElementType() == ElementType::Way &&
+          element2->getElementType() == ElementType::Way &&
+          (OsmSchema::getInstance().score(adjoiningBuildingKvp, element1->getTags()) >=
+             tagScoreThreshold ||
+           OsmSchema::getInstance().score(adjoiningBuildingKvp, element2->getTags()) >=
+             tagScoreThreshold))
+      {
+        LOG_TRACE(
+          "one or both is adjoining building: " << element1->getElementId() << ", " <<
+          element2->getElementId());
+        adjoiningBuildingEncountered = true;
+
+        const double overlap = OverlapExtractor().extract(*_map, element1, element2);
+        if (!highestOverlapScores.contains(element1->getElementId()) ||
+            overlap > highestOverlapScores[element1->getElementId()])
+        {
+          highestOverlapScores[element1->getElementId()] = overlap;
+          highestOverlapMatches[element1->getElementId()] = match;
+          LOG_TRACE(
+            "Updating highest overlap score: " << overlap << " for ref: " <<
+            element1->getElementId() << ", sec: " << element2->getElementId());
+        }
+        else
+        {
+          LOG_TRACE(
+            "Dropping match with lower overlap score: " << overlap <<
+            " compared to highest overlap score: " <<
+            highestOverlapScores[element1->getElementId()] << " for ref: " <<
+            element1->getElementId() << ", sec: " << element2->getElementId());
+        }
+      }
+    }
+    highestOverlapScores.clear();
+    LOG_VART(adjoiningBuildingEncountered);
+
+    if (adjoiningBuildingEncountered)
+    {
+      std::vector<MatchPtr> modifiedMatches;
+      for (QMap<ElementId, MatchPtr>::const_iterator modifiedMatchItr = highestOverlapMatches.begin();
+           modifiedMatchItr != highestOverlapMatches.end(); ++modifiedMatchItr)
+      {
+        modifiedMatches.push_back(modifiedMatchItr.value());
+      }
+      matches = modifiedMatches;
+    }
+    highestOverlapMatches.clear();
+    LOG_VART(matches);
+  }
 };
 
 BuildingMatchCreator::BuildingMatchCreator() :
@@ -301,10 +387,10 @@ _conflateMatchBuildingModel(ConfigOptions().getConflateMatchBuildingModel())
 {
 }
 
-MatchPtr BuildingMatchCreator::createMatch(const ConstOsmMapPtr& map, ElementId eid1, ElementId eid2)
+MatchPtr BuildingMatchCreator::createMatch(const ConstOsmMapPtr& map, ElementId eid1,
+                                           ElementId eid2)
 {
   std::shared_ptr<BuildingMatch> result;
-
   if (eid1.getType() != ElementType::Node && eid2.getType() != ElementType::Node)
   {
     ConstElementPtr e1 = map->getElement(eid1);
@@ -316,7 +402,6 @@ MatchPtr BuildingMatchCreator::createMatch(const ConstOsmMapPtr& map, ElementId
       result.reset(new BuildingMatch(map, _getRf(), eid1, eid2, getMatchThreshold()));
     }
   }
-
   return result;
 }
 
Clone this wiki locally