Skip to content

v0.2.47..v0.2.48 changeset ApiDbReader.cpp

Garret Voltz edited this page Sep 27, 2019 · 1 revision
diff --git a/hoot-core/src/main/cpp/hoot/core/io/ApiDbReader.cpp b/hoot-core/src/main/cpp/hoot/core/io/ApiDbReader.cpp
index e9d1cb7..036615c 100644
--- a/hoot-core/src/main/cpp/hoot/core/io/ApiDbReader.cpp
+++ b/hoot-core/src/main/cpp/hoot/core/io/ApiDbReader.cpp
@@ -33,7 +33,7 @@
 #include <hoot/core/io/ApiDb.h>
 #include <hoot/core/util/Log.h>
 #include <hoot/core/util/StringUtils.h>
-#include <hoot/core/ops/MapCropper.h>
+#include <hoot/core/util/IoUtils.h>
 
 // tgs
 #include <tgs/System/Time.h>
@@ -62,7 +62,9 @@ _totalNumMapWays(0),
 _totalNumMapRelations(0),
 _numNodesRead(0),
 _numWaysRead(0),
-_numRelationsRead(0)
+_numRelationsRead(0),
+_keepImmediatelyConnectedWaysOutsideBounds(
+  ConfigOptions().getConvertBoundingBoxKeepImmediatelyConnectedWaysOutsideBounds())
 {
 }
 
@@ -269,8 +271,6 @@ void ApiDbReader::_updateMetadataOnElement(ElementPtr element)
         logWarnCount++;
       }
     }
-    //I don't think OSM non-hoot metadata tags should be removed here...
-    //tags.remove(MetadataTags::Accuracy());
   }
 }
 
@@ -285,8 +285,9 @@ bool ApiDbReader::_isValidBounds(const Envelope& bounds)
   return true;
 }
 
-void ApiDbReader::_readWaysByNodeIds(OsmMapPtr map, const QSet<QString>& nodeIds, QSet<QString>& wayIds,
-                                     QSet<QString>& additionalNodeIds, long& nodeCount, long& wayCount)
+void ApiDbReader::_readWaysByNodeIds(OsmMapPtr map, const QSet<QString>& nodeIds,
+                                     QSet<QString>& wayIds, QSet<QString>& additionalNodeIds,
+                                     long& nodeCount, long& wayCount)
 {
   LOG_DEBUG("Retrieving way IDs referenced by the selected nodes...");
   std::shared_ptr<QSqlQuery> wayIdItr = _getDatabase()->selectWayIdsByWayNodeIds(nodeIds);
@@ -297,14 +298,40 @@ void ApiDbReader::_readWaysByNodeIds(OsmMapPtr map, const QSet<QString>& nodeIds
     wayIds.insert(QString::number(wayId));
   }
   LOG_VARD(wayIds.size());
+
   if (wayIds.size() > 0)
   {
+    // If the appropriate option is enabled, here we'll add the IDs of all ways that fall outside
+    // of the requested bounds but are directly connected to a way that is being returned by the
+    // query.
+    QSet<QString> connectedWayIds;
+    LOG_VARD(_keepImmediatelyConnectedWaysOutsideBounds);
+    if (_keepImmediatelyConnectedWaysOutsideBounds)
+    {
+      LOG_DEBUG("Retrieving way IDs immediately connected to the current ways...");
+      connectedWayIds = _getDatabase()->selectConnectedWayIds(wayIds);
+      LOG_VARD(connectedWayIds);
+      LOG_VARD(connectedWayIds.size());
+      wayIds.unite(connectedWayIds);
+      LOG_VARD(wayIds);
+      LOG_VARD(wayIds.size());
+    }
+
     LOG_DEBUG("Retrieving ways by way ID...");
     std::shared_ptr<QSqlQuery> wayItr =
       _getDatabase()->selectElementsByElementIdList(wayIds, TableType::Way);
+    const bool tagConnectedWays =
+      ConfigOptions().getConvertBoundingBoxTagImmediatelyConnectedOutOfBoundsWays();
+    LOG_VARD(tagConnectedWays);
     while (wayItr->next())
     {
       WayPtr way = _resultToWay(*wayItr, *map);
+      // If the appropriate option is enabled, we'll tag the connected out of bounds ways that we
+      // just identified. This may be helpful later when creating replacement changesets.
+      if (tagConnectedWays && connectedWayIds.contains(QString::number(way->getId())))
+      {
+        way->getTags().set(MetadataTags::HootConnectedWayOutsideBounds(), "yes");
+      }
       map->addElement(way);
       LOG_VART(way);
       wayCount++;
@@ -320,7 +347,7 @@ void ApiDbReader::_readWaysByNodeIds(OsmMapPtr map, const QSet<QString>& nodeIds
       additionalNodeIds.insert(QString::number(nodeId));
     }
 
-    //subtract nodeIds from additionalWayNodeIds so no dupes get added
+    //subtract nodeIds from additionalNodeIds, so no dupes get added
     LOG_VARD(nodeIds.size());
     LOG_VARD(additionalNodeIds.size());
     additionalNodeIds = additionalNodeIds.subtract(nodeIds);
@@ -349,8 +376,10 @@ void ApiDbReader::_readByBounds(OsmMapPtr map, const Envelope& bounds)
   long boundedWayCount = 0;
   long boundedRelationCount = 0;
 
-  LOG_DEBUG("Retrieving node records within the query bounds...");
+  LOG_DEBUG("Retrieving nodes within the query bounds...");
   std::shared_ptr<QSqlQuery> nodeItr = _getDatabase()->selectNodesByBounds(bounds);
+  // Element IDs are stored as strings to allow inserting them directly into the select query
+  // strings.
   QSet<QString> nodeIds;
   while (nodeItr->next())
   {
@@ -359,11 +388,11 @@ void ApiDbReader::_readByBounds(OsmMapPtr map, const Envelope& bounds)
     LOG_VART(node);
     map->addElement(node);
     boundedNodeCount++;
-    //Don't use the mapped id from the node object here, b/c we want don't want to use mapped ids
-    //with any queries.  Mapped ids may not exist yet.
+    // Don't use the mapped id from the node object here, b/c we want don't want to use mapped ids
+    // with any queries, because mapped ids may not exist yet.
     const long nodeId = resultIterator.value(0).toLongLong();
     LOG_VART(ElementId(ElementType::Node, nodeId));
-    nodeIds.insert( QString::number(nodeId));
+    nodeIds.insert(QString::number(nodeId));
   }
   LOG_VARD(nodeIds.size());
 
@@ -376,6 +405,10 @@ void ApiDbReader::_readByBounds(OsmMapPtr map, const Envelope& bounds)
       _readWaysByNodeIds(
         map, nodeIds, wayIds, additionalWayNodeIds, boundedNodeCount, boundedWayCount);
       nodeIds.unite(additionalWayNodeIds);
+      LOG_VARD(nodeIds.size());
+      LOG_VARD(wayIds);
+      LOG_VARD(wayIds.size());
+
       LOG_DEBUG("Retrieving relation IDs referenced by the selected ways and nodes...");
       QSet<QString> relationIds;
       assert(nodeIds.size() > 0);
@@ -398,6 +431,7 @@ void ApiDbReader::_readByBounds(OsmMapPtr map, const Envelope& bounds)
         }
       }
       LOG_VARD(relationIds.size());
+
       //  Iterate all relations (and sub-relations) that are "within" the bounds
       QSet<QString> completedRelationIds;
       while (relationIds.size() > 0)
@@ -405,6 +439,7 @@ void ApiDbReader::_readByBounds(OsmMapPtr map, const Envelope& bounds)
         QSet<QString> newNodes;
         QSet<QString> newWays;
         QSet<QString> newRelations;
+
         LOG_DEBUG("Retrieving relations by relation ID...");
         std::shared_ptr<QSqlQuery> relationItr =
           _getDatabase()->selectElementsByElementIdList(relationIds, TableType::Relation);
@@ -435,8 +470,10 @@ void ApiDbReader::_readByBounds(OsmMapPtr map, const Envelope& bounds)
           //  Keep track of all relations that have been added to the map so we don't try them again
           completedRelationIds.insert(QString::number(relation->getId()));
         }
+
         //  Clear the relations that we are iterating on, it is then filled with new relations later
         relationIds.clear();
+
         //  Iterate any new nodes that are members of relations that need to be queried
         newNodes = newNodes.subtract(nodeIds);
         if (newNodes.size() > 0)
@@ -455,11 +492,13 @@ void ApiDbReader::_readByBounds(OsmMapPtr map, const Envelope& bounds)
             nodeIds.insert(QString::number(nodeId));
           }
         }
+
         //  Iterate any new ways that are members of relations that need to be queried
         newWays = newWays.subtract(wayIds);
         if (newWays.size() > 0)
         {
           QSet<QString> additionalNodeIds;
+
           LOG_DEBUG("Retrieving ways by way ID...");
           std::shared_ptr<QSqlQuery> wayItr =
             _getDatabase()->selectElementsByElementIdList(newWays, TableType::Way);
@@ -481,7 +520,7 @@ void ApiDbReader::_readByBounds(OsmMapPtr map, const Envelope& bounds)
             additionalNodeIds.insert(QString::number(nodeId));
           }
 
-          //subtract nodeIds from additionalWayNodeIds so no dupes get added
+          //subtract nodeIds from additionalWayNodeIds, so no dupes get added
           LOG_VARD(nodeIds.size());
           LOG_VARD(additionalNodeIds.size());
           additionalNodeIds = additionalNodeIds.subtract(nodeIds);
@@ -490,7 +529,8 @@ void ApiDbReader::_readByBounds(OsmMapPtr map, const Envelope& bounds)
           if (additionalNodeIds.size() > 0)
           {
             LOG_DEBUG(
-              "Retrieving nodes falling outside of the query bounds but belonging to a selected way...");
+              "Retrieving nodes falling outside of the query bounds but belonging to a selected " <<
+              "way...");
             std::shared_ptr<QSqlQuery> additionalWayNodeItr =
               _getDatabase()->selectElementsByElementIdList(additionalNodeIds, TableType::Node);
             while (additionalWayNodeItr->next())
@@ -502,6 +542,7 @@ void ApiDbReader::_readByBounds(OsmMapPtr map, const Envelope& bounds)
             }
           }
         }
+
         //  Get the set of new relations found minus anything that has already been completed
         relationIds = newRelations.subtract(completedRelationIds);
       }
@@ -517,25 +558,17 @@ void ApiDbReader::_readByBounds(OsmMapPtr map, const Envelope& bounds)
 
   // The default behavior of the db bounded read is to return the entirety of features found
   // within the bounds, even if sections of those features exist outside the bounds. Only run the
-  // crop operation if the crop related option are different than the default behavior. Clearly, it
-  // would be more efficient to run a different query to pull the features back the way we want
-  // them from the start and skip this step completely. That's possibly something to look into
-  // doing in the future.
+  // crop operation if the crop related options are different than the default behavior. Clearly, it
+  // would be more efficient to run a different set of initial queries to pull the features back
+  // already cropped the way we want them from the start and skip this step completely. That's
+  // possibly an optimization to look into doing in the future.
   ConfigOptions conf;
   if (!conf.getConvertBoundingBoxKeepEntireFeaturesCrossingBounds() ||
        conf.getConvertBoundingBoxKeepOnlyFeaturesInsideBounds())
-  {
-    LOG_INFO("Applying bounds filtering to ingested data: " << _bounds << "...");
-    MapCropper cropper(_bounds);
-    LOG_INFO(cropper.getInitStatusMessage());
-    // We don't reuse MapCropper's version of these options, since we want the freedom to have
-    // different default values than what MapCropper uses.
-    cropper.setKeepEntireFeaturesCrossingBounds(
-      ConfigOptions().getConvertBoundingBoxKeepEntireFeaturesCrossingBounds());
-    cropper.setKeepOnlyFeaturesInsideBounds(
-      ConfigOptions().getConvertBoundingBoxKeepOnlyFeaturesInsideBounds());
-    cropper.apply(map);
-    LOG_INFO(cropper.getCompletedStatusMessage());
+  { 
+    // We've already handled keeping immediately connected oob ways during the query, so don't need
+    // to worry about it here.
+    IoUtils::cropToBounds(map, _bounds);
   }
 
   LOG_DEBUG("Current map:");
Clone this wiki locally