Skip to content

v0.2.49..v0.2.50 changeset ReuseNodeIdsOnWayOp.cpp

Garret Voltz edited this page Nov 6, 2019 · 1 revision
diff --git a/hoot-core/src/main/cpp/hoot/core/ops/ReuseNodeIdsOnWayOp.cpp b/hoot-core/src/main/cpp/hoot/core/ops/ReuseNodeIdsOnWayOp.cpp
new file mode 100644
index 0000000..4071601
--- /dev/null
+++ b/hoot-core/src/main/cpp/hoot/core/ops/ReuseNodeIdsOnWayOp.cpp
@@ -0,0 +1,147 @@
+/*
+ * 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) 2019 DigitalGlobe (http://www.digitalglobe.com/)
+ */
+#include "ReuseNodeIdsOnWayOp.h"
+
+// hoot
+#include <hoot/core/conflate/IdSwap.h>
+#include <hoot/core/elements/NodeToWayMap.h>
+#include <hoot/core/elements/OsmMap.h>
+#include <hoot/core/index/OsmMapIndex.h>
+#include <hoot/core/ops/IdSwapOp.h>
+#include <hoot/core/util/Factory.h>
+#include <hoot/core/util/Log.h>
+
+using namespace std;
+
+namespace hoot
+{
+
+HOOT_FACTORY_REGISTER(OsmMapOperation, ReuseNodeIdsOnWayOp)
+
+ReuseNodeIdsOnWayOp::ReuseNodeIdsOnWayOp()
+{
+}
+
+ReuseNodeIdsOnWayOp::ReuseNodeIdsOnWayOp(ElementId from, ElementId to)
+  : _from(from),
+    _to(to)
+{
+}
+
+void ReuseNodeIdsOnWayOp::addElement(const ConstElementPtr& e)
+{
+  if (_from.isNull())
+    _from = e->getElementId();
+  else if (_to.isNull())
+    _to = e->getElementId();
+  else
+    throw IllegalArgumentException("Error adding element. Only two elements can be added 'from' and 'to'.");
+}
+
+void ReuseNodeIdsOnWayOp::apply(const std::shared_ptr<OsmMap>& map)
+{
+  //  There must be two ways to work with
+  if (_from.isNull() || _to.isNull())
+    throw IllegalArgumentException("You must specify a valid 'from' and 'to' element ID.");
+  //  Check both from and to and make sure that they are in the map
+  if (!map->containsElement(_from))
+  {
+    LOG_TRACE(_from << " doesn't exist in map.");
+    return;
+  }
+  if (!map->containsElement(_to))
+  {
+    LOG_TRACE(_to << " doesn't exist in map.");
+    return;
+  }
+  //  Both elements must be ways in order to reuse node IDs
+  if (_from.getType() != ElementType::Way)
+  {
+    LOG_TRACE(_from << " isn't a way.");
+    return;
+  }
+  if (_to.getType() != ElementType::Way)
+  {
+    LOG_TRACE(_to << " isn't a way.");
+    return;
+  }
+  //  Don't try to reuse node IDs from UNKNOWN2 because UNKNOWN1 node IDs take precident
+  WayPtr from = map->getWay(_from);
+  WayPtr to = map->getWay(_to);
+  if (from->getStatus() != Status::Unknown1)
+  {
+    LOG_TRACE(from << " has status " << from->getStatus());
+    return;
+  }
+  //  By now "to" should have been set to conflated
+  if (to->getStatus() != Status::Conflated)
+  {
+    LOG_TRACE(to << " has status " << to->getStatus());
+    return;
+  }
+  LOG_TRACE("Replacing node IDs in " << from << " with " << to << "...");
+  //  Only replace node IDs of non-shared nodes
+  std::shared_ptr<NodeToWayMap> nodeToWayMap = map->getIndex().getNodeToWayMap();
+  //  Swap all of the node IDs at once
+  std::shared_ptr<IdSwap> swap(new IdSwap());
+  //  For closed ways the use the unique node count
+  size_t toNodeCount = to->getNodeCount();
+  if (toNodeCount > 1 && to->getNodeId(0) == to->getNodeId(toNodeCount - 1))
+    toNodeCount--;
+  size_t fromNodeCount = from->getNodeCount();
+  if (fromNodeCount > 1 && from->getNodeId(0) == from->getNodeId(fromNodeCount - 1))
+    fromNodeCount--;
+  //  Iterate all of the "from" way's node IDs making sure not to iterate
+  //  off of the end of the "to" way either
+  for (size_t fromIndex = 0, toIndex = 0;
+       fromIndex < fromNodeCount && toIndex < toNodeCount;
+       ++fromIndex)
+  {
+    long fromNodeId = from->getNodeId(fromIndex);
+    //  Skip any shared node in the from way
+    if (nodeToWayMap->getWaysByNode(fromNodeId).size() == 1)
+    {
+      long toNodeId = to->getNodeId(toIndex);
+      //  Skip any shared node in the to way
+      while (nodeToWayMap->getWaysByNode(toNodeId).size() > 1 && toIndex < toNodeCount)
+      {
+        toIndex++;
+        toNodeId = to->getNodeId(toIndex);
+      }
+      //  Make sure that both the to and from node IDs are valid before modifying the nodes
+      if (toIndex < toNodeCount)
+      {
+        swap->add(ElementId(ElementType::Node, fromNodeId), ElementId(ElementType::Node, toNodeId));
+        toIndex++;
+      }
+    }
+  }
+  //  Setup the ID swap so that all the swaps happen together
+  IdSwapOp(swap).apply(map);
+}
+
+}
Clone this wiki locally