Skip to content

v0.2.48..v0.2.49 changeset RdpWayGeneralizerTest.cpp

Garret Voltz edited this page Oct 2, 2019 · 1 revision
diff --git a/hoot-core-test/src/test/cpp/hoot/core/algorithms/RdpWayGeneralizerTest.cpp b/hoot-core-test/src/test/cpp/hoot/core/algorithms/RdpWayGeneralizerTest.cpp
new file mode 100644
index 0000000..ae2fea7
--- /dev/null
+++ b/hoot-core-test/src/test/cpp/hoot/core/algorithms/RdpWayGeneralizerTest.cpp
@@ -0,0 +1,313 @@
+/*
+ * 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) 2014, 2015, 2017, 2018, 2019 DigitalGlobe (http://www.digitalglobe.com/)
+ */
+// CPP Unit
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+#include <cppunit/TestAssert.h>
+#include <cppunit/TestFixture.h>
+
+// boost
+#include <boost/random/uniform_real.hpp>
+#include <boost/random/linear_congruential.hpp>
+
+// Hoot
+#include <hoot/core/elements/OsmMap.h>
+#include <hoot/core/TestUtils.h>
+#include <hoot/core/io/OsmXmlWriter.h>
+#include <hoot/core/util/Log.h>
+#include <hoot/core/util/MapProjector.h>
+#include <hoot/core/algorithms/RdpWayGeneralizer.h>
+
+using namespace geos::geom;
+
+namespace hoot
+{
+
+class RdpWayGeneralizerTest : public HootTestFixture
+{
+  CPPUNIT_TEST_SUITE(RdpWayGeneralizerTest);
+  CPPUNIT_TEST(runPerpendicularDistanceTest);
+  CPPUNIT_TEST(runCalcPointsInput1aTest);
+  CPPUNIT_TEST(runCalcPointsInput1bTest);
+  CPPUNIT_TEST(runCalcPointsInput2aTest);
+  CPPUNIT_TEST(runCalcPointsInput2bTest);
+  CPPUNIT_TEST(runGeneralizeWayInput1NoInformationNodesTest);
+  CPPUNIT_TEST(runGeneralizeWayInput1WithInformationNodesTest);
+  CPPUNIT_TEST(runInvalidEpsilonTest);
+  CPPUNIT_TEST_SUITE_END();
+
+public:
+
+  QMap<QString, QList<ConstNodePtr>> _inputPointsCache;
+  QMap<QString, QList<Coordinate>> _inputCoordsCache;
+
+  RdpWayGeneralizerTest()
+    : HootTestFixture("test-files/algorithms/RdpWayGeneralizerTest/",
+                      "test-output/algorithms/RdpWayGeneralizerTest/")
+  {
+    setResetType(ResetBasic);
+  }
+
+  QList<ConstNodePtr> readPoints(const QString& filePath)
+  {
+    if (_inputPointsCache.contains(filePath))
+    {
+      return _inputPointsCache[filePath];
+    }
+
+    QFile file(filePath);
+    if (file.open(QIODevice::ReadOnly) == false)
+    {
+      throw HootException(QString("Error opening %1").arg(filePath));
+    }
+
+    QTextStream textStream(&file);
+    QList<ConstNodePtr> points;
+    OsmMapPtr map(new OsmMap());
+    while (!textStream.atEnd())
+    {
+      QStringList pointParts = textStream.readLine().split(",");
+      ConstNodePtr node(
+        new Node(
+          Status::Unknown1,
+          map->createNextNodeId(),
+          pointParts.at(0).toDouble(),
+          pointParts.at(1).toDouble(),
+          15.0));
+      points.append(node);
+    }
+    file.close();
+
+    _inputPointsCache[filePath] = points;
+    return points;
+  }
+
+  QList<Coordinate> readCoords(const QString& filePath)
+  {
+    if (_inputCoordsCache.contains(filePath))
+    {
+      return _inputCoordsCache[filePath];
+    }
+
+    QFile file(filePath);
+    if (file.open(QIODevice::ReadOnly) == false)
+    {
+      throw HootException(QString("Error opening %1 for writing").arg(filePath));
+    }
+
+    QTextStream textStream(&file);
+    QList<Coordinate> coordinates;
+    while (!textStream.atEnd())
+    {
+      QStringList pointParts = textStream.readLine().split(",");
+      coordinates.append(Coordinate(pointParts.at(0).toDouble(), pointParts.at(1).toDouble()));
+    }
+    file.close();
+
+    if (!_inputCoordsCache.contains(filePath))
+    {
+      _inputCoordsCache[filePath] = coordinates;
+    }
+    return coordinates;
+  }
+
+  void writeMap(OsmMapPtr map, const QString& outFileName)
+  {
+    OsmXmlWriter writer;
+    writer.setIncludeHootInfo(true);
+    writer.write(map, outFileName);
+  }
+
+  void writePointOutput(const QList<ConstNodePtr>& points, const QString& outFileName)
+  {
+    OsmMapPtr map(new OsmMap());
+
+    //points will be empty for the generalize calls with way inputs instead of points
+    for (QList<ConstNodePtr>::const_iterator it = points.constBegin();
+         it != points.constEnd(); ++it)
+    {
+      NodePtr nodeCopy(new Node(*(*it).get()));
+      map->addNode(nodeCopy);
+    }
+
+    writeMap(map, outFileName);
+  }
+
+  void runPerpendicularDistanceTest()
+  {
+    const QList<ConstNodePtr>& inputPoints =
+      readPoints(_inputPath + "RdpWayGeneralizerTestDataset1.txt");
+    CPPUNIT_ASSERT_EQUAL(197, inputPoints.size());
+
+    RdpWayGeneralizer generalizer(0.3);
+    CPPUNIT_ASSERT_DOUBLES_EQUAL(
+      2.53015,
+      generalizer._getPerpendicularDistanceBetweenSplitNodeAndImaginaryLine(
+        inputPoints.at(1), inputPoints.at(0), inputPoints.at(inputPoints.size() - 1)),
+      0.0001);
+  }
+
+  void runCalcPointsInput1aTest()
+  {
+    const QList<ConstNodePtr>& inputPoints =
+      readPoints(_inputPath + "RdpWayGeneralizerTestDataset1.txt");
+    CPPUNIT_ASSERT_EQUAL(197, inputPoints.size());
+
+    RdpWayGeneralizer generalizer(0.1);
+    const QList<ConstNodePtr>& outputPoints =
+      generalizer._getGeneralizedPoints(inputPoints);
+    CPPUNIT_ASSERT_EQUAL(148, outputPoints.size());
+    QString outFile = _outputPath + "runCalcPointsInput1aTest-out.osm";
+    writePointOutput(outputPoints, outFile);
+    HOOT_FILE_EQUALS(_inputPath + "runCalcPointsInput1aTest-out.osm", outFile);
+  }
+
+  void runCalcPointsInput1bTest()
+  {
+    const QList<ConstNodePtr>& inputPoints =
+      readPoints(_inputPath + "RdpWayGeneralizerTestDataset1.txt");
+    CPPUNIT_ASSERT_EQUAL(197, inputPoints.size());
+
+    RdpWayGeneralizer generalizer(5.9);
+    const QList<ConstNodePtr>& outputPoints =
+      generalizer._getGeneralizedPoints(inputPoints);
+    CPPUNIT_ASSERT_EQUAL(22, outputPoints.size());
+    QString outFile = _outputPath + "runCalcPointsInput1bTest-out.osm";
+    writePointOutput(outputPoints, outFile);
+    HOOT_FILE_EQUALS(_inputPath + "runCalcPointsInput1bTest-out.osm", outFile);
+  }
+
+  void runCalcPointsInput2aTest()
+  {
+    const QList<ConstNodePtr>& inputPoints =
+      readPoints(_inputPath + "RdpWayGeneralizerTestDataset2.txt");
+    CPPUNIT_ASSERT_EQUAL(77, inputPoints.size());
+
+    RdpWayGeneralizer generalizer(0.1);
+    const QList<ConstNodePtr>& outputPoints =
+      generalizer._getGeneralizedPoints(inputPoints);
+    CPPUNIT_ASSERT_EQUAL(48, outputPoints.size());
+    QString outFile = _outputPath + "runCalcPointsInput2aTest-out.osm";
+    writePointOutput(outputPoints, outFile);
+    HOOT_FILE_EQUALS(_inputPath + "runCalcPointsInput2aTest-out.osm", outFile);
+  }
+
+  void runCalcPointsInput2bTest()
+  {
+    const QList<ConstNodePtr>& inputPoints =
+      readPoints(_inputPath + "RdpWayGeneralizerTestDataset2.txt");
+    CPPUNIT_ASSERT_EQUAL(77, inputPoints.size());
+
+    RdpWayGeneralizer generalizer(5.9);
+    const QList<ConstNodePtr>& outputPoints =
+      generalizer._getGeneralizedPoints(inputPoints);
+    CPPUNIT_ASSERT_EQUAL(4, outputPoints.size());
+    QString outFile = _outputPath + "runCalcPointsInput2bTest-out.osm";
+    writePointOutput(outputPoints, outFile);
+    HOOT_FILE_EQUALS(_inputPath + "runCalcPointsInput2bTest-out.osm", outFile);
+  }
+
+  void runGeneralizeWayInput1NoInformationNodesTest()
+  {
+    OsmMapPtr map(new OsmMap());
+    QList<Coordinate> inputCoords =
+      readCoords(_inputPath + "RdpWayGeneralizerTestDataset1.txt");
+    CPPUNIT_ASSERT_EQUAL(197, inputCoords.size());
+    inputCoords.append(Coordinate::getNull());
+    WayPtr way = TestUtils::createWay(map, Status::Unknown1, inputCoords.toVector().data(), 1, "");
+    CPPUNIT_ASSERT_EQUAL((size_t)197, way->getNodeIds().size());
+
+    RdpWayGeneralizer generalizer(0.1);
+    generalizer.setOsmMap(map.get());
+    generalizer.generalize(way);
+
+    CPPUNIT_ASSERT_EQUAL((size_t)197, map->getNodes().size());
+    CPPUNIT_ASSERT_EQUAL((size_t)148, way->getNodeIds().size());
+    const QString outFile = _outputPath + "runGeneralizeWayInput1NoInformationNodesTest-out.osm";
+    writeMap(map, outFile);
+    HOOT_FILE_EQUALS(_inputPath + "runGeneralizeWayInput1NoInformationNodesTest-out.osm", outFile);
+  }
+
+  void runGeneralizeWayInput1WithInformationNodesTest()
+  {
+    OsmMapPtr map(new OsmMap());
+    QList<Coordinate> inputCoords =
+      readCoords(_inputPath + "RdpWayGeneralizerTestDataset1.txt");
+    CPPUNIT_ASSERT_EQUAL(197, inputCoords.size());
+    inputCoords.append(Coordinate::getNull());
+    WayPtr way = TestUtils::createWay(map, Status::Unknown1, inputCoords.toVector().data(), 1, "");
+    CPPUNIT_ASSERT_EQUAL((size_t)197, way->getNodeIds().size());
+
+    //randomly add some information tags to nodes
+    const double informationCountProbability = 0.1;
+    boost::minstd_rand rng;
+    rng.seed(1);
+    boost::uniform_real<> randomDistribution(0.0, 1.0);
+    for (int i = 0; i < (int)way->getNodeCount(); i++)
+    {
+      const double randomNum = randomDistribution(rng);
+      if (randomNum <= informationCountProbability)
+      {
+        //key and value don't matter here...anything that's not debug or metadata will count as
+        //an information tag
+        map->getElement(map->getNode(way->getNodeId(i))->getElementId())->getTags().
+            set("testKey", "testValue");
+      }
+    }
+
+    RdpWayGeneralizer generalizer(0.1);
+    generalizer.setOsmMap(map.get());
+    generalizer.generalize(way);
+
+    CPPUNIT_ASSERT_EQUAL((size_t)197, map->getNodes().size());
+    CPPUNIT_ASSERT_EQUAL((size_t)137, way->getNodeIds().size());
+    const QString outFile = _outputPath + "runGeneralizeWayInput1WithInformationNodesTest-out.osm";
+    writeMap(map, outFile);
+    HOOT_FILE_EQUALS(_inputPath + "runGeneralizeWayInput1WithInformationNodesTest-out.osm", outFile);
+  }
+
+  void runInvalidEpsilonTest()
+  {
+    QString exceptionMsg;
+    try
+    {
+      RdpWayGeneralizer generalizer(0.0);
+    }
+    catch (const HootException& e)
+    {
+      exceptionMsg = e.what();
+    }
+    CPPUNIT_ASSERT_EQUAL(
+      QString("Invalid epsilon value: 0").toStdString(),
+      exceptionMsg.toStdString());
+  }
+
+};
+
+CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(RdpWayGeneralizerTest, "quick");
+
+}
Clone this wiki locally