Skip to content

v0.2.49..v0.2.50 changeset NodeDensityTilesCmd.cpp

Garret Voltz edited this page Nov 6, 2019 · 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
new file mode 100644
index 0000000..3e74c3f
--- /dev/null
+++ b/hoot-core/src/main/cpp/hoot/core/cmd/NodeDensityTilesCmd.cpp
@@ -0,0 +1,205 @@
+/*
+ * This file is part of Hootenanny.
+ *
+ * Hootenanny is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --------------------------------------------------------------------
+ *
+ * The following copyright notices are generated automatically. If you
+ * have a new notice to add, please use the format:
+ * " * @copyright Copyright ..."
+ * 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/)
+ */
+
+// Hoot
+#include <hoot/core/cmd/BaseCommand.h>
+#include <hoot/core/elements/OsmMap.h>
+#include <hoot/core/io/ApiDbReader.h>
+#include <hoot/core/io/OsmMapReader.h>
+#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/util/Log.h>
+#include <hoot/core/visitors/CalculateMapBoundsVisitor.h>
+
+namespace hoot
+{
+
+class NodeDensityTilesCmd : public BaseCommand
+{
+
+public:
+
+  static std::string className() { return "hoot::NodeDensityTilesCmd"; }
+
+  NodeDensityTilesCmd() { }
+
+  virtual QString getName() const override { return "node-density-tiles"; }
+
+  virtual QString getDescription() const override
+  { return "Calculates bounding box partitions based on a map's node density"; }
+
+  virtual int runSimple(QStringList& args) override
+  {
+    if (args.size() < 2)
+    {
+      std::cout << getHelp() << std::endl << std::endl;
+      throw HootException(
+        QString("%1 takes at least two parameters.").arg(getName()));
+    }
+
+    QStringList inputs;
+    const QString input = args[0];
+    LOG_VARD(input);
+    if (!input.contains(";"))
+    {
+      inputs.append(input);
+    }
+    else
+    {
+      //multiple inputs
+      inputs = input.split(";");
+    }
+    LOG_VARD(inputs);
+
+    const QString output = args[1];
+    if (!output.toLower().endsWith(".geojson") && !output.toLower().endsWith(".osm"))
+    {
+      throw IllegalArgumentException(
+        "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
+
+    long maxNodesPerTile = 1000;
+    if (args.size() > 2)
+    {
+      bool parseSuccess = false;
+      maxNodesPerTile = args[2].toLong(&parseSuccess);
+      if (!parseSuccess || maxNodesPerTile < 1)
+      {
+        throw HootException("Invalid maximum nodes per tile value: " + args[2]);
+      }
+    }
+    LOG_VARD(maxNodesPerTile);
+
+    double pixelSize = 0.001; //.1km?
+    if (args.size() > 2)
+    {
+      bool parseSuccess = false;
+      pixelSize = args[3].toDouble(&parseSuccess);
+      if (!parseSuccess || pixelSize <= 0.0)
+      {
+        throw HootException("Invalid pixel size value: " + args[3]);
+      }
+    }
+    LOG_VARD(pixelSize);
+
+    int randomSeed = -1;
+    if (args.contains("--random") && args.size() > 4)
+    {
+      bool parseSuccess = false;
+      randomSeed = args[4].toInt(&parseSuccess);
+      if (!parseSuccess || randomSeed < -1)
+      {
+        throw HootException("Invalid random seed value: " + args[4]);
+      }
+    }
+    LOG_VARD(randomSeed);
+
+    conf().set(ConfigOptions().getIdGeneratorKey(), "hoot::PositiveIdGenerator");
+
+    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);
+
+    if (output.toLower().endsWith(".geojson"))
+    {
+      TileUtils::writeTilesToGeoJson(tiles, nodeCounts, output, inputMap->getSource(),
+                                     args.contains("--random"), randomSeed);
+    }
+    else
+    {
+      TileUtils::writeTilesToOsm(tiles, nodeCounts, output, args.contains("--random"), randomSeed);
+    }
+
+    return 0;
+  }
+
+private:
+
+  OsmMapPtr _readInputs(const QStringList& inputs)
+  {
+    const bool bboxSpecified =
+      !ConfigOptions().getConvertBoundingBox().trimmed().isEmpty() ||
+      !ConfigOptions().getConvertBoundingBoxHootApiDatabase().trimmed().isEmpty() ||
+      !ConfigOptions().getConvertBoundingBoxOsmApiDatabase().trimmed().isEmpty();
+
+    OsmMapPtr map(new OsmMap());
+    for (int i = 0; i < inputs.size(); i++)
+    {
+      const QString input = inputs.at(i);
+      std::shared_ptr<OsmMapReader> reader =
+        OsmMapReaderFactory::createReader(input, true, Status::Unknown1);
+
+      std::shared_ptr<Boundable> boundable = std::dynamic_pointer_cast<Boundable>(reader);
+      if (bboxSpecified && !boundable)
+      {
+        // TODO: need a test for this
+        throw IllegalArgumentException(
+          "Reader for " + input + " must implement Boundable when the " +
+          "convert.bounding.box configuration option is specified.");
+      }
+
+      std::shared_ptr<ApiDbReader> apiDbReader =
+        std::dynamic_pointer_cast<ApiDbReader>(reader);
+      if (apiDbReader)
+      {
+        //the tiles calculation is only concerned with nodes, and the only readers capable of
+        //filtering down to nodes up front right now are the api db readers; more importantly,
+        //setting this to true also prevents any features from being returned outside of
+        //convert.bounding.box, if it was specified (ways partially inside the bounds, etc.)
+        apiDbReader->setReturnNodesOnly(true);
+      }
+
+      reader->open(input);
+      reader->read(map);
+    }
+    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;
+  }
+};
+
+HOOT_FACTORY_REGISTER(Command, NodeDensityTilesCmd)
+
+}
Clone this wiki locally