diff --git a/hoot-core/src/main/cpp/hoot/core/conflate/highway/Roundabout.cpp b/hoot-core/src/main/cpp/hoot/core/conflate/highway/Roundabout.cpp
index d16af61..303cb4a 100644
--- a/hoot-core/src/main/cpp/hoot/core/conflate/highway/Roundabout.cpp
+++ b/hoot-core/src/main/cpp/hoot/core/conflate/highway/Roundabout.cpp
@@ -31,25 +31,27 @@
#include <hoot/core/elements/ElementConverter.h>
#include <hoot/core/elements/NodeToWayMap.h>
#include <hoot/core/index/OsmMapIndex.h>
-#include <hoot/core/io/OsmMapWriterFactory.h>
#include <hoot/core/ops/RemoveNodeByEid.h>
#include <hoot/core/ops/RemoveWayByEid.h>
#include <hoot/core/ops/UnconnectedWaySnapper.h>
#include <hoot/core/util/MapProjector.h>
#include <hoot/core/visitors/ElementIdsVisitor.h>
+#include <hoot/core/elements/OsmUtils.h>
#include <geos/geom/Geometry.h>
#include <geos/geom/CoordinateSequence.h>
#include <geos/geom/LineString.h>
+using geos::geom::CoordinateSequence;
+
namespace hoot
{
typedef std::shared_ptr<geos::geom::Geometry> GeomPtr;
-Roundabout::Roundabout()
- : _status(Status::Invalid),
- _overrideStatus(false)
+Roundabout::Roundabout() :
+_status(Status::Invalid),
+_overrideStatus(false)
{
}
@@ -86,18 +88,15 @@ NodePtr Roundabout::getNewCenter(OsmMapPtr pMap)
lat = lat / count;
lon = lon / count;
- NodePtr pNewNode(new Node(_status,
- pMap->createNextNodeId(),
- lon, lat, 15));
+ NodePtr pNewNode(new Node(_status, pMap->createNextNodeId(), lon, lat, 15));
pNewNode->setTag(MetadataTags::HootSpecial(), MetadataTags::RoundaboutCenter());
return pNewNode;
}
-RoundaboutPtr Roundabout::makeRoundabout(const OsmMapPtr &pMap,
- WayPtr pWay)
+RoundaboutPtr Roundabout::makeRoundabout(const OsmMapPtr& pMap, WayPtr pWay)
{
- RoundaboutPtr rnd(new Roundabout);
+ RoundaboutPtr rnd(new Roundabout());
// Add the way to the roundabout
rnd->setRoundaboutWay(pWay);
@@ -111,7 +110,10 @@ RoundaboutPtr Roundabout::makeRoundabout(const OsmMapPtr &pMap,
// Calculate and set center
rnd->setRoundaboutCenter(rnd->getNewCenter(pMap));
+ LOG_VART(rnd->getCenter());
+ LOG_TRACE("Created roundabout: " << rnd->toDetailedString(pMap));
+ LOG_VART(OsmUtils::getWayNodesDetailedString(rnd->getRoundaboutWay(), pMap));
return rnd;
}
@@ -128,6 +130,8 @@ namespace // Anonymous
void Roundabout::handleCrossingWays(OsmMapPtr pMap)
{
+ LOG_TRACE("Handling crossing ways...");
+
// Get a center point
NodePtr pCenterNode = getNewCenter(pMap);
pCenterNode->setStatus(_otherStatus);
@@ -153,8 +157,8 @@ void Roundabout::handleCrossingWays(OsmMapPtr pMap)
{
// Make list of waylocations
std::vector<WayLocation> splitPoints;
- geos::geom::Geometry * pIntersect = pRndGeo->intersection(pWayGeo.get());
- geos::geom::CoordinateSequence *pCoords = pIntersect->getCoordinates();
+ GeomPtr pIntersect(pRndGeo->intersection(pWayGeo.get()));
+ std::shared_ptr<CoordinateSequence> pCoords(pIntersect->getCoordinates());
// We are only interested in ways that intersect the geometry once or
// twice. More than that is situation we are not prepared to handle.
@@ -195,17 +199,16 @@ void Roundabout::handleCrossingWays(OsmMapPtr pMap)
_connectingWays.push_back(newWays[j]);
// Now make connector way
- WayPtr pWay(new Way(_otherStatus,
- pMap->createNextWayId(),
- 15));
+ WayPtr pWay(new Way(_otherStatus, pMap->createNextWayId(), 15));
pWay->addNode(pCenterNode->getId());
pWay->setTag("highway", "unclassified");
pWay->setTag(MetadataTags::HootSpecial(), MetadataTags::RoundaboutConnector());
// Also add in the connector ways to later remove
+ LOG_TRACE("Adding temp way: " << pWay->getId() << "...");
_tempWays.push_back(pWay);
- // Take the new way. Whichever is closest, first node or last,
- // connect it to our center point.
+ // Take the new way. Whichever is closest, first node or last, connect it to our
+ // center point.
NodePtr pFirstNode = pMap->getNode(newWays[j]->getFirstNodeId());
NodePtr pLastNode = pMap->getNode(newWays[j]->getLastNodeId());
@@ -231,6 +234,7 @@ void Roundabout::handleCrossingWays(OsmMapPtr pMap)
if (newWays.size() > 0 && replace)
{
// Remove pWay
+ LOG_TRACE("Removing original way: " << pWay->getElementId() << "...");
RemoveWayByEid::removeWayFully(pMap, pWay->getId());
pMap->addNode(pCenterNode);
}
@@ -239,17 +243,21 @@ void Roundabout::handleCrossingWays(OsmMapPtr pMap)
}
}
-/* Get all the nodes in the roundabout way.
- * Iterate through them, and see if they belong to another way.
- * If they do, keep them.
- *
- * Remove the roundabout from the map (way + leftover nodes)
- *
- * Iterate through the nodes that were kept, and connect them to
- * the centerpoint with temp ways.
- */
void Roundabout::removeRoundabout(OsmMapPtr pMap)
{
+ /* Get all the nodes in the roundabout way.
+ * Iterate through them, and see if they belong to another way.
+ * If they do, keep them.
+ *
+ * Remove the roundabout from the map (way + leftover nodes)
+ *
+ * Iterate through the nodes that were kept, and connect them to
+ * the centerpoint with temp ways.
+ */
+
+ //LOG_TRACE("Removing roundabout: " << _roundaboutWay->getElementId() << "...");
+ LOG_TRACE("Removing roundabout: " << toDetailedString(pMap) << "...");
+
// Find our connecting nodes & extra nodes.
std::set<long> connectingNodeIDs;
std::set<long> extraNodeIDs;
@@ -265,57 +273,73 @@ void Roundabout::removeRoundabout(OsmMapPtr pMap)
extraNodeIDs.insert(_roundaboutNodes[i]->getId());
}
}
+ //LOG_VART(connectingNodeIDs.size());
+ // LOG_VART(extraNodeIDs.size());
+ LOG_VART(connectingNodeIDs);
+ LOG_VART(extraNodeIDs);
// Find our center coord...
if (!_pCenterNode)
_pCenterNode = getNewCenter(pMap);
// Remove roundabout way & extra nodes
+ LOG_TRACE("Removing roundabout way: " << _roundaboutWay->getId() << "...");
+ LOG_VART(OsmUtils::getWayNodesDetailedString(_roundaboutWay, pMap));
RemoveWayByEid::removeWayFully(pMap, _roundaboutWay->getId());
- for (std::set<long>::iterator it = extraNodeIDs.begin();
- it != extraNodeIDs.end(); ++it)
+ for (std::set<long>::iterator it = extraNodeIDs.begin(); it != extraNodeIDs.end(); ++it)
{
- RemoveNodeByEid::removeNode(pMap, *it);
+ LOG_TRACE("Removing extra node with ID: " << *it << "...");
+ // There may be something off with the map index, as I found situation where one of these extra
+ // nodes was still in use. So, changed the removal to only if unused here.
+ RemoveNodeByEid::removeNode(pMap, *it, true);
}
// Add center node
+ LOG_TRACE("Adding center node: " << _pCenterNode << "...");
pMap->addNode(_pCenterNode);
// Connect it up
- for (std::set<long>::iterator it = connectingNodeIDs.begin();
- it != connectingNodeIDs.end(); ++it)
+ LOG_TRACE("Connecting center node: " << _pCenterNode << "...");
+ for (std::set<long>::iterator it = connectingNodeIDs.begin(); it != connectingNodeIDs.end(); ++it)
{
- WayPtr pWay(new Way(_status,
- pMap->createNextWayId(),
- 15));
+ WayPtr pWay(new Way(_status, pMap->createNextWayId(), 15));
pWay->addNode(_pCenterNode->getId());
pWay->addNode(*it);
+ LOG_VART(pWay->getNodeIds());
pWay->setTag("highway", "unclassified");
// Add special hoot tag
pWay->setTag(MetadataTags::HootSpecial(), MetadataTags::RoundaboutConnector());
pMap->addWay(pWay);
+ LOG_TRACE("Adding temp way: " << pWay->getId());
+ LOG_VART(OsmUtils::getWayNodesDetailedString(_roundaboutWay, pMap));
_tempWays.push_back(pWay);
}
+ LOG_VART(_tempWays.size());
}
-/*
- * Go through our nodes... if they are still there, check location.
- * If they are in the same place, fine. Otherwise, add nodes back as new.
- *
- * Then put the original way back. Modify the nodes it contains, to make
- * sure its correct
- *
- * See if center node is still there, if so, use it to get the ways that need
- * to connect to the roundabout.
- *
- * MAYBE: our roundabout nodes might need to be copies, so they don't get moved
- * around during conflation & merging
- */
void Roundabout::replaceRoundabout(OsmMapPtr pMap)
{
- // Re-add roundabout from the ref dataset or the secondary dataset if it has no match in the reference
+ /*
+ * Go through our nodes... if they are still there, check location.
+ * If they are in the same place, fine. Otherwise, add nodes back as new.
+ *
+ * Then put the original way back. Modify the nodes it contains, to make
+ * sure its correct
+ *
+ * See if center node is still there, if so, use it to get the ways that need
+ * to connect to the roundabout.
+ *
+ * MAYBE: our roundabout nodes might need to be copies, so they don't get moved
+ * around during conflation & merging
+ */
+
+ //LOG_TRACE("Replacing roundabout: " << _roundaboutWay->getElementId() << "...");
+ LOG_TRACE("Replacing roundabout: " << toDetailedString(pMap) << "...");
+
+ // Re-add roundabout from the ref dataset or the secondary dataset if it has no match in the
+ // reference
if (_status == Status::Unknown1 || _overrideStatus)
{
std::vector<ConstNodePtr> wayNodes;
@@ -327,12 +351,19 @@ void Roundabout::replaceRoundabout(OsmMapPtr pMap)
if (pMap->getNodes().end() != pMap->getNodes().find(nodeId))
{
ConstNodePtr otherNode = pMap->getNodes().find(nodeId)->second;
+ LOG_VART(otherNode->getId());
// If nodes differ by more than circular error, add the node as new
- if (thisNode->toCoordinate().distance(otherNode->toCoordinate()) > thisNode->getCircularError())
+ LOG_VART(thisNode->toCoordinate().distance(otherNode->toCoordinate()));
+ LOG_VART(thisNode->getCircularError());
+ if (thisNode->toCoordinate().distance(otherNode->toCoordinate()) >
+ thisNode->getCircularError())
{
NodePtr pNewNode(new Node(*thisNode));
pNewNode->setId(pMap->createNextNodeId());
+ LOG_TRACE(
+ "Node with ID: " << nodeId << " found. Adding it with ID: " << pNewNode->getId() <<
+ "...");
pMap->addNode(pNewNode);
wayNodes.push_back(pNewNode);
found = true;
@@ -343,6 +374,9 @@ void Roundabout::replaceRoundabout(OsmMapPtr pMap)
if (!found)
{
NodePtr pNewNode(new Node(*(_roundaboutNodes[i])));
+ LOG_TRACE(
+ "Node with ID: " << nodeId << " not found. Adding new node: " << pNewNode->getId() <<
+ "...");
pMap->addNode(pNewNode);
wayNodes.push_back(pNewNode);
}
@@ -356,17 +390,25 @@ void Roundabout::replaceRoundabout(OsmMapPtr pMap)
for (size_t i = 0; i < wayNodes.size(); i++)
nodeIds.push_back(wayNodes[i]->getId());
pRoundabout->setNodes(nodeIds);
+ LOG_VART(pRoundabout->getNodeIds());
pMap->addWay(pRoundabout);
+// OsmUtils::logElementDetail(
+// pRoundabout, pMap, Log::Trace,
+// "Roundabout::replaceRoundabout: roundabout after updating nodes");
+ LOG_VART(OsmUtils::getWayNodesDetailedString(pRoundabout, pMap));
// Convert the roundabout to a geometry for distance checking later
ElementConverter converter(pMap);
std::shared_ptr<geos::geom::Geometry> geometry = converter.convertToGeometry(pRoundabout);
// Check all of the connecting ways (if they exist) for an endpoint on or near the roundabout
+ LOG_VART(_connectingWays.size());
+ int numAttemptedSnaps = 0;
for (size_t i = 0; i < _connectingWays.size(); ++i)
{
WayPtr way = _connectingWays[i];
bool foundValidWay = pMap->containsWay(way->getId());
- // If the way doesn't exist anymore check for ways with its ID as the parent ID before ignoring it
+ // If the way doesn't exist anymore check for ways with its ID as the parent ID before
+ // ignoring it
if (!foundValidWay)
{
// Check the endpoints against the roundabout
@@ -384,7 +426,8 @@ void Roundabout::replaceRoundabout(OsmMapPtr pMap)
endpoint = node1;
else
endpoint = node2;
- // If the way doesn't exist anymore because of splitting, find the ways with the right endpoint
+ // If the way doesn't exist anymore because of splitting, find the ways with the right
+ // endpoint
std::vector<long> waysWithNode =
ElementIdsVisitor::findWaysByNode(pMap, endpoint->getId());
if (waysWithNode.size() < 1)
@@ -415,21 +458,135 @@ void Roundabout::replaceRoundabout(OsmMapPtr pMap)
if (!endpoint1 || !endpoint2)
continue;
// Check if either of the endpoints are already part of the roundabout
- if (pRoundabout->containsNodeId(endpoint1->getId()) || pRoundabout->containsNodeId(endpoint2->getId()))
+ if (pRoundabout->containsNodeId(endpoint1->getId()) ||
+ pRoundabout->containsNodeId(endpoint2->getId()))
continue;
// Snap the closest
UnconnectedWaySnapper::snapClosestEndpointToWay(pMap, way, pRoundabout);
+ numAttemptedSnaps++;
}
+ LOG_VART(numAttemptedSnaps);
- // Need to remove temp parts no matter what
- // Delete temp ways we added
+ // Need to remove temp parts no matter what; delete temp ways we added
+ LOG_VART(_tempWays.size());
for (size_t i = 0; i < _tempWays.size(); i++)
- RemoveWayByEid::removeWayFully(pMap, _tempWays[i]->getId());
+ {
+ ConstWayPtr tempWay = _tempWays[i];
+ LOG_TRACE("Removing temp way: " << tempWay->getElementId() << "...");
+ RemoveWayByEid::removeWayFully(pMap, tempWay->getId());
+ }
// Remove center node if no other ways are using it
if (pMap->getIndex().getNodeToWayMap()->getWaysByNode(_pCenterNode->getId()).size() < 1)
+ {
+ LOG_TRACE("Removing center node: " << _pCenterNode->getElementId() << "...");
RemoveNodeByEid::removeNodeFully(pMap, _pCenterNode->getId());
+ }
+ }
+}
+
+QString Roundabout::toString() const
+{
+ return
+ QString(
+ "Way: %1, Status: %2, Other Status: %3, Original nodes size: %4, Current nodes size: %5: "
+ "Center node: %6, Temp ways size: %7, Connecting ways size: %8, Override status: %9")
+ .arg(_roundaboutWay->getId())
+ .arg(_status.toString())
+ .arg(_otherStatus.toString())
+ .arg(QString::number(_roundaboutNodes.size()))
+ .arg(QString::number(_roundaboutWay->getNodeIds().size()))
+ .arg(_pCenterNode->getId())
+ .arg(QString::number(_tempWays.size()))
+ .arg(QString::number(_connectingWays.size()))
+ .arg(_overrideStatus);
+}
+
+QString Roundabout::toDetailedString(OsmMapPtr map) const
+{
+ QString str = toString();
+
+ str += ", Original nodes size: " + QString::number(_roundaboutNodes.size());
+ if (_roundaboutWay)
+ {
+ str += ", Current nodes size: " + QString::number(_roundaboutWay->getNodeIds().size());
+ }
+
+ bool nodeIdsMatch = false;
+ const std::vector<ConstNodePtr> originalNodes = _roundaboutNodes;
+ const std::vector<long> originalNodeIds = OsmUtils::nodesToNodeIds(originalNodes);
+ if (_roundaboutWay)
+ {
+ nodeIdsMatch = (originalNodeIds == _roundaboutWay->getNodeIds());
+ }
+ if (nodeIdsMatch)
+ {
+ str += ", original and current node IDs match";
+ }
+ else
+ {
+ str +=
+ ", original and current node IDs do not match, original nodes: " + getOriginalNodesString();
+ str += "; current nodes: " + getCurrentNodesString(map);
+ }
+
+ if (nodeIdsMatch)
+ {
+ const std::vector<ConstNodePtr> currentNodes =
+ OsmUtils::nodeIdsToNodes(_roundaboutWay->getNodeIds(), map);
+ if (OsmUtils::nodeCoordsMatch(originalNodes, currentNodes))
+ {
+ str += ", original and current node coordinates match.";
+ }
+ else
+ {
+ str +=
+ ", original and current node coordinates do not match. original node coords: " +
+ OsmUtils::nodeCoordsToString(originalNodes) + ", current node coords: " +
+ OsmUtils::nodeCoordsToString(currentNodes);
+ }
+ }
+
+ return str;
+}
+
+QString Roundabout::getOriginalNodesString() const
+{
+ QString str;
+ for (size_t i = 0; i < _roundaboutNodes.size(); i++)
+ {
+ ConstNodePtr node = _roundaboutNodes[i];
+ if (node)
+ {
+ str += QString::number(node->getId()) + ",";
+ }
+ else
+ {
+ str += "null node,";
+ }
+ }
+ str.chop(1);
+ return str;
+}
+
+QString Roundabout::getCurrentNodesString(OsmMapPtr map) const
+{
+ QString str;
+ const std::vector<long> nodeIds = _roundaboutWay->getNodeIds();
+ for (size_t i = 0; i < nodeIds.size(); i++)
+ {
+ ConstNodePtr node = map->getNode(nodeIds[i]);
+ if (node)
+ {
+ str += QString::number(node->getId()) + ", ";
+ }
+ else
+ {
+ str += "ID: " + QString::number(nodeIds[i]) + " not found, ";
+ }
}
+ str.chop(1);
+ return str;
}
}