diff --git a/hoot-core/src/main/cpp/hoot/core/ops/IdSwapOp.cpp b/hoot-core/src/main/cpp/hoot/core/ops/IdSwapOp.cpp
index 8b0ebc1..d867c4a 100644
--- a/hoot-core/src/main/cpp/hoot/core/ops/IdSwapOp.cpp
+++ b/hoot-core/src/main/cpp/hoot/core/ops/IdSwapOp.cpp
@@ -28,6 +28,9 @@
// Hoot
#include <hoot/core/conflate/IdSwap.h>
+#include <hoot/core/elements/NodeToWayMap.h>
+#include <hoot/core/index/OsmMapIndex.h>
+#include <hoot/core/ops/RemoveNodeByEid.h>
#include <hoot/core/util/Factory.h>
namespace hoot
@@ -35,15 +38,15 @@ namespace hoot
HOOT_FACTORY_REGISTER(OsmMapOperation, IdSwapOp)
-IdSwapOp::IdSwapOp()
-{
-}
-
-void IdSwapOp::apply(std::shared_ptr<hoot::OsmMap>& map)
+void IdSwapOp::apply(const std::shared_ptr<hoot::OsmMap>& map)
{
// Validate the swap information
- IdSwapPtr swap = map->getIdSwap();
- if (!swap)
+ IdSwapPtr swap;
+ if (_idSwap)
+ swap = _idSwap;
+ else if (map->getIdSwap())
+ swap = map->getIdSwap();
+ else
return;
// Iterate all of the entries to swap
for (IdSwap::iterator it = swap->begin(); it != swap->end(); ++it)
@@ -58,32 +61,80 @@ void IdSwapOp::apply(std::shared_ptr<hoot::OsmMap>& map)
// Don't swap elements that aren't the same type
if (element1->getElementType() != element2->getElementType())
continue;
- // Create a copy of element elements
- ElementPtr element1a(element1->clone());
- ElementPtr element2a(element2->clone());
- // Replace element 2 with an empty ID temporarily
- element2a->setId(0);
- map->replace(element2, element2a);
- // Replace element 1 with element 2's ID
- element1a->setId(element2->getId());
- map->replace(element1, element1a);
- // Replace element 2a with element 1's ID
- element2->setId(element1->getId());
- map->replace(element2a, element2);
- // Swap the PIDs also
- if (element1->getElementType() == ElementType::Way &&
- element2->getElementType() == ElementType::Way)
+ // Each type of element potentially has a something extra to swap
+ // Both are ensured to have the same type at this point
+ if (element1->getElementType() == ElementType::Way)
{
// This is tricky because element1a has replaced element1 as the actual object
+ // Create a copy of element elements
+ ElementPtr element1a(element1->clone());
+ ElementPtr element2a(element2->clone());
+ // Replace element 2 with an empty ID temporarily
+ element2a->setId(0);
+ map->replace(element2, element2a);
+ // Replace element 1 with element 2's ID
+ element1a->setId(element2->getId());
+ map->replace(element1, element1a);
+ // Replace element 2a with element 1's ID
+ element2->setId(element1->getId());
+ map->replace(element2a, element2);
+ // Swap the PIDs also
WayPtr way1 = std::dynamic_pointer_cast<Way>(element1a);
WayPtr way2 = std::dynamic_pointer_cast<Way>(element2);
long temp = way1->getPid();
way1->setPid(way2->getPid());
way2->setPid(temp);
}
+ else if (element1->getElementType() == ElementType::Node)
+ {
+ // Nodes cannot use OsmMap::replace() or OsmMap::replaceNode()
+ // because it deletes the node being replaced
+ NodePtr node1 = std::dynamic_pointer_cast<Node>(element1);
+ NodePtr node2 = std::dynamic_pointer_cast<Node>(element2);
+ // Remove the nodes from the map index but don't remove them fully
+ RemoveNodeByEid(node1->getId(), false).apply(map);
+ RemoveNodeByEid(node2->getId(), false).apply(map);
+ // Swap the node IDs in the nodes themselves
+ long nodeId1 = node1->getId();
+ long nodeId2 = node2->getId();
+ node1->setId(0);
+ node2->setId(nodeId1);
+ node1->setId(nodeId2);
+ // Add the new swapped nodes back to the map
+ map->addNode(node1);
+ map->addNode(node2);
+ // Swap the node IDs in any way that they are associated with
+ swapNodeIdInWay(map, nodeId1, 0);
+ swapNodeIdInWay(map, nodeId2, nodeId1);
+ swapNodeIdInWay(map, 0, nodeId2);
+ }
// Update the number affected
_numAffected++;
}
}
+void IdSwapOp::swapNodeIdInWay(const std::shared_ptr<OsmMap>& map, long nodeId, long swapId)
+{
+ std::shared_ptr<NodeToWayMap> nodeToWayMap = map->getIndex().getNodeToWayMap();
+ std::set<long> ways = nodeToWayMap->getWaysByNode(nodeId);
+ // Iterate all of the ways that contain this node
+ for (std::set<long>::iterator it = ways.begin(); it != ways.end(); ++it)
+ {
+ long wayId = *it;
+ WayPtr way = map->getWay(wayId);
+ if (!way)
+ continue;
+ // Get a list of all nodes in the way
+ std::vector<long> nodes = way->getNodeIds();
+ // Iterate all nodes in the way replacing nodeId with swapId as many times as it occurs
+ for (size_t i = 0; i < nodes.size(); i++)
+ {
+ if (nodes[i] == nodeId)
+ nodes[i] = swapId;
+ }
+ // Replace the vector of node IDs in the way with the new list
+ way->setNodes(nodes);
+ }
+}
+
}