void WayCleaner::cleanWay(WayPtr way, const ConstOsmMapPtr& map) { const vector<long> nodeIds = way->getNodeIds(); if (isZeroLengthWay(way, map)) { throw HootException("Cannot clean zero length way."); } QList<long> modifiedNodeIds = QVector<long>::fromStdVector(nodeIds).toList(); QList<long> nodeIdsTemp; QList<Coordinate> coords; for (size_t i = 0; i < nodeIds.size(); i++) { bool found = false; if (nodeIdsTemp.contains(nodeIds[i])) { //the only duplicated nodes allowed are the first and last for a closed way if (i == (nodeIds.size() - 1) && nodeIds[0] == nodeIds[i]) { } else { found = true; } } else { nodeIdsTemp.append(nodeIds[i]); } const Coordinate coord = map->getNode(nodeIds[i])->toCoordinate(); if (coords.contains(coord)) { //the only duplicated coords allowed are the first and last for a closed way, if the node ID's //match if (i == (nodeIds.size() - 1) && nodeIds[0] == nodeIds[i]) { } else { found = true; } } else { coords.append(coord); } if (found) { modifiedNodeIds.removeAt(i); } } way->setNodes(modifiedNodeIds.toVector().toStdVector()); }
vector<ElementPtr> PertyWaySplitVisitor::_split(ElementPtr element) { //randomly select elements and split them into two parts boost::uniform_real<> randomSplitDistribution(0.0, 1.0); const double randomSplitNum = randomSplitDistribution(*_rng); if (randomSplitNum <= _waySplitProbability) { LOG_TRACE("element " << element->getElementId() << " *will* be split based on a split " << "probability of: " << _waySplitProbability << " and a randomly generated number: " << randomSplitNum << "\n"); _splitRecursionLevel++; LOG_VART(_splitRecursionLevel); const int numNodesBeforeSplit = _map->getNodes().size(); LOG_VART(numNodesBeforeSplit); const int numWaysBeforeSplit = _map->getWays().size(); LOG_VART(numWaysBeforeSplit); WayLocation waySplitPoint; MultiLineStringLocation multiLineSplitPoint; QList<long> nodeIdsBeforeSplit; int segmentIndex = -1; ElementId wayId; //determine where to split the element if (element->getElementType() == ElementType::Way) { WayPtr way = boost::dynamic_pointer_cast<Way>(element); LOG_VART(way->getNodeCount()); nodeIdsBeforeSplit = QVector<long>::fromStdVector(way->getNodeIds()).toList(); LOG_VART(nodeIdsBeforeSplit); waySplitPoint = _calcSplitPoint(way); } else { multiLineSplitPoint = _calcSplitPoint(boost::dynamic_pointer_cast<Relation>(element), wayId); waySplitPoint = multiLineSplitPoint.getWayLocation(); } const QString distanceMsgStrEnd = QString("a minimum node spacing of ") .append(QString::number(_minNodeSpacing)) .append(" meters"); if (!waySplitPoint.isValid()) { _splitRecursionLevel--; LOG_VART(_splitRecursionLevel); LOG_TRACE("split point *will not* be used because *it violates* " << distanceMsgStrEnd); //if it violates the min node spacing, return an empty element collection, which will end the //recursive splitting on the current way return vector<ElementPtr>(); } else { LOG_TRACE("split point *will* be used because it *does not* violate " << distanceMsgStrEnd); segmentIndex = waySplitPoint.getSegmentIndex(); LOG_VART(segmentIndex); } //split the element vector<ElementPtr> newElementsAfterSplit; if (element->getElementType() == ElementType::Way) { vector<WayPtr> newWaysAfterSplit = WaySplitter::split(_map->shared_from_this(), boost::dynamic_pointer_cast<Way>(element), waySplitPoint); for (size_t i = 0; i < newWaysAfterSplit.size(); i++) { newElementsAfterSplit.push_back(newWaysAfterSplit.at(i)); } } else { ElementPtr match; MultiLineStringSplitter().split(_map->shared_from_this(), multiLineSplitPoint, match); newElementsAfterSplit.push_back(match); } const int numNodesAfterSplit = _map->getNodes().size(); LOG_VART(numNodesAfterSplit); const int numNewNodesCreatedBySplit = numNodesAfterSplit - numNodesBeforeSplit; LOG_VART(numNewNodesCreatedBySplit); LOG_VART(_map->getWays().size()); if (numNewNodesCreatedBySplit > 0) { WayPtr way = boost::dynamic_pointer_cast<Way>(element); //Its possible that the splitting of a relation could generate a new node. In that case, //_updateNewNodeProperties does not need to be called b/c the MultiLineStringSplitter has //already properly updated the new node's properties. when a way is split, however, the //new node's properties must be updated by the call to _updateNewNodeProperties. if (way != 0) { assert(nodeIdsBeforeSplit.size() > 0); //update properties on any nodes added as a result of the way splitting (new ways created as a //result of the splitting will already have had their parent's tags added by WaySplitter) _updateNewNodeProperties( _getNodeAddedBySplit(nodeIdsBeforeSplit, newElementsAfterSplit), _map->getNode(way->getNodeId(segmentIndex)), _map->getNode(way->getNodeId(segmentIndex + 1))); } } //recursive call for (vector<ElementPtr>::const_iterator it = newElementsAfterSplit.begin(); it != newElementsAfterSplit.end(); ++it) { _split(*it); } return newElementsAfterSplit; } else { LOG_TRACE("element " << element->getElementId() << " *will not* be split based on a split " << "probability of: " << _waySplitProbability << " and a randomly generated number: " << randomSplitNum << "\n"); } //end the recursive splitting on the current way return vector<ElementPtr>(); }
void _sanityCheckSplit(SplitLongLinearWaysVisitor& /*splitVisitor*/, const int startNode, const int numNodes, const int numWays) { // Pull out ways WayMap ways = _map->getWays(); CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(numWays), ways.size() ); // Pull out nodes OsmMap::NodeMap nodes = _map->getNodeMap(); CPPUNIT_ASSERT_EQUAL( numNodes, nodes.size() ); // Make sure no relations RelationMap relations = _map->getRelationMap(); CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(0), relations.size() ); unsigned int nodesLeftToFind = numNodes; unsigned int searchId = startNode; while ( nodesLeftToFind > 0 ) { LOG_DEBUG("Looking for node ID " << searchId); bool madeProgress = false; bool hitError = false; for (WayMap::const_iterator it = ways.begin(); it != ways.end(); it++) { // Does this way have the node we're looking for? WayPtr currWay = it->second; if ( currWay->getFirstNodeId() == searchId ) { nodesLeftToFind--; LOG_DEBUG("Found node ID " << searchId << " at start of way " << currWay->getId()); madeProgress = true; // Make sure rest of nodes we want exist and are in correct order searchId++; std::vector<long> wayIds = currWay->getNodeIds(); // Start at second node, since we already checked first one for ( std::vector<long>::const_iterator nodeIt = wayIds.begin() + 1; nodeIt != wayIds.end(); ++nodeIt ) { if ( *nodeIt != searchId ) { // Throw a hissy fit hitError = true; break; } nodesLeftToFind--; searchId++; } searchId--; // Search count is off by one if ( nodesLeftToFind > 0 ) { nodesLeftToFind++; } LOG_DEBUG("Found remainder of IDs up to " << searchId << " inside way"); LOG_DEBUG("Nodes left to find: " << nodesLeftToFind); // We found what we needed, bail out of looking for more ways break; } else { LOG_DEBUG("Way started with ID " << currWay->getFirstNodeId() << ", skipping"); } } CPPUNIT_ASSERT( (madeProgress == true) && (hitError == false) ); } }