Skip to content

v0.2.53..v0.2.54 changeset SuperfluousNodeRemover.cpp

Garret Voltz edited this page Mar 31, 2020 · 1 revision
diff --git a/hoot-core/src/main/cpp/hoot/core/ops/SuperfluousNodeRemover.cpp b/hoot-core/src/main/cpp/hoot/core/ops/SuperfluousNodeRemover.cpp
index e1a848b..d4e247a 100644
--- a/hoot-core/src/main/cpp/hoot/core/ops/SuperfluousNodeRemover.cpp
+++ b/hoot-core/src/main/cpp/hoot/core/ops/SuperfluousNodeRemover.cpp
@@ -22,7 +22,7 @@
  * This will properly maintain the copyright information. DigitalGlobe
  * copyrights will be updated automatically.
  *
- * @copyright Copyright (C) 2015, 2016, 2017, 2018, 2019 DigitalGlobe (http://www.digitalglobe.com/)
+ * @copyright Copyright (C) 2015, 2016, 2017, 2018, 2019, 2020 DigitalGlobe (http://www.digitalglobe.com/)
  */
 
 #include "SuperfluousNodeRemover.h"
@@ -32,6 +32,7 @@
 #include <hoot/core/util/MapProjector.h>
 #include <hoot/core/util/Factory.h>
 #include <hoot/core/util/Log.h>
+#include <hoot/core/util/StringUtils.h>
 #include <hoot/core/ops/RemoveNodeByEid.h>
 
 // Standard
@@ -50,15 +51,44 @@ namespace hoot
 HOOT_FACTORY_REGISTER(OsmMapOperation, SuperfluousNodeRemover)
 
 SuperfluousNodeRemover::SuperfluousNodeRemover() :
-_ignoreInformationTags(false)
+_ignoreInformationTags(false),
+_unallowedOrphanKvps(ConfigOptions().getSuperfluousNodeRemoverUnallowedOrphanKvps()),
+_taskStatusUpdateInterval(ConfigOptions().getTaskStatusUpdateInterval())
 {
 }
 
 void SuperfluousNodeRemover::apply(std::shared_ptr<OsmMap>& map)
 {
-  _numAffected = 0;
+  _numAffected = 0;     // _numAffected reflects the actual number of nodes removed
+  _numProcessed = 0;    // _numProcessed reflects total elements processed
   _usedNodes.clear();
 
+  // Let's collect the IDs of all the nodes we can't remove first.
+
+  const RelationMap& relations = map->getRelations();
+  for (RelationMap::const_iterator it = relations.begin(); it != relations.end(); ++it)
+  {
+    ConstRelationPtr relation = it->second;
+    const vector<RelationData::Entry>& members = relation->getMembers();
+    for (size_t i = 0; i < members.size(); i++)
+    {
+      const RelationData::Entry member = members[i];
+      if (member.getElementId().getType() == ElementType::Node)
+      {
+        _usedNodes.insert(member.getElementId().getId());
+      }
+    }
+
+    _numProcessed++;
+    if (_numProcessed % _taskStatusUpdateInterval == 0)
+    {
+      PROGRESS_INFO(
+        "Exempted " << StringUtils::formatLargeNumber(_usedNodes.size()) <<
+        " nodes from removal after processing " << StringUtils::formatLargeNumber(_numProcessed) <<
+        " total elements.");
+    }
+  }
+
   const WayMap& ways = map->getWays();
   for (WayMap::const_iterator it = ways.begin(); it != ways.end(); ++it)
   {
@@ -66,6 +96,16 @@ void SuperfluousNodeRemover::apply(std::shared_ptr<OsmMap>& map)
     const vector<long>& nodeIds = w->getNodeIds();
     LOG_VART(nodeIds);
     _usedNodes.insert(nodeIds.begin(), nodeIds.end());
+    _numProcessed += nodeIds.size();
+
+    _numProcessed++;
+    if (_numProcessed % _taskStatusUpdateInterval == 0)
+    {
+      PROGRESS_INFO(
+        "Exempted " << StringUtils::formatLargeNumber(_usedNodes.size()) <<
+        " nodes from removal after processing " << StringUtils::formatLargeNumber(_numProcessed) <<
+        " total elements.");
+    }
   }
 
   const NodeMap nodes = map->getNodes();
@@ -74,10 +114,29 @@ void SuperfluousNodeRemover::apply(std::shared_ptr<OsmMap>& map)
     const Node* n = it->second.get();
     LOG_VART(n->getElementId());
     LOG_VART(n->getTags().getNonDebugCount());
-    if (!_ignoreInformationTags && n->getTags().getNonDebugCount() != 0)
+
+    // There original reason behind adding this is that there a potential bug in
+    // HighwaySnapMerger::_snapEnds that will leave turning circle nodes orphaned from roads.
+    // Turning circles are always expected to be a road way node. If its an actual bug, it should
+    // eventually be fixed, but this logic will clean them up for the time being. The types we allow
+    // to be orphaned are configurable in case we ever need to add others.
+    if (_usedNodes.find(n->getId()) == _usedNodes.end() &&
+        n->getTags().hasAnyKvp(_unallowedOrphanKvps))
+    {
+    }
+    else if (!_ignoreInformationTags && n->getTags().getNonDebugCount() != 0)
     {
       _usedNodes.insert(n->getId());
     }
+    _numProcessed++;
+
+    if (_numProcessed % _taskStatusUpdateInterval == 0)
+    {
+      PROGRESS_INFO(
+        "Exempted " << StringUtils::formatLargeNumber(_usedNodes.size()) <<
+        " nodes from removal after processing " << StringUtils::formatLargeNumber(_numProcessed) <<
+        " total elements.");
+    }
   }
   LOG_VART(_usedNodes.size());
 
@@ -93,6 +152,9 @@ void SuperfluousNodeRemover::apply(std::shared_ptr<OsmMap>& map)
     nodesWgs84 = &reprojected->getNodes();
   }
 
+  // Now, let's remove any that aren't in our do not remove list.
+
+  _numProcessed = 0;
   for (NodeMap::const_iterator it = nodesWgs84->begin(); it != nodesWgs84->end(); ++it)
   {
     const Node* n = it->second.get();
@@ -112,18 +174,20 @@ void SuperfluousNodeRemover::apply(std::shared_ptr<OsmMap>& map)
         LOG_VART(_bounds);
       }
     }
-  }
-}
+    _numProcessed++;
 
-void SuperfluousNodeRemover::readObject(QDataStream& is)
-{
-  bool hasBounds;
-  is >> hasBounds;
-  if (hasBounds)
-  {
-    double minx, miny, maxx, maxy;
-    is >> minx >> miny >> maxx >> maxy;
-    _bounds = Envelope(minx, maxx, miny, maxy);
+    if (_numAffected > 0 && _numAffected % _taskStatusUpdateInterval == 0)
+    {
+      PROGRESS_INFO(
+        "Removed " << StringUtils::formatLargeNumber(_numAffected) <<
+        " nodes / " << StringUtils::formatLargeNumber(_usedNodes.size()) << " total nodes.");
+    }
+    else if (_numProcessed % _taskStatusUpdateInterval == 0)
+    {
+      PROGRESS_INFO(
+        "Processed " << StringUtils::formatLargeNumber(_numProcessed) <<
+        " nodes / " << StringUtils::formatLargeNumber(nodesWgs84->size()) << " total nodes.");
+    }
   }
 }
 
@@ -140,7 +204,7 @@ long SuperfluousNodeRemover::removeNodes(std::shared_ptr<OsmMap>& map,
   LOG_INFO(nodeRemover.getInitStatusMessage());
   nodeRemover.apply(map);
   LOG_DEBUG(nodeRemover.getCompletedStatusMessage());
-  return nodeRemover.getNumAffected();
+  return nodeRemover.getNumFeaturesAffected();
 }
 
 void SuperfluousNodeRemover::setBounds(const Envelope &bounds)
@@ -148,6 +212,18 @@ void SuperfluousNodeRemover::setBounds(const Envelope &bounds)
   _bounds = bounds;
 }
 
+void SuperfluousNodeRemover::readObject(QDataStream& is)
+{
+  bool hasBounds;
+  is >> hasBounds;
+  if (hasBounds)
+  {
+    double minx, miny, maxx, maxy;
+    is >> minx >> miny >> maxx >> maxy;
+    _bounds = Envelope(minx, maxx, miny, maxy);
+  }
+}
+
 void SuperfluousNodeRemover::writeObject(QDataStream& os) const
 {
   if (_bounds.isNull())
Clone this wiki locally