Skip to content

v0.2.55..v0.2.56 changeset DiffConflator.cpp

Garret Voltz edited this page Aug 14, 2020 · 3 revisions
diff --git a/hoot-core/src/main/cpp/hoot/core/conflate/DiffConflator.cpp b/hoot-core/src/main/cpp/hoot/core/conflate/DiffConflator.cpp
index 8965d6a..75fe114 100644
--- a/hoot-core/src/main/cpp/hoot/core/conflate/DiffConflator.cpp
+++ b/hoot-core/src/main/cpp/hoot/core/conflate/DiffConflator.cpp
@@ -86,6 +86,7 @@ HOOT_FACTORY_REGISTER(OsmMapOperation, DiffConflator)
 DiffConflator::DiffConflator() :
 _matchFactory(MatchFactory::getInstance()),
 _settings(Settings::getInstance()),
+_intraDatasetElementIdsPopulated(false),
 _taskStatusUpdateInterval(ConfigOptions().getTaskStatusUpdateInterval()),
 _numSnappedWays(0)
 {
@@ -96,6 +97,7 @@ DiffConflator::DiffConflator(const std::shared_ptr<MatchThreshold>& matchThresho
 _matchFactory(MatchFactory::getInstance()),
 _matchThreshold(matchThreshold),
 _settings(Settings::getInstance()),
+_intraDatasetElementIdsPopulated(false),
 _taskStatusUpdateInterval(ConfigOptions().getTaskStatusUpdateInterval()),
 _numSnappedWays(0)
 {
@@ -107,6 +109,13 @@ DiffConflator::~DiffConflator()
   _reset();
 }
 
+void DiffConflator::setConfiguration(const Settings &conf)
+{
+  _settings = conf;
+  _matchThreshold.reset();
+  _reset();
+}
+
 void DiffConflator::_updateProgress(const int currentStep, const QString message)
 {
   // Always check for a valid task weight and that the job was set to running. Otherwise, this is
@@ -130,7 +139,7 @@ void DiffConflator::apply(OsmMapPtr& map)
   _tagChangesetStats = "";
   _unifiedChangesetStats = "";
 
-  // Store the map - we might need it for tag diff later.
+  // Store the map, as we might need it for tag diff later.
   _pMap = map;
 
   // This status progress reporting could get way more granular, but we'll go with this for now to
@@ -158,7 +167,9 @@ void DiffConflator::apply(OsmMapPtr& map)
   _stats.append(SingleStat("Project to Planar Time (sec)", timer.getElapsedAndRestart()));
   OsmMapWriterFactory::writeDebugMap(_pMap, "after-projecting-to-planar");
 
-  // find all the matches in this _pMap
+  // find all the matches in this map
+  _intraDatasetMatchOnlyElementIds.clear();
+  _intraDatasetElementIdsPopulated = false;
   if (_matchThreshold.get())
   {
     _matchFactory.createMatches(_pMap, _matches, _bounds, _matchThreshold);
@@ -253,34 +264,53 @@ void DiffConflator::_removeMatches(const Status& status)
 
   const bool treatReviewsAsMatches = ConfigOptions().getDifferentialTreatReviewsAsMatches();
   LOG_VARD(treatReviewsAsMatches);
+
+  if (!_intraDatasetElementIdsPopulated)
+  {
+    _intraDatasetMatchOnlyElementIds = _getElementIdsInvolvedInOnlyIntraDatasetMatches(_matches);
+    _intraDatasetElementIdsPopulated = true;
+  }
+
   for (std::vector<ConstMatchPtr>::iterator mit = _matches.begin(); mit != _matches.end(); ++mit)
   {
     ConstMatchPtr match = *mit;
+    LOG_VART(match);
     if (treatReviewsAsMatches || match->getType() != MatchType::Review)
     {
-      std::set<std::pair<ElementId, ElementId>> pairs = (*mit)->getMatchPairs();
+      std::set<std::pair<ElementId, ElementId>> pairs = match->getMatchPairs();
       for (std::set<std::pair<ElementId, ElementId>>::iterator pit = pairs.begin();
            pit != pairs.end(); ++pit)
-      {
+      {  
+        ElementPtr e1;
+        ElementPtr e2;
+
         if (!pit->first.isNull())
         {
           LOG_VART(pit->first);
-          ElementPtr e = _pMap->getElement(pit->first);
-          if (e && e->getStatus() == status)
-          {
-            //LOG_VART(e->getTags().get("name"));
-            RecursiveElementRemover(pit->first).apply(_pMap);
-          }
+          e1 = _pMap->getElement(pit->first);
+
         }
         if (!pit->second.isNull())
         {
           LOG_VART(pit->second);
-          ElementPtr e = _pMap->getElement(pit->second);
-          if (e && e->getStatus() == status)
-          {
-            //LOG_VART(e->getTags().get("name"));
-            RecursiveElementRemover(pit->second).apply(_pMap);
-          }
+          e2 = _pMap->getElement(pit->second);
+        }
+
+        if (e1 && e1->getStatus() == status &&
+            // poi/poly is the only conflation type that allows intra-dataset matches. We don't want
+            // these to be removed from the diff output.
+            !(match->getMatchName() == PoiPolygonMatch::MATCH_NAME &&
+              _intraDatasetMatchOnlyElementIds.contains(pit->first)))
+        {
+          LOG_VART(e1);
+          RecursiveElementRemover(pit->first).apply(_pMap);
+        }
+        if (e2 && e2->getStatus() == status &&
+            !(match->getMatchName() == PoiPolygonMatch::MATCH_NAME &&
+             _intraDatasetMatchOnlyElementIds.contains(pit->second)))
+        {
+          LOG_VART(e2);
+          RecursiveElementRemover(pit->second).apply(_pMap);
         }
       }
     }
@@ -289,11 +319,70 @@ void DiffConflator::_removeMatches(const Status& status)
   OsmMapWriterFactory::writeDebugMap(_pMap, "after-removing-" + status.toString() + "-matches");
 }
 
-void DiffConflator::setConfiguration(const Settings &conf)
+QSet<ElementId> DiffConflator::_getElementIdsInvolvedInOnlyIntraDatasetMatches(
+  const std::vector<ConstMatchPtr>& matches)
 {
-  _settings = conf;
-  _matchThreshold.reset();
-  _reset();
+  QSet<ElementId> elementIds;
+
+  const bool allowReviews = ConfigOptions().getDifferentialTreatReviewsAsMatches();
+
+  // Go through and record any element's involved in an intra-dataset match, since we don't want
+  // those types of matches from preventing an element from passing through to the diff output.
+
+  for (std::vector<ConstMatchPtr>::const_iterator matchItr = matches.begin();
+       matchItr != matches.end(); ++matchItr)
+  {
+    ConstMatchPtr match = *matchItr;
+    if (match->getType() == MatchType::Match ||
+        (allowReviews && match->getType() == MatchType::Review))
+    {
+      std::set<std::pair<ElementId, ElementId>> pairs = match->getMatchPairs();
+      for (std::set<std::pair<ElementId, ElementId>>::const_iterator pairItr = pairs.begin();
+           pairItr != pairs.end(); ++pairItr)
+      {
+        std::pair<ElementId, ElementId> pair = *pairItr;
+        ConstElementPtr e1 = _pMap->getElement(pair.first);
+        ConstElementPtr e2 = _pMap->getElement(pair.second);
+        // Any match with elements having the same status (came from the same dataset) is an
+        // intra-dataset match.
+        if (e1 && e2 && e1->getStatus() == e2->getStatus())
+        {
+          elementIds.insert(pair.first);
+          elementIds.insert(pair.second);
+        }
+      }
+    }
+  }
+
+  // Now, go back through and exclude any previously added that are also involved in an
+  // inter-dataset match, since we don't want those in the diff output.
+
+  for (std::vector<ConstMatchPtr>::const_iterator matchItr = matches.begin();
+       matchItr != matches.end(); ++matchItr)
+  {
+    ConstMatchPtr match = *matchItr;
+    if (match->getType() == MatchType::Match ||
+        (allowReviews && match->getType() == MatchType::Review))
+    {
+      std::set<std::pair<ElementId, ElementId>> pairs = match->getMatchPairs();
+      for (std::set<std::pair<ElementId, ElementId>>::const_iterator pairItr = pairs.begin();
+           pairItr != pairs.end(); ++pairItr)
+      {
+        std::pair<ElementId, ElementId> pair = *pairItr;
+        ConstElementPtr e1 = _pMap->getElement(pair.first);
+        ConstElementPtr e2 = _pMap->getElement(pair.second);
+        // Any match with elements having a different status (came from different datasets) is an
+        // inter-dataset match.
+        if (e1 && e2 && e1->getStatus() != e2->getStatus())
+        {
+          elementIds.remove(pair.first);
+          elementIds.remove(pair.second);
+        }
+      }
+    }
+  }
+
+  return elementIds;
 }
 
 MemChangesetProviderPtr DiffConflator::getTagDiff()
@@ -516,8 +605,11 @@ Change DiffConflator::_getChange(ConstElementPtr pOldElement, ConstElementPtr pN
 
   // Need to merge tags into the new element. Keeps all names, chooses tags1 in event of a conflict.
   Tags newTags =
-    TagComparator::getInstance().overwriteMerge(pNewElement->getTags(), pOldElement->getTags(), QStringList(),
-                                                ConfigOptions().getDuplicateNameCaseSensitive());
+    TagComparator::getInstance().overwriteMerge(
+      pNewElement->getTags(), pOldElement->getTags(),
+      ConfigOptions().getTagMergerOverwriteExclude(),
+      ConfigOptions().getTagMergerOverwriteAccumulateValuesKeys(),
+      ConfigOptions().getDuplicateNameCaseSensitive());
   pChangeElement->setTags(newTags);
 
   // Create the change
Clone this wiki locally