Skip to content

v0.2.54..v0.2.55 changeset NodeDensityTilesCmd.cpp

Garret Voltz edited this page Aug 14, 2020 · 1 revision
diff --git a/hoot-core/src/main/cpp/hoot/core/cmd/NodeDensityTilesCmd.cpp b/hoot-core/src/main/cpp/hoot/core/cmd/NodeDensityTilesCmd.cpp
index 3e74c3f..9df08c6 100644
--- a/hoot-core/src/main/cpp/hoot/core/cmd/NodeDensityTilesCmd.cpp
+++ b/hoot-core/src/main/cpp/hoot/core/cmd/NodeDensityTilesCmd.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/)
  */
 
 // Hoot
@@ -33,10 +33,13 @@
 #include <hoot/core/io/OsmMapReaderFactory.h>
 #include <hoot/core/io/OsmMapWriterFactory.h>
 #include <hoot/core/util/Factory.h>
-#include <hoot/core/conflate/tile/TileUtils.h>
-#include <hoot/core/util/OpenCv.h>
+#include <hoot/core/conflate/tile/NodeDensityTileBoundsCalculator.h>
 #include <hoot/core/util/Log.h>
-#include <hoot/core/visitors/CalculateMapBoundsVisitor.h>
+#include <hoot/core/io/TileBoundsWriter.h>
+#include <hoot/core/util/StringUtils.h>
+
+// Qt
+#include <QElapsedTimer>
 
 namespace hoot
 {
@@ -57,10 +60,13 @@ public:
 
   virtual int runSimple(QStringList& args) override
   {
+    QElapsedTimer timer;
+    timer.start();
+
     if (args.size() < 2)
     {
       std::cout << getHelp() << std::endl << std::endl;
-      throw HootException(
+      throw IllegalArgumentException(
         QString("%1 takes at least two parameters.").arg(getName()));
     }
 
@@ -73,7 +79,7 @@ public:
     }
     else
     {
-      //multiple inputs
+      // multiple inputs
       inputs = input.split(";");
     }
     LOG_VARD(inputs);
@@ -82,46 +88,108 @@ public:
     if (!output.toLower().endsWith(".geojson") && !output.toLower().endsWith(".osm"))
     {
       throw IllegalArgumentException(
-        "Invalid output file format: " + output + ".  Only the GeoJSON (.geojson) and OSM " +
+        "Invalid output file format: " + output + ". Only the GeoJSON (.geojson) and OSM " +
         "(.osm) output formats are supported.");
     }
     LOG_VARD(output);
 
-    //if either of max nodes per tile or pixel size is specified, then both must be specified
+    // optional parameters
 
-    long maxNodesPerTile = 1000;
-    if (args.size() > 2)
+    int maxNodesPerTile = 1000;
+    if (args.contains("--maxNodesPerTile"))
     {
+      const int optionNameIndex = args.indexOf("--maxNodesPerTile");
       bool parseSuccess = false;
-      maxNodesPerTile = args[2].toLong(&parseSuccess);
+      const QString optionStrVal = args.at(optionNameIndex + 1).trimmed();
+      maxNodesPerTile = optionStrVal.toInt(&parseSuccess);
       if (!parseSuccess || maxNodesPerTile < 1)
       {
-        throw HootException("Invalid maximum nodes per tile value: " + args[2]);
+        throw IllegalArgumentException(
+          "Invalid maximum node count per tile value: " + optionStrVal);
       }
+      args.removeAt(optionNameIndex + 1);
+      args.removeAt(optionNameIndex);
     }
     LOG_VARD(maxNodesPerTile);
 
-    double pixelSize = 0.001; //.1km?
-    if (args.size() > 2)
+    double pixelSize = 0.001; // .1km?
+    if (args.contains("--pixel-size"))
     {
+      const int optionNameIndex = args.indexOf("--pixel-size");
       bool parseSuccess = false;
-      pixelSize = args[3].toDouble(&parseSuccess);
+      const QString optionStrVal = args.at(optionNameIndex + 1).trimmed();
+      pixelSize = optionStrVal.toDouble(&parseSuccess);
       if (!parseSuccess || pixelSize <= 0.0)
       {
-        throw HootException("Invalid pixel size value: " + args[3]);
+        throw IllegalArgumentException("Invalid pixel size value: " + optionStrVal);
       }
+      args.removeAt(optionNameIndex + 1);
+      args.removeAt(optionNameIndex);
     }
     LOG_VARD(pixelSize);
 
-    int randomSeed = -1;
-    if (args.contains("--random") && args.size() > 4)
+    int maxAttempts = 3;
+    if (args.contains("--maxAttempts"))
     {
+      const int optionNameIndex = args.indexOf("--maxAttempts");
       bool parseSuccess = false;
-      randomSeed = args[4].toInt(&parseSuccess);
+      const QString optionStrVal = args.at(optionNameIndex + 1).trimmed();
+      maxAttempts = optionStrVal.toInt(&parseSuccess);
+      if (!parseSuccess || maxAttempts < 1)
+      {
+        throw IllegalArgumentException("Invalid maximum attempts value: " + optionStrVal);
+      }
+      args.removeAt(optionNameIndex + 1);
+      args.removeAt(optionNameIndex);
+    }
+    LOG_VARD(maxAttempts);
+
+    int maxTimePerAttempt = -1;
+    if (args.contains("--maxTimePerAttempt"))
+    {
+      const int optionNameIndex = args.indexOf("--maxTimePerAttempt");
+      bool parseSuccess = false;
+      const QString optionStrVal = args.at(optionNameIndex + 1).trimmed();
+      maxTimePerAttempt = optionStrVal.toInt(&parseSuccess);
+      if (!parseSuccess || maxTimePerAttempt < -1)
+      {
+        throw IllegalArgumentException("Invalid maximum time per attempt value: " + optionStrVal);
+      }
+      args.removeAt(optionNameIndex + 1);
+      args.removeAt(optionNameIndex);
+    }
+    LOG_VARD(maxTimePerAttempt);
+
+    int pixelSizeAutoReductionFactor = 10;
+    if (args.contains("--pixelSizeReductionFactor"))
+    {
+      const int optionNameIndex = args.indexOf("--pixelSizeReductionFactor");
+      bool parseSuccess = false;
+      const QString optionStrVal = args.at(optionNameIndex + 1).trimmed();
+      pixelSizeAutoReductionFactor = optionStrVal.toInt(&parseSuccess);
+      if (!parseSuccess || pixelSizeAutoReductionFactor < 1)
+      {
+        throw IllegalArgumentException(
+          "Invalid pixel size automatic reduction factor value: " + optionStrVal);
+      }
+      args.removeAt(optionNameIndex + 1);
+      args.removeAt(optionNameIndex);
+    }
+    LOG_VARD(pixelSizeAutoReductionFactor);
+
+    int randomSeed = -1;
+    if (args.contains("--random") && args.contains("--randomSeed"))
+    { 
+      const int optionNameIndex = args.indexOf("--randomSeed");
+      bool parseSuccess = false;
+      const QString optionStrVal = args.at(optionNameIndex + 1).trimmed();
+      randomSeed = optionStrVal.toInt(&parseSuccess);
       if (!parseSuccess || randomSeed < -1)
       {
-        throw HootException("Invalid random seed value: " + args[4]);
+        throw IllegalArgumentException("Invalid random seed value: " + optionStrVal);
       }
+      args.removeAt(optionNameIndex + 1);
+      args.removeAt(optionNameIndex);
     }
     LOG_VARD(randomSeed);
 
@@ -129,24 +197,42 @@ public:
 
     OsmMapPtr inputMap = _readInputs(inputs);
 
-    long minNodeCountInOneTile = 0;
-    long maxNodeCountInOneTile = 0;
-    std::vector<std::vector<long>> nodeCounts;
-    const std::vector<std::vector<geos::geom::Envelope>> tiles =
-      TileUtils::calculateTiles(
-        maxNodesPerTile, pixelSize, inputMap, minNodeCountInOneTile, maxNodeCountInOneTile,
-        nodeCounts);
+    NodeDensityTileBoundsCalculator tileCalc;
+    tileCalc.setPixelSize(pixelSize);
+    tileCalc.setMaxNodesPerTile(maxNodesPerTile);
+    //tileCalc.setSlop(0.1); // tweak this?
+    tileCalc.setMaxNumTries(maxAttempts);
+    tileCalc.setMaxTimePerAttempt(maxTimePerAttempt);
+    tileCalc.setPixelSizeRetryReductionFactor(pixelSizeAutoReductionFactor);
+    tileCalc.calculateTiles(inputMap);
+    const std::vector<std::vector<geos::geom::Envelope>> tiles = tileCalc.getTiles();
+    const std::vector<std::vector<long>> nodeCounts = tileCalc.getNodeCounts();
 
     if (output.toLower().endsWith(".geojson"))
     {
-      TileUtils::writeTilesToGeoJson(tiles, nodeCounts, output, inputMap->getSource(),
-                                     args.contains("--random"), randomSeed);
+      TileBoundsWriter::writeTilesToGeoJson(
+        tiles, nodeCounts, output, inputMap->getSource(), args.contains("--random"), randomSeed);
     }
     else
     {
-      TileUtils::writeTilesToOsm(tiles, nodeCounts, output, args.contains("--random"), randomSeed);
+      TileBoundsWriter::writeTilesToOsm(
+        tiles, nodeCounts, output, args.contains("--random"), randomSeed);
     }
 
+    LOG_STATUS(
+      "Node density tiles calculated in " << StringUtils::millisecondsToDhms(timer.elapsed()) << ".");
+    LOG_STATUS("Number of calculated tiles: " << StringUtils::formatLargeNumber(tiles.size()));
+    LOG_STATUS(
+      "Maximum node count in a single tile: " <<
+      StringUtils::formatLargeNumber(tileCalc.getMaxNodeCountInOneTile()));
+    LOG_STATUS(
+      "Mininum node count in a single tile: " <<
+      StringUtils::formatLargeNumber(tileCalc.getMinNodeCountInOneTile()));
+    LOG_STATUS("Pixel size used: " << tileCalc.getPixelSize());
+    LOG_STATUS(
+      "Maximum node count per tile used: " <<
+      StringUtils::formatLargeNumber(tileCalc.getMaxNodesPerTile()));
+
     return 0;
   }
 
@@ -191,9 +277,6 @@ private:
     }
     LOG_VARD(map->getNodeCount());
 
-//    OGREnvelope envelope = CalculateMapBoundsVisitor::getBounds(map);
-//    std::shared_ptr<geos::geom::Envelope> tempEnv(GeometryUtils::toEnvelope(envelope));
-//    LOG_VARD(tempEnv->toString());
     OsmMapWriterFactory::writeDebugMap(map);
 
     return map;
Clone this wiki locally