Skip to content

v0.2.53..v0.2.54 changeset RemoveEmptyAreasVisitor.cpp

Garret Voltz edited this page Mar 31, 2020 · 1 revision
diff --git a/hoot-core/src/main/cpp/hoot/core/visitors/RemoveEmptyAreasVisitor.cpp b/hoot-core/src/main/cpp/hoot/core/visitors/RemoveEmptyAreasVisitor.cpp
index 9ca0347..1e68e1b 100644
--- a/hoot-core/src/main/cpp/hoot/core/visitors/RemoveEmptyAreasVisitor.cpp
+++ b/hoot-core/src/main/cpp/hoot/core/visitors/RemoveEmptyAreasVisitor.cpp
@@ -34,7 +34,9 @@
 #include <hoot/core/elements/ElementConverter.h>
 #include <hoot/core/util/Factory.h>
 #include <hoot/core/criterion/AreaCriterion.h>
+#include <hoot/core/criterion/BuildingCriterion.h>
 #include <hoot/core/util/StringUtils.h>
+#include <hoot/core/util/GeometryUtils.h>
 
 using namespace geos::geom;
 namespace hoot
@@ -42,13 +44,20 @@ namespace hoot
 
 HOOT_FACTORY_REGISTER(ElementVisitor, RemoveEmptyAreasVisitor)
 
-RemoveEmptyAreasVisitor::RemoveEmptyAreasVisitor()
+RemoveEmptyAreasVisitor::RemoveEmptyAreasVisitor() :
+_requireAreaForPolygonConversion(true)
 {
 }
 
+void RemoveEmptyAreasVisitor::setConfiguration(const Settings& conf)
+{
+  _requireAreaForPolygonConversion = ConfigOptions(conf).getConvertRequireAreaForPolygon();
+  LOG_VARD(_requireAreaForPolygonConversion);
+}
+
 void RemoveEmptyAreasVisitor::visit(const ConstElementPtr& e)
 {
-  // no need to visit nodes.
+  // no need to visit nodes
   if (e->getElementType() != ElementType::Node)
   {
     std::shared_ptr<Element> ee = _map->getElement(e->getElementId());
@@ -61,8 +70,15 @@ void RemoveEmptyAreasVisitor::visit(const std::shared_ptr<Element>& e)
   if (!_ec.get())
   {
     _ec.reset(new ElementConverter(_map->shared_from_this()));
+    LOG_VARD(_requireAreaForPolygonConversion);
+    // TODO: This is directly related to the relation change commented out below. If this logic
+    // isn't needed, then we can remove implementation of the Configurable interface.
+    _ec->setRequireAreaForPolygonConversion(_requireAreaForPolygonConversion);
   }
 
+  LOG_VART(e->getElementId());
+  //LOG_VART(e);
+
   LOG_VART(AreaCriterion().isSatisfied(e));
   if (AreaCriterion().isSatisfied(e))
   {
@@ -70,10 +86,50 @@ void RemoveEmptyAreasVisitor::visit(const std::shared_ptr<Element>& e)
     LOG_VART(g.get());
     if (g.get())
     {
+      LOG_VART(GeometryUtils::geometryTypeIdToString(g->getGeometryTypeId()));
       LOG_VART(g->getArea());
     }
+    bool removeArea = false;
     if (g.get() && g->getArea() == 0.0)
     {
+      if (e->getElementType() == ElementType::Relation)
+      {
+        // require that all way children of this relation have empty areas in order to remove it
+        ConstRelationPtr relation = std::dynamic_pointer_cast<const Relation>(e);
+        const std::vector<RelationData::Entry>& members = relation->getMembers();
+        bool anyMemberHasPositiveArea = false;
+        for (size_t i = 0; i < members.size(); i++)
+        {
+          const RelationData::Entry& member = members[i];
+          // not going down more than one relation level here, but that may eventually need to be
+          // done; Also, should we also require that each child way also satisfy AreaCriterion?
+          if (member.getElementId().getType() == ElementType::Way)
+          {
+            ConstWayPtr memberWay =
+              std::dynamic_pointer_cast<const Way>(_map->getElement(member.getElementId()));
+            if (memberWay)
+            {
+              std::shared_ptr<Geometry> wayGeom = _ec->convertToGeometry(memberWay);
+              if (wayGeom && wayGeom->getArea() > 0.0)
+              {
+                LOG_TRACE(memberWay->getElementId() << " has positive area.");
+                anyMemberHasPositiveArea = true;
+                break;
+              }
+            }
+          }
+        }
+        removeArea = !anyMemberHasPositiveArea;
+      }
+      else
+      {
+        removeArea = true;
+      } 
+    }
+
+    if (removeArea)
+    {
+      LOG_TRACE("Recursively removing empty area: " << e->getElementId() << "...");
       RecursiveElementRemover(e->getElementId()).apply(_map->shared_from_this());
       _numAffected++;
     }
@@ -88,5 +144,14 @@ void RemoveEmptyAreasVisitor::visit(const std::shared_ptr<Element>& e)
   }
 }
 
+QStringList RemoveEmptyAreasVisitor::getCriteria() const
+{
+  QStringList criteria;
+  // need to also add building here for unecessary conflation op removal purposes, since
+  // AreaCriterion includes buildings in some instances
+  criteria.append(QString::fromStdString(BuildingCriterion::className()));
+  criteria.append(QString::fromStdString(AreaCriterion::className()));
+  return criteria;
+}
 
 }
Clone this wiki locally