diff --git a/conf/core/ConfigOptions.asciidoc b/conf/core/ConfigOptions.asciidoc index 83204310d4..b771cd6742 100644 --- a/conf/core/ConfigOptions.asciidoc +++ b/conf/core/ConfigOptions.asciidoc @@ -924,6 +924,15 @@ secondary road endpoint nodes to the nearest reference road. List of tags to ignore when performing differential conflation with tags. +=== differential.treat.reviews.as.matches + +* Data Type: bool +* Default Value: `true` + +If true reviews are treated as matches by Differential Conflation and removed from the output if +differential.remove.reference.data is enabled. If set to false, reviews are not treated as matches +and will pass through to the differential output. + === direction.finder.angle.threshold * Data Type: double @@ -4316,7 +4325,7 @@ Minimum tag numeric value that will allow the TagValueNumericRangeCriterion to b For commands supporting it, the iteration count at which a status message should be logged. This setting may have a negative impact on performance if set to a very low value. -=== test.case.cmd +=== test.case.conflate.cmd * Data Type: string * Default Value: `hoot::ConflateCmd` @@ -4324,6 +4333,22 @@ setting may have a negative impact on performance if set to a very low value. Set the conflate command that should be used in a test case. This is only useful when writing test cases (`test-files/cases/`) and was originally added to support the MultiaryPoiConflateCmd. +=== test.case.conflate.differential + +* Data Type: bool +* Default Value: `false` + +When activated, this runs the conflate case test conflate command with the --differential option. + +=== test.case.conflate.differential.include.tags + +* Data Type: bool +* Default Value: `false` + +When activated, this runs the conflate case test conflate command with both the --differential +and --include-tags options (setting this to true automatically sets test.case.conflate.differential +to true). + === test.force.orthographic.projection * Data Type: bool diff --git a/conf/services/conflationTypes.json b/conf/services/conflationTypes.json index ab11fe1b3c..5477535aaa 100644 --- a/conf/services/conflationTypes.json +++ b/conf/services/conflationTypes.json @@ -27,6 +27,7 @@ "members": { "differential.remove.unconflatable.data": "Pass unconflatable data from the secondary input to output", "differential.snap.unconnected.roads": "Snap unconnected secondary roads to reference roads", + "differential.treat.reviews.as.matches": "Treat reviews as matches and remove from output", "snap.unconnected.ways.snap.tolerance": "Maximum distance, in meters, to allow snapping unconnected roads to neighboring roads", "snap.unconnected.ways.use.existing.way.nodes": "Reuse highway nodes when snapping unconnected roads", "snap.unconnected.ways.existing.way.node.tolerance": "Maximum distance, in meters, to allow snapping unconnected highway nodes to neighboring roads" diff --git a/hoot-core-test/src/test/cpp/hoot/core/test/ConflateCaseTest.cpp b/hoot-core-test/src/test/cpp/hoot/core/test/ConflateCaseTest.cpp index 8e11592885..4dc400b297 100644 --- a/hoot-core-test/src/test/cpp/hoot/core/test/ConflateCaseTest.cpp +++ b/hoot-core-test/src/test/cpp/hoot/core/test/ConflateCaseTest.cpp @@ -72,6 +72,22 @@ void ConflateCaseTest::_runConflateCmd() args << in1.absoluteFilePath(); args << in2.absoluteFilePath(); args << testOutput; + bool differential = ConfigOptions().getTestCaseConflateDifferential(); + const bool differentialWithTags = ConfigOptions().getTestCaseConflateDifferentialIncludeTags(); + if (differentialWithTags) + { + // let this override and correct what would otherwise be an invalid config + differential = true; + } + if (differential) + { + args << "--differential"; + } + if (differentialWithTags) + { + args << "--include-tags"; + } + int result = -1; try { @@ -85,8 +101,8 @@ void ConflateCaseTest::_runConflateCmd() QFileInfo expected(_d, "Expected.osm"); if (expected.exists() == false) { - throw IllegalArgumentException("Unable to find Expected.osm in conflate case: " + - _d.absolutePath()); + throw IllegalArgumentException( + "Unable to find Expected.osm in conflate case: " + _d.absolutePath()); } if (result != 0) @@ -176,11 +192,11 @@ void ConflateCaseTest::runTest() // configures and cleans up the conf() environment TestSetup st(_confs); - if (ConfigOptions().getTestCaseCmd().toStdString() == ConflateCmd::className()) + if (ConfigOptions().getTestCaseConflateCmd().toStdString() == ConflateCmd::className()) { _runConflateCmd(); } - else if (ConfigOptions().getTestCaseCmd() == multiaryConflateClass) + else if (ConfigOptions().getTestCaseConflateCmd() == multiaryConflateClass) { _runMultiaryConflateCmd(); } diff --git a/hoot-core/src/main/cpp/hoot/core/algorithms/linearreference/NaiveWayMatchStringMapping.h b/hoot-core/src/main/cpp/hoot/core/algorithms/linearreference/NaiveWayMatchStringMapping.h index 64a1835377..b1b334a37e 100644 --- a/hoot-core/src/main/cpp/hoot/core/algorithms/linearreference/NaiveWayMatchStringMapping.h +++ b/hoot-core/src/main/cpp/hoot/core/algorithms/linearreference/NaiveWayMatchStringMapping.h @@ -37,6 +37,7 @@ class WayString; class NaiveWayMatchStringMapping : public WayMatchStringMapping { public: + NaiveWayMatchStringMapping(WayStringPtr str1, WayStringPtr str2); virtual WayStringPtr getWayString1() { return _ws1; } @@ -52,6 +53,7 @@ class NaiveWayMatchStringMapping : public WayMatchStringMapping virtual void setWayString2(const WayStringPtr& ws2) { _ws2 = ws2; } private: + WayStringPtr _ws1, _ws2; Meters _length1, _length2; }; diff --git a/hoot-core/src/main/cpp/hoot/core/algorithms/linearreference/WayMatchStringMapping.h b/hoot-core/src/main/cpp/hoot/core/algorithms/linearreference/WayMatchStringMapping.h index ffcb5ce15b..d9d5474c65 100644 --- a/hoot-core/src/main/cpp/hoot/core/algorithms/linearreference/WayMatchStringMapping.h +++ b/hoot-core/src/main/cpp/hoot/core/algorithms/linearreference/WayMatchStringMapping.h @@ -87,6 +87,9 @@ class WayMatchStringMapping virtual void setWayString2(const WayStringPtr& ws2) = 0; void setWayString(WayNumber way, const WayStringPtr& ws) { (way == WayNumber::Way1) ? setWayString1(ws) : setWayString2(ws); } + + QString toString() + { return "1: " + getWayString1()->toString() + "; 2: " + getWayString2()->toString(); } }; typedef std::shared_ptr WayMatchStringMappingPtr; diff --git a/hoot-core/src/main/cpp/hoot/core/algorithms/optimizer/IntegerProgrammingSolver.cpp b/hoot-core/src/main/cpp/hoot/core/algorithms/optimizer/IntegerProgrammingSolver.cpp index 189701073c..a5a2dc739c 100644 --- a/hoot-core/src/main/cpp/hoot/core/algorithms/optimizer/IntegerProgrammingSolver.cpp +++ b/hoot-core/src/main/cpp/hoot/core/algorithms/optimizer/IntegerProgrammingSolver.cpp @@ -22,7 +22,7 @@ * This will properly maintain the copyright information. DigitalGlobe * copyrights will be updated automatically. * - * @copyright Copyright (C) 2015, 2017, 2018 DigitalGlobe (http://www.digitalglobe.com/) + * @copyright Copyright (C) 2015, 2017, 2018, 2019 DigitalGlobe (http://www.digitalglobe.com/) */ #include "IntegerProgrammingSolver.h" @@ -82,6 +82,8 @@ void IntegerProgrammingSolver::solve() void IntegerProgrammingSolver::solveBranchAndCut() { + LOG_DEBUG("solveBranchAndCut"); + glp_iocp iocp; glp_init_iocp(&iocp); // Turn on the presolver so that glp_intopt works correctly @@ -133,6 +135,8 @@ void IntegerProgrammingSolver::solveBranchAndCut() void IntegerProgrammingSolver::solveSimplex() { + LOG_DEBUG("solveSimplex"); + glp_smcp smcp; glp_init_smcp(&smcp); // Setup the time limit if necessary diff --git a/hoot-core/src/main/cpp/hoot/core/cmd/ConflateCmd.cpp b/hoot-core/src/main/cpp/hoot/core/cmd/ConflateCmd.cpp index 900f60a61c..3cd2244555 100644 --- a/hoot-core/src/main/cpp/hoot/core/cmd/ConflateCmd.cpp +++ b/hoot-core/src/main/cpp/hoot/core/cmd/ConflateCmd.cpp @@ -55,6 +55,8 @@ #include #include #include +#include +#include // Standard #include @@ -163,19 +165,33 @@ int ConflateCmd::runSimple(QStringList& args) Progress progress(ConfigOptions().getJobId(), JOB_SOURCE, Progress::JobState::Running); const int maxFilePrintLength = ConfigOptions().getProgressVarPrintLengthMax(); QString msg = - "Conflating ..." + input1.right(maxFilePrintLength) + " with ..." + - input2.right(maxFilePrintLength) + " and writing the output to ..." + + "Conflating " + input1.right(maxFilePrintLength) + " with " + + input2.right(maxFilePrintLength) + " and writing the output to " + output.right(maxFilePrintLength); if (isDiffConflate) { - msg = msg.prepend("Differentially "); + if (diffConflator.conflatingTags()) + { + msg = msg.replace("Conflating", "Differentially conflating (tags only) "); + } + else + { + msg = msg.replace("Conflating", "Differentially conflating "); + } } + progress.set(0.0, msg); double bytesRead = IoSingleStat(IoSingleStat::RChar).value; LOG_VART(bytesRead); QList> allStats; + _updateConfigOptionsForAttributeConflation(); + if (isDiffConflate) + { + _updateConfigOptionsForDifferentialConflation(); + } + // The number of steps here must be updated as you add/remove job steps in the logic. _numTotalTasks = 5; if (displayStats) @@ -334,7 +350,6 @@ int ConflateCmd::runSimple(QStringList& args) stats.append(SingleStat("Conflation Time (sec)", t.getElapsedAndRestart())); currentTask++; - _updatePostConfigOptionsForAttributeConflation(); if (ConfigOptions().getConflatePostOps().size() > 0) { // apply any user specified post-conflate operations @@ -476,7 +491,32 @@ float ConflateCmd::_getJobPercentComplete(const int currentTaskNum) const return (float)currentTaskNum / (float)_numTotalTasks; } -void ConflateCmd::_updatePostConfigOptionsForAttributeConflation() +void ConflateCmd::_updateConfigOptionsForDifferentialConflation() +{ + // Since Differential throws out all matches, there's no way we can have a bad merge between + // ref/secondary roundabouts. Therefore, no need to replace/remove them. If there's a match, we'll + // end with no secondary roundabout in the diff output and only the ref roundabout when the diff + // is applied back to the ref. + + QStringList preConflateOps = ConfigOptions().getConflatePreOps(); + const QString removeRoundaboutsClassName = QString::fromStdString(RemoveRoundabouts::className()); + if (preConflateOps.contains(removeRoundaboutsClassName)) + { + preConflateOps.removeAll(removeRoundaboutsClassName); + conf().set(ConfigOptions::getConflatePreOpsKey(), preConflateOps); + } + + QStringList postConflateOps = ConfigOptions().getConflatePostOps(); + const QString replaceRoundaboutsClassName = + QString::fromStdString(ReplaceRoundabouts::className()); + if (postConflateOps.contains(replaceRoundaboutsClassName)) + { + postConflateOps.removeAll(replaceRoundaboutsClassName); + conf().set(ConfigOptions::getConflatePostOpsKey(), postConflateOps); + } +} + +void ConflateCmd::_updateConfigOptionsForAttributeConflation() { // These are some custom adjustments to config opts that must be done for Attribute Conflation. // There may be a way to eliminate these by adding more custom behavior to the UI. diff --git a/hoot-core/src/main/cpp/hoot/core/cmd/ConflateCmd.h b/hoot-core/src/main/cpp/hoot/core/cmd/ConflateCmd.h index 29264ed10d..3e9d3dbdf1 100644 --- a/hoot-core/src/main/cpp/hoot/core/cmd/ConflateCmd.h +++ b/hoot-core/src/main/cpp/hoot/core/cmd/ConflateCmd.h @@ -67,7 +67,8 @@ class ConflateCmd : public BaseCommand int _numTotalTasks; - void _updatePostConfigOptionsForAttributeConflation(); + void _updateConfigOptionsForAttributeConflation(); + void _updateConfigOptionsForDifferentialConflation(); void _checkForTagValueTruncationOverride(); float _getJobPercentComplete(const int currentTaskNum) const; diff --git a/hoot-core/src/main/cpp/hoot/core/conflate/DiffConflator.cpp b/hoot-core/src/main/cpp/hoot/core/conflate/DiffConflator.cpp index 49a5018aeb..3318ec00d4 100644 --- a/hoot-core/src/main/cpp/hoot/core/conflate/DiffConflator.cpp +++ b/hoot-core/src/main/cpp/hoot/core/conflate/DiffConflator.cpp @@ -125,7 +125,7 @@ void DiffConflator::apply(OsmMapPtr& map) _updateProgress(currentStep - 1, "Matching features..."); - // If we don't do this, then any non-matchable data will simply pass through to output. + // If we skip this part, then any non-matchable data will simply pass through to output. if (ConfigOptions().getDifferentialRemoveUnconflatableData()) { LOG_INFO("Discarding unconflatable elements..."); @@ -161,9 +161,8 @@ void DiffConflator::apply(OsmMapPtr& map) currentStep++; - // Use matches to calculate and store tag diff. We must do this before we - // create the map diff, because that operation deletes all of the info needed - // for calculating the tag diff. + // Use matches to calculate and store tag diff. We must do this before we create the map diff, + // because that operation deletes all of the info needed for calculating the tag diff. _updateProgress(currentStep - 1, "Storing tag differentials..."); _calcAndStoreTagChanges(); currentStep++; @@ -219,28 +218,37 @@ void DiffConflator::_snapSecondaryRoadsBackToRef() void DiffConflator::_removeMatches(const Status& status) { LOG_DEBUG("\tRemoving match elements with status: " << status.toString() << "..."); + + const bool treatReviewsAsMatches = ConfigOptions().getDifferentialTreatReviewsAsMatches(); + LOG_VARD(treatReviewsAsMatches); for (std::vector::iterator mit = _matches.begin(); mit != _matches.end(); ++mit) { - std::set> pairs = (*mit)->getMatchPairs(); - for (std::set>::iterator pit = pairs.begin(); - pit != pairs.end(); ++pit) + ConstMatchPtr match = *mit; + if (treatReviewsAsMatches || match->getType() != MatchType::Review) { - if (!pit->first.isNull()) + std::set> pairs = (*mit)->getMatchPairs(); + for (std::set>::iterator pit = pairs.begin(); + pit != pairs.end(); ++pit) { - LOG_VART(pit->first); - ElementPtr e = _pMap->getElement(pit->first); - if (e && e->getStatus() == status) + if (!pit->first.isNull()) { - RecursiveElementRemover(pit->first).apply(_pMap); + LOG_VART(pit->first); + ElementPtr e = _pMap->getElement(pit->first); + if (e && e->getStatus() == status) + { + //LOG_VART(e->getTags().get("name")); + RecursiveElementRemover(pit->first).apply(_pMap); + } } - } - if (!pit->second.isNull()) - { - LOG_VART(pit->second); - ElementPtr e = _pMap->getElement(pit->second); - if (e && e->getStatus() == status) + if (!pit->second.isNull()) { - RecursiveElementRemover(pit->second).apply(_pMap); + LOG_VART(pit->second); + ElementPtr e = _pMap->getElement(pit->second); + if (e && e->getStatus() == status) + { + //LOG_VART(e->getTags().get("name")); + RecursiveElementRemover(pit->second).apply(_pMap); + } } } } @@ -326,21 +334,18 @@ void DiffConflator::addChangesToMap(OsmMapPtr pMap, ChangesetProviderPtr pChange } else if (ElementType::Relation == c.getElement()->getElementType().getEnum()) { - // Diff conflation doesn't do relations yet + // Diff conflation w/ tags doesn't handle relations. Changed this to silently log that the + // relations are being skipped for now. #3449 was created to deal with adding relation support + // and then closed since we lack a use case currently that requires it. If we ever get one, + // then we can re-open that issue. - if (logWarnCount < Log::getWarnMessageLimit()) + LOG_DEBUG("Relation handling not implemented with differential conflation: " << c); + if (Log::getInstance().getLevel() <= Log::Trace) { - LOG_WARN("Relation handling not implemented with differential conflation: " << c); - LOG_VART(c); ConstRelationPtr relation = std::dynamic_pointer_cast(c.getElement()); LOG_VART(relation->getElementId()); LOG_VART(OsmUtils::getRelationDetailedString(relation, _pOriginalMap)); } - else if (logWarnCount == Log::getWarnMessageLimit()) - { - LOG_WARN(className() << ": " << Log::LOG_WARN_LIMIT_REACHED_MESSAGE); - } - logWarnCount++; } } OsmMapWriterFactory::writeDebugMap(pMap, "after-adding-diff-tag-changes"); @@ -394,13 +399,16 @@ void DiffConflator::_calcAndStoreTagChanges() } LOG_VART(pOldElement->getElementId()); + //LOG_VART(pOldElement->getTags().get("name")); LOG_VART(pNewElement->getElementId()); + //LOG_VART(pNewElement->getTags().get("name")); - // Apparently a NetworkMatch can be a node/way pair. See note in + // Apparently, a NetworkMatch can be a node/way pair. See note in // NetworkMatch::_discoverWayPairs as to why its allowed. However, tag changes between // node/way match pairs other than poi/poly don't seem to make any sense. Clearly, if we add - // other conflation type other than poi/poly which matches differing geometry types then this - // will need to be updated. + // a conflation type other than poi/poly which matches differing geometry types then this will + // need to be updated. + if (match->getMatchName() != PoiPolygonMatch().getMatchName() && pOldElement->getElementType() != pNewElement->getElementType()) { diff --git a/hoot-core/src/main/cpp/hoot/core/conflate/DiffConflator.h b/hoot-core/src/main/cpp/hoot/core/conflate/DiffConflator.h index 29aaecc80c..56b4cc2c56 100644 --- a/hoot-core/src/main/cpp/hoot/core/conflate/DiffConflator.h +++ b/hoot-core/src/main/cpp/hoot/core/conflate/DiffConflator.h @@ -137,9 +137,9 @@ class DiffConflator : public OsmMapOperation, public Serializable, public Bounda virtual QString getDescription() const { return "Conflates two maps into a single map based on the difference between the inputs"; } - // Gets the tag differential between the maps. To do this, we look through all - // of the matches, and compare tags. A set of newer tags is returned as a - // changeset (because updating the tags requires a modify operation) + // Gets the tag differential between the maps. To do this, we look through all of the matches, + // and compare tags. A set of newer tags is returned as a changeset (because updating the tags + // requires a modify operation) /** * @brief getTagDiff - Gets the tag differential that was calculated during the @@ -197,10 +197,9 @@ class DiffConflator : public OsmMapOperation, public Serializable, public Bounda // Stores the changes we calculate when doing the tag differential MemChangesetProviderPtr _pTagChanges; - // A copy of the "Input1" map. This is used when calculating the tag - // differential. It's important, because elements get modified by map - // cleaning operations prior to conflation - and we need this as a reference - // for original IDs and original geometry, so that we can generate a clean + // A copy of the "Input1" map. This is used when calculating the tag differential. It's important, + // because elements get modified by map cleaning operations prior to conflation - and we need this + // as a reference for original IDs and original geometry, so that we can generate a clean // changeset output for the tag diff. OsmMapPtr _pOriginalMap; @@ -223,8 +222,8 @@ class DiffConflator : public OsmMapOperation, public Serializable, public Bounda // Calculates and stores the tag differential as a set of change objects void _calcAndStoreTagChanges(); - // Decides if the newTags should replace the oldTags. Among other things, - // it checks the differential.tag.ignore.list + // Decides if the newTags should replace the oldTags. Among other things, it checks the + // differential.tag.ignore.list bool _tagsAreDifferent(const Tags& oldTags, const Tags& newTags); // Creates a change object using the original element and new tags 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 eeaa579ae3..303cb4abce 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,12 +31,12 @@ #include #include #include -#include #include #include #include #include #include +#include #include #include @@ -49,9 +49,9 @@ namespace hoot typedef std::shared_ptr GeomPtr; -Roundabout::Roundabout() - : _status(Status::Invalid), - _overrideStatus(false) +Roundabout::Roundabout() : +_status(Status::Invalid), +_overrideStatus(false) { } @@ -88,15 +88,13 @@ 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()); @@ -112,7 +110,10 @@ RoundaboutPtr Roundabout::makeRoundabout(const OsmMapPtr &pMap, WayPtr pWay) // 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; } @@ -129,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); @@ -196,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()); @@ -241,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 connectingNodeIDs; std::set extraNodeIDs; @@ -267,18 +273,20 @@ void Roundabout::removeRoundabout(OsmMapPtr pMap) extraNodeIDs.insert(_roundaboutNodes[i]->getId()); } } - LOG_VART(connectingNodeIDs.size()); - LOG_VART(extraNodeIDs.size()); + //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: " << _roundaboutWay->getElementId() << "..."); + LOG_TRACE("Removing roundabout way: " << _roundaboutWay->getId() << "..."); + LOG_VART(OsmUtils::getWayNodesDetailedString(_roundaboutWay, pMap)); RemoveWayByEid::removeWayFully(pMap, _roundaboutWay->getId()); - for (std::set::iterator it = extraNodeIDs.begin(); - it != extraNodeIDs.end(); ++it) + for (std::set::iterator it = extraNodeIDs.begin(); it != extraNodeIDs.end(); ++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 @@ -287,43 +295,51 @@ void Roundabout::removeRoundabout(OsmMapPtr pMap) } // Add center node + LOG_TRACE("Adding center node: " << _pCenterNode << "..."); pMap->addNode(_pCenterNode); // Connect it up - for (std::set::iterator it = connectingNodeIDs.begin(); - it != connectingNodeIDs.end(); ++it) + LOG_TRACE("Connecting center node: " << _pCenterNode << "..."); + for (std::set::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 wayNodes; @@ -335,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; @@ -351,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); } @@ -364,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 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 @@ -392,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 waysWithNode = ElementIdsVisitor::findWaysByNode(pMap, endpoint->getId()); if (waysWithNode.size() < 1) @@ -423,14 +458,17 @@ 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++) { ConstWayPtr tempWay = _tempWays[i]; @@ -447,4 +485,108 @@ void Roundabout::replaceRoundabout(OsmMapPtr pMap) } } +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 originalNodes = _roundaboutNodes; + const std::vector 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 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 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; +} + } diff --git a/hoot-core/src/main/cpp/hoot/core/conflate/highway/Roundabout.h b/hoot-core/src/main/cpp/hoot/core/conflate/highway/Roundabout.h index 03a15074dd..615d8a796d 100644 --- a/hoot-core/src/main/cpp/hoot/core/conflate/highway/Roundabout.h +++ b/hoot-core/src/main/cpp/hoot/core/conflate/highway/Roundabout.h @@ -39,14 +39,11 @@ namespace hoot { /** - * This is a class for storing & maniuplating representations of roundabouts. - * It holds nodes/ways that are part of the roundabout, and nodes/ways - * used to replace the roundabout. - * - * This is a work in progress, but for now the class contains methods to extract - * roundabout info from a map, replace a roundabout with a bunch of ways - * connected to a center point, and put the roundabout back to the way it was + * This is a class for storing & manipulating representations of roundabouts. It holds nodes/ways + * that are part of the roundabout, and nodes/ways used to replace the roundabout. * + * The class contains methods to extract roundabout info from a map, replace a roundabout with a + * bunch of ways connected to a center point, and put the roundabout back to the way it was */ class Roundabout { @@ -61,33 +58,33 @@ class Roundabout * @brief setRoundaboutWay - Set the roundabout way that this object represents * @param pWay - Pointer to the roundabout way */ - void setRoundaboutWay (WayPtr pWay); + void setRoundaboutWay(WayPtr pWay); /** * @brief setRoundaboutCenter - Set the center node for this roundabout. You * can create one if needed by calling getNewCenter * @param pNode - Center node */ - void setRoundaboutCenter (NodePtr pNode); + void setRoundaboutCenter(NodePtr pNode); /** * @brief addRoundaboutNode - Add the node to our internal list of nodes that * make up the roundabout (perimeter) * @param pNode - Pointer to the node */ - void addRoundaboutNode (ConstNodePtr pNode) { _roundaboutNodes.push_back(pNode); } + void addRoundaboutNode(ConstNodePtr pNode) { _roundaboutNodes.push_back(pNode); } /** * @brief getRoundaboutWay - Get the roundabout way * @return - Pointer to the way */ - WayPtr getRoundaboutWay() { return _roundaboutWay; } + WayPtr getRoundaboutWay() const { return _roundaboutWay; } /** * @brief getRoundaboutNodes - Get the nodes that make up the roundabout * @return - Vector of node pointers */ - std::vector getRoundaboutNodes() { return _roundaboutNodes; } + std::vector getRoundaboutNodes() const { return _roundaboutNodes; } /** * @brief getNewCenter - Averages all of the locations of the nodes in the @@ -103,7 +100,7 @@ class Roundabout * @brief getCenter - Gets the node set as the roundabout's center * @return - Node */ - NodePtr getCenter() { return _pCenterNode; } + NodePtr getCenter() const { return _pCenterNode; } /** * @brief makeRoundabout - Creates & populates a roundabout object using the @@ -112,8 +109,7 @@ class Roundabout * @param pWay - The roundabout way * @return - A newly constructed roundabout object */ - static std::shared_ptr makeRoundabout(const OsmMapPtr &pMap, - WayPtr pWay); + static std::shared_ptr makeRoundabout(const OsmMapPtr& pMap, WayPtr pWay); /** * @brief removeRoundabout - Removes this roundabout from the map, and @@ -145,6 +141,11 @@ class Roundabout */ void overrideRoundabout() { _overrideStatus = true; } + QString toString() const; + QString toDetailedString(OsmMapPtr map) const; + QString getOriginalNodesString() const; + QString getCurrentNodesString(OsmMapPtr map) const; + private: // The original roundabout way @@ -170,7 +171,6 @@ class Roundabout // For secondary roundabouts with no sibling, override the replacement bool _overrideStatus; - }; // For convenience diff --git a/hoot-core/src/main/cpp/hoot/core/conflate/matching/MatchThreshold.cpp b/hoot-core/src/main/cpp/hoot/core/conflate/matching/MatchThreshold.cpp index 4c402b9ec6..fbe7a59e1f 100644 --- a/hoot-core/src/main/cpp/hoot/core/conflate/matching/MatchThreshold.cpp +++ b/hoot-core/src/main/cpp/hoot/core/conflate/matching/MatchThreshold.cpp @@ -22,7 +22,7 @@ * This will properly maintain the copyright information. DigitalGlobe * copyrights will be updated automatically. * - * @copyright Copyright (C) 2015, 2016, 2017, 2018 DigitalGlobe (http://www.digitalglobe.com/) + * @copyright Copyright (C) 2015, 2016, 2017, 2018, 2019 DigitalGlobe (http://www.digitalglobe.com/) */ #include "MatchThreshold.h" @@ -69,13 +69,15 @@ QString MatchThreshold::getTypeDetail(const MatchClassification& mc) const { if (mc.getReviewP() >= _reviewThreshold) { - return QString("The feature pair with a review score of %1 was marked for review because it met the review threshold of %2.") + return QString("The feature pair with a review score of %1 was marked for review because it " + "met the review threshold of %2.") .arg(mc.getReviewP()) .arg(_reviewThreshold); } else if (mc.getMatchP() >= _matchThreshold && mc.getMissP() >= _missThreshold) { - return QString("The feature pair with a match score of %1 and a miss score of %2 was marked for review because it met neither the threshold for a match at %3 nor that for a miss at %4.") + return QString("The feature pair with a match score of %1 and a miss score of %2 was marked " + "for review because it met neither the threshold for a match at %3 nor that for a miss at %4.") .arg(mc.getMatchP()) .arg(mc.getMissP()) .arg(_matchThreshold) @@ -84,19 +86,23 @@ QString MatchThreshold::getTypeDetail(const MatchClassification& mc) const } else if (mc.getMatchP() >= _matchThreshold) { - return QString("The feature pair with a match score of %1 was matched because it met the threshold for a match at %2.") + return QString("The feature pair with a match score of %1 was matched because it met the " + "threshold for a match at %2.") .arg(mc.getMatchP()) .arg(_matchThreshold); } else if (mc.getMissP() >= _missThreshold) { - return QString("The feature pair with a miss score of %1 was not matched because it met the threshold for a miss at %2.") + return QString("The feature pair with a miss score of %1 was not matched because it met " + "the threshold for a miss at %2.") .arg(mc.getMissP()) .arg(_missThreshold); } else { - return QString("The feature pair with match score: %1, miss score: %2, and review score: %3 was marked for review because it met neither the threshold for a match (%4), miss (%5), nor review (%6).") + return QString("The feature pair with match score: %1, miss score: %2, and review score: " + "%3 was marked for review because it met neither the threshold for a match " + "(%4), miss (%5), nor review (%6).") .arg(mc.getMatchP()) .arg(mc.getMissP()) .arg(mc.getReviewP()) diff --git a/hoot-core/src/main/cpp/hoot/core/conflate/network/NetworkDetails.cpp b/hoot-core/src/main/cpp/hoot/core/conflate/network/NetworkDetails.cpp index c440412f13..c64e0a33d9 100644 --- a/hoot-core/src/main/cpp/hoot/core/conflate/network/NetworkDetails.cpp +++ b/hoot-core/src/main/cpp/hoot/core/conflate/network/NetworkDetails.cpp @@ -1121,7 +1121,13 @@ WayStringPtr NetworkDetails::toWayString(ConstEdgeStringPtr e, const EidMapper& throw IllegalArgumentException("Expected a network edge with exactly 1 way."); } ElementId eid = mapper.mapEid(e->getMembers()[0]->getElementId()); + ConstWayPtr w = std::dynamic_pointer_cast(_map->getWay(eid)); + if (!w) + { + LOG_VART(eid); + throw IllegalArgumentException("Way: " + eid.toString() + " does not exist in the map."); + } Meters l = calculateLength(e); double startP = subline->getStart()->getPortion(); @@ -1133,6 +1139,7 @@ WayStringPtr NetworkDetails::toWayString(ConstEdgeStringPtr e, const EidMapper& } } + LOG_VARD(ws); return ws; } diff --git a/hoot-core/src/main/cpp/hoot/core/conflate/network/PartialNetworkMerger.cpp b/hoot-core/src/main/cpp/hoot/core/conflate/network/PartialNetworkMerger.cpp index c90d97bc77..a7acbf58bb 100644 --- a/hoot-core/src/main/cpp/hoot/core/conflate/network/PartialNetworkMerger.cpp +++ b/hoot-core/src/main/cpp/hoot/core/conflate/network/PartialNetworkMerger.cpp @@ -66,6 +66,7 @@ PartialNetworkMerger::PartialNetworkMerger(const set> void PartialNetworkMerger::_appendSublineMappings( QList mappings) const { + LOG_TRACE("Appending subline mappings..."); foreach (WayMatchStringMerger::SublineMappingPtr sm, mappings) { foreach (WayMatchStringMerger::SublineMappingPtr other, _allSublineMappings) @@ -80,6 +81,7 @@ void PartialNetworkMerger::_appendSublineMappings( } _allSublineMappings.append(sm); } + LOG_VART(_allSublineMappings.size()); } void PartialNetworkMerger::apply(const OsmMapPtr& map, @@ -142,10 +144,22 @@ WayMatchStringMergerPtr PartialNetworkMerger::_createMatchStringMerger(const Osm vector>& replaced, ConstEdgeMatchPtr edgeMatch) const { // convert the EdgeStrings into WaySublineStrings - WayStringPtr str1 = _details->toWayString(edgeMatch->getString1(), *this); - WayStringPtr str2 = _details->toWayString(edgeMatch->getString2(), *this); + WayStringPtr str1; + WayStringPtr str2; + try + { + str1 = _details->toWayString(edgeMatch->getString1(), *this); + str2 = _details->toWayString(edgeMatch->getString2(), *this); + } + catch (const IllegalArgumentException& /*e*/) + { + return WayMatchStringMergerPtr(); + } + LOG_VARD(str1); + LOG_VARD(str2); WayMatchStringMappingPtr mapping(new NaiveWayMatchStringMapping(str1, str2)); + LOG_VARD(mapping->toString()); /****************** * At the beginning, the merger should identify where the primary way should be broken into bits @@ -206,15 +220,20 @@ void PartialNetworkMerger::_processFullMatch(const OsmMapPtr& map, LOG_DEBUG("Calculating mappings and split points for matches..."); foreach (ConstEdgeMatchPtr em, _edgeMatches) { - _mergerList.append(_createMatchStringMerger(map, replaced, em)); - - // Put all split points and mappings into a single structure that can be used to split ways - _appendSublineMappings(_mergerList.back()->getAllSublineMappings()); + WayMatchStringMergerPtr merger = _createMatchStringMerger(map, replaced, em); + if (merger) + { + _mergerList.append(merger); + // Put all split points and mappings into a single structure that can be used to split ways + _appendSublineMappings(_mergerList.back()->getAllSublineMappings()); + } } + LOG_VART(_mergerList.size()); try { // split the ways in such a way that the mappings are updated appropriately. + LOG_DEBUG("Applying way splits..."); WayMatchStringSplitter splitter; splitter.applySplits(map, replaced, _allSublineMappings); diff --git a/hoot-core/src/main/cpp/hoot/core/elements/Node.cpp b/hoot-core/src/main/cpp/hoot/core/elements/Node.cpp index 9c7ecd8cf5..dde5bb6931 100644 --- a/hoot-core/src/main/cpp/hoot/core/elements/Node.cpp +++ b/hoot-core/src/main/cpp/hoot/core/elements/Node.cpp @@ -127,4 +127,22 @@ void Node::visitRw(ElementProvider& map, ConstElementVisitor& filter) filter.visit(std::dynamic_pointer_cast(map.getNode(getId()))); } +bool Node::coordsMatch(const Node& other) const +{ + const int comparisonSensitivity = ConfigOptions().getNodeComparisonCoordinateSensitivity(); + const double x = + std::round(getX() * std::pow(10.0, comparisonSensitivity)) / + std::pow(10.0, comparisonSensitivity); + const double otherX = + std::round(other.getX() * std::pow(10.0, comparisonSensitivity)) / + std::pow(10.0, comparisonSensitivity); + const double y = + std::round(getY() * std::pow(10.0, comparisonSensitivity)) / + std::pow(10.0, comparisonSensitivity); + const double otherY = + std::round(other.getY() * std::pow(10.0, comparisonSensitivity)) / + std::pow(10.0, comparisonSensitivity); + return ((x - otherX) == 0.0) && ((y - otherY) == 0.0); +} + } diff --git a/hoot-core/src/main/cpp/hoot/core/elements/Node.h b/hoot-core/src/main/cpp/hoot/core/elements/Node.h index 2173d373a2..88e49cc8a2 100644 --- a/hoot-core/src/main/cpp/hoot/core/elements/Node.h +++ b/hoot-core/src/main/cpp/hoot/core/elements/Node.h @@ -126,6 +126,15 @@ class Node : public Element virtual void visitRw(ElementProvider& map, ConstElementVisitor& visitor); + /** + * Determines if the coordinates from this node match with that of another given a configurable + * tolerance + * + * @param other the node to compare coordinates with + * @return true if the coordinates match; false otherwise + */ + bool coordsMatch(const Node& other) const; + protected: friend class SharedPtrPool; diff --git a/hoot-core/src/main/cpp/hoot/core/elements/OsmUtils.cpp b/hoot-core/src/main/cpp/hoot/core/elements/OsmUtils.cpp index 264064b104..de488a75fe 100644 --- a/hoot-core/src/main/cpp/hoot/core/elements/OsmUtils.cpp +++ b/hoot-core/src/main/cpp/hoot/core/elements/OsmUtils.cpp @@ -74,7 +74,7 @@ void OsmUtils::printNodes(const QString& nodeCollectionName, } } -const QList OsmUtils::nodesToNodeIds(const QList>& nodes) +QList OsmUtils::nodesToNodeIds(const QList>& nodes) { QList nodeIds; for (QList>::const_iterator it = nodes.constBegin(); @@ -86,6 +86,21 @@ const QList OsmUtils::nodesToNodeIds(const QList OsmUtils::nodesToNodeIds(const std::vector>& nodes) +{ + std::vector nodeIds; + for (std::vector>::const_iterator it = nodes.begin(); + it != nodes.end(); ++it) + { + std::shared_ptr node = *it; + if (node) + { + nodeIds.push_back(node->getElementId().getId()); + } + } + return nodeIds; +} + QList> OsmUtils::nodeIdsToNodes( const QList& nodeIds, const std::shared_ptr& map) { @@ -97,6 +112,75 @@ QList> OsmUtils::nodeIdsToNodes( return nodes; } +std::vector> OsmUtils::nodeIdsToNodes( + const std::vector& nodeIds, const std::shared_ptr& map) +{ + std::vector> nodes; + for (std::vector::const_iterator it = nodeIds.begin(); it != nodeIds.end(); ++it) + { + nodes.push_back(std::dynamic_pointer_cast(map->getElement(ElementType::Node, *it))); + } + return nodes; +} + +bool OsmUtils::nodeCoordsMatch(std::vector> nodes1, + std::vector> nodes2) +{ + if (nodes1.size() != nodes2.size()) + { + return false; + } + + for (size_t i = 0; i < nodes1.size(); i++) + { + ConstNodePtr node1 = nodes1[i]; + ConstNodePtr node2 = nodes2[i]; + + if (!node1 || !node2) + { + return false; + } + + if (!node1->coordsMatch(*node2)) + { + return false; + } + } + + return true; +} + +QString OsmUtils::nodeCoordsToString(const std::vector& nodes) +{ + QString str; + const int comparisonSensitivity = ConfigOptions().getNodeComparisonCoordinateSensitivity(); + for (size_t i = 0; i < nodes.size(); i++) + { + ConstNodePtr node = nodes[i]; + if (node) + { + str += + "ID: " + QString::number(node->getId()) + ", X: " + + QString::number(node->getX(), 'f', comparisonSensitivity) + ", Y: " + + QString::number(node->getY(), 'f', comparisonSensitivity) + "; "; + } + else + { + str += "null coord; "; + } + } + str.chop(2); + return str; +} + +bool OsmUtils::nodeCoordsMatch(const ConstWayPtr& way1, const ConstWayPtr& way2, + const ConstOsmMapPtr& map) +{ + return + nodeCoordsMatch( + nodeIdsToNodes(way1->getNodeIds(), map), nodeIdsToNodes(way2->getNodeIds(), map)); +} + Coordinate OsmUtils::nodeToCoord(const std::shared_ptr& node) { return Coordinate(node->getX(), node->getY()); @@ -162,6 +246,11 @@ QString OsmUtils::getRelationMembersDetailedString(const ConstRelationPtr& relat return str; } +QString OsmUtils::getWayNodesDetailedString(const ConstWayPtr& way, const ConstOsmMapPtr& map) +{ + return nodeCoordsToString(nodeIdsToNodes(way->getNodeIds(), map)); +} + long OsmUtils::getFirstWayIdFromRelation(const ConstRelationPtr& relation, const OsmMapPtr& map) { const std::vector& relationMembers = relation->getMembers(); @@ -192,7 +281,12 @@ void OsmUtils::logElementDetail(const ConstElementPtr& element, const ConstOsmMa { LOG_VAR(message); LOG_VAR(element); - if (element->getElementType() == ElementType::Relation) + if (element->getElementType() == ElementType::Way) + { + ConstWayPtr way = std::dynamic_pointer_cast(element); + LOG_VAR(OsmUtils::getWayNodesDetailedString(way, map)); + } + else if (element->getElementType() == ElementType::Relation) { ConstRelationPtr relation = std::dynamic_pointer_cast(element); LOG_VAR(OsmUtils::getRelationMembersDetailedString(relation, map)); @@ -571,7 +665,7 @@ bool OsmUtils::allElementsHaveAnyTagKey(const QStringList& tagKeys, } bool OsmUtils::allElementsHaveAnyKvp(const QStringList& kvps, - const std::set& elementIds, OsmMapPtr& map) + const std::set& elementIds, OsmMapPtr& map) { std::vector elements; for (std::set::const_iterator it = elementIds.begin(); it != elementIds.end(); ++it) @@ -582,7 +676,7 @@ bool OsmUtils::allElementsHaveAnyKvp(const QStringList& kvps, } bool OsmUtils::anyElementsHaveAnyTagKey(const QStringList& tagKeys, - const std::set& elementIds, OsmMapPtr& map) + const std::set& elementIds, OsmMapPtr& map) { std::vector elements; for (std::set::const_iterator it = elementIds.begin(); it != elementIds.end(); ++it) @@ -593,7 +687,7 @@ bool OsmUtils::anyElementsHaveAnyTagKey(const QStringList& tagKeys, } bool OsmUtils::anyElementsHaveAnyKvp(const QStringList& kvps, - const std::set& elementIds, OsmMapPtr& map) + const std::set& elementIds, OsmMapPtr& map) { std::vector elements; for (std::set::const_iterator it = elementIds.begin(); it != elementIds.end(); ++it) diff --git a/hoot-core/src/main/cpp/hoot/core/elements/OsmUtils.h b/hoot-core/src/main/cpp/hoot/core/elements/OsmUtils.h index 5fd694df5e..772082cace 100644 --- a/hoot-core/src/main/cpp/hoot/core/elements/OsmUtils.h +++ b/hoot-core/src/main/cpp/hoot/core/elements/OsmUtils.h @@ -65,23 +65,72 @@ class OsmUtils const QList>& nodes); /** - Retrieves a collection of node ID's for a collection of nodes + Retrieves a collection of node IDs for a collection of nodes @param nodes a collection of nodes - @return a collection of node ID's + @return a collection of node IDs */ - static const QList nodesToNodeIds(const QList>& nodes); + static QList nodesToNodeIds(const QList>& nodes); /** - Retrieves a collection of nodes given a collection of node ID's + * Retrieves a collection of node IDs for a collection of nodes + * + * @param nodes a collection of nodes + * @return a collection of node IDs + */ + static std::vector nodesToNodeIds(const std::vector>& nodes); + + /** + Retrieves a collection of nodes given a collection of node IDs - @param nodeIds a collection of node ID's - @param map the map owning the nodes with the given ID's + @param nodeIds a collection of node IDs + @param map the map owning the nodes with the given IDs @return a collection of nodes */ static QList> nodeIdsToNodes( const QList& nodeIds, const std::shared_ptr& map); + /** + * Retrieves a collection of nodes given a collection of node IDs + * + * @param nodeIds a collection of node IDs + * @param map the map owning the nodes with the given IDs + * @return a collection of nodes + */ + static std::vector> nodeIdsToNodes( + const std::vector& nodeIds, const std::shared_ptr& map); + + /** + * Determines if the coordinates from two collection of nodes match, given a configurable + * tolerance + * + * @param nodes1 the first collection of nodes to compare + * @param nodes2 the second collection of nodes to compare + * @return true if the coordinates match; false otherwise + */ + static bool nodeCoordsMatch(std::vector> nodes1, + std::vector> nodes2); + + /** + * Determines if the way node coordinates from two ways match, given a configurable + * tolerance + * + * @param way1 the first way with nodes to compare + * @param way2 the second way with nodes to compare + * @param map the map owning the ways + * @return true if the way node coordinates match; false otherwise + */ + static bool nodeCoordsMatch(const ConstWayPtr& way1, const ConstWayPtr& way2, + const ConstOsmMapPtr& map); + + /** + * Returns a printable string for a collection of nodes + * + * @param nodes the nodes for which to create a string + * @return a string + */ + static QString nodeCoordsToString(const std::vector& nodes); + /** Converts a OSM node to a coordinate @@ -215,6 +264,15 @@ class OsmUtils static QString getRelationMembersDetailedString(const ConstRelationPtr& relation, const ConstOsmMapPtr& map); + /** + * Get a detailed string respresenting a way's nodes + * + * @param way way to get info from + * @param map map owning the way + * @return a detailed way nodes string + */ + static QString getWayNodesDetailedString(const ConstWayPtr& way, const ConstOsmMapPtr& map); + /** * Returns the first way ID from a set of relation members * diff --git a/hoot-core/src/main/cpp/hoot/core/elements/Way.cpp b/hoot-core/src/main/cpp/hoot/core/elements/Way.cpp index 939efda1fc..87f87495a3 100644 --- a/hoot-core/src/main/cpp/hoot/core/elements/Way.cpp +++ b/hoot-core/src/main/cpp/hoot/core/elements/Way.cpp @@ -479,4 +479,9 @@ long Way::getPid(long p, long c) else return WayData::PID_EMPTY; } +bool Way::hasSameNodeIds(const Way& other) const +{ + return getNodeIds() == other.getNodeIds(); +} + } diff --git a/hoot-core/src/main/cpp/hoot/core/elements/Way.h b/hoot-core/src/main/cpp/hoot/core/elements/Way.h index 819cf7a07e..80fc0930dc 100644 --- a/hoot-core/src/main/cpp/hoot/core/elements/Way.h +++ b/hoot-core/src/main/cpp/hoot/core/elements/Way.h @@ -186,6 +186,15 @@ class Way : public Element */ void reverseOrder(); + /** + * Determines if two ways have the same node IDs + * + * @param other way to compare node IDs with + * @return true if the other way has the same node IDs in the same order as this way; false + * otherwise + */ + bool hasSameNodeIds(const Way& other) const; + /** * This is rarely used. Primarily it is useful when loading the way from a file that does * cache way envelope bounds (see .osm.pbf). diff --git a/hoot-core/src/main/cpp/hoot/core/ops/NamedOp.cpp b/hoot-core/src/main/cpp/hoot/core/ops/NamedOp.cpp index cf1d47ca29..5cd00d1f1d 100644 --- a/hoot-core/src/main/cpp/hoot/core/ops/NamedOp.cpp +++ b/hoot-core/src/main/cpp/hoot/core/ops/NamedOp.cpp @@ -37,6 +37,7 @@ #include #include #include +#include // Qt #include @@ -99,6 +100,7 @@ void NamedOp::apply(OsmMapPtr& map) LOG_DEBUG( "\tElement count before operation " << s << ": " << StringUtils::formatLargeNumber(map->getElementCount())); + LOG_DEBUG("Projection before " << s << ": " << MapProjector::toWkt(map->getProjection())); // We could benefit from passing progress into some of the ops to get more granular feedback. @@ -161,6 +163,8 @@ void NamedOp::apply(OsmMapPtr& map) opCount++; OsmMapWriterFactory::writeDebugMap(map, "after-" + s.replace("hoot::", "")); + + LOG_DEBUG("Projection after " << s << ": " << MapProjector::toWkt(map->getProjection())); } } diff --git a/hoot-core/src/main/cpp/hoot/core/ops/RemoveRoundabouts.cpp b/hoot-core/src/main/cpp/hoot/core/ops/RemoveRoundabouts.cpp index 49c882e781..e2854f581e 100644 --- a/hoot-core/src/main/cpp/hoot/core/ops/RemoveRoundabouts.cpp +++ b/hoot-core/src/main/cpp/hoot/core/ops/RemoveRoundabouts.cpp @@ -37,6 +37,7 @@ #include #include #include +#include // Qt #include @@ -52,8 +53,10 @@ RemoveRoundabouts::RemoveRoundabouts() { } -void RemoveRoundabouts::removeRoundabouts(std::vector &removed) +void RemoveRoundabouts::removeRoundabouts(std::vector& removed) { + LOG_TRACE("Removing roundabouts..."); + // Get a list of roundabouts in the map RoundaboutCriterion roundaboutCrit; for (WayMap::const_iterator it = _pMap->getWays().begin(); it != _pMap->getWays().end(); ++it) @@ -72,6 +75,7 @@ void RemoveRoundabouts::removeRoundabouts(std::vector &removed) RoundaboutPtr rnd = Roundabout::makeRoundabout(_pMap, pWay); removed.push_back(rnd); } + LOG_VART(removed.size()); // Exit if there are no roundabouts removed if (removed.size() == 0) @@ -102,6 +106,10 @@ void RemoveRoundabouts::removeRoundabouts(std::vector &removed) removed[i]->overrideRoundabout(); } } + + // This could be very expensive...enable for debugging only. + //OsmMapWriterFactory::writeDebugMap( + //_pMap, "after-handline-crossing-ways-" + QString::number(i + 1)); } // Mangle the last way if it doesn't have a sibling @@ -111,19 +119,26 @@ void RemoveRoundabouts::removeRoundabouts(std::vector &removed) removed[removed.size() - 1]->overrideRoundabout(); } + OsmMapWriterFactory::writeDebugMap(_pMap, "after-handline-crossing-ways"); + // Now remove roundabouts for (size_t i = 0; i < removed.size(); i++) { removed[i]->removeRoundabout(_pMap); _numAffected++; + + // This could be very expensive...enable for debugging only. + //OsmMapWriterFactory::writeDebugMap( + //_pMap, "after-removing-roundabout-" + QString::number(i + 1)); } } -void RemoveRoundabouts::apply(OsmMapPtr &pMap) +void RemoveRoundabouts::apply(OsmMapPtr& pMap) { _numAffected = 0; _pMap = pMap; + LOG_VART(MapProjector::toWkt(pMap->getProjection())); MapProjector::projectToPlanar(_pMap); std::vector removed; diff --git a/hoot-core/src/main/cpp/hoot/core/ops/ReplaceRoundabouts.cpp b/hoot-core/src/main/cpp/hoot/core/ops/ReplaceRoundabouts.cpp index 34fde1487c..a060dd8c07 100644 --- a/hoot-core/src/main/cpp/hoot/core/ops/ReplaceRoundabouts.cpp +++ b/hoot-core/src/main/cpp/hoot/core/ops/ReplaceRoundabouts.cpp @@ -39,6 +39,7 @@ #include #include #include +#include // Qt #include @@ -56,24 +57,36 @@ ReplaceRoundabouts::ReplaceRoundabouts() void ReplaceRoundabouts::replaceRoundabouts(const std::shared_ptr& pMap) { + LOG_TRACE("Replacing roundabouts..."); + // Make sure we are planar MapProjector::projectToPlanar(pMap); // Get a list of roundabouts from the map, go through & process them std::vector roundabouts = pMap->getRoundabouts(); + LOG_VART(roundabouts.size()); for (size_t i = 0; i < roundabouts.size(); i++) { RoundaboutPtr pRoundabout = roundabouts[i]; pRoundabout->replaceRoundabout(pMap); _numAffected++; + + // This could be very expensive...enable for debugging only. + //OsmMapWriterFactory::writeDebugMap(pMap, "after-replacing-roundabout-" + QString::number(i + 1)); } + OsmMapWriterFactory::writeDebugMap(pMap, "after-replacing-roundabouts"); // Clean up any roundabout centers that didn't clean themselves up earlier std::vector centers = ElementIdsVisitor::findElementsByTag( pMap, ElementType::Node, MetadataTags::HootSpecial(), "roundabout_center"); + LOG_VART(centers.size()); foreach (long id, centers) + { + LOG_TRACE("Removing center node: " << id << "..."); RemoveNodeByEid::removeNode(pMap, id, true); + } + OsmMapWriterFactory::writeDebugMap(pMap, "roundabout-replacement-after-removing-center-nodes"); } void ReplaceRoundabouts::apply(std::shared_ptr& pMap) diff --git a/hoot-core/src/main/cpp/hoot/core/ops/UnconnectedWaySnapper.cpp b/hoot-core/src/main/cpp/hoot/core/ops/UnconnectedWaySnapper.cpp index e4da3b42af..7f8c3365e5 100644 --- a/hoot-core/src/main/cpp/hoot/core/ops/UnconnectedWaySnapper.cpp +++ b/hoot-core/src/main/cpp/hoot/core/ops/UnconnectedWaySnapper.cpp @@ -753,6 +753,10 @@ bool UnconnectedWaySnapper::_snapUnconnectedNodeToWay(const NodePtr& nodeToSnap) bool UnconnectedWaySnapper::snapClosestEndpointToWay(OsmMapPtr map, const WayPtr& disconnected, const WayPtr& connectTo) { + LOG_TRACE( + "Attempting to snap " << disconnected->getElementId() << " to " << connectTo->getElementId() << + "..."); + // Create object for static call UnconnectedWaySnapper uws; uws._map = map; diff --git a/hoot-core/src/main/cpp/hoot/core/scoring/MapComparator.cpp b/hoot-core/src/main/cpp/hoot/core/scoring/MapComparator.cpp index 66c6e19bbb..c00d660e66 100644 --- a/hoot-core/src/main/cpp/hoot/core/scoring/MapComparator.cpp +++ b/hoot-core/src/main/cpp/hoot/core/scoring/MapComparator.cpp @@ -269,6 +269,7 @@ void MapComparator::_printIdDiff( { QSet ids1; QSet ids2; + LOG_VARD(limit); switch (elementType.getEnum()) { @@ -299,16 +300,60 @@ void MapComparator::_printIdDiff( QSet ids1Copy = ids1; const QSet idsIn1AndNotIn2 = ids1Copy.subtract(ids2); + QSet idsIn1AndNotIn2Limited; + if (limit < idsIn1AndNotIn2.size()) + { + int ctr = 0; + for (QSet::const_iterator it = idsIn1AndNotIn2.begin(); it != idsIn1AndNotIn2.end(); ++it) + { + idsIn1AndNotIn2Limited.insert(*it); + ctr++; + + if (ctr == limit) + { + break; + } + } + } + else + { + idsIn1AndNotIn2Limited = idsIn1AndNotIn2; + } QSet ids2Copy = ids2; const QSet idsIn2AndNotIn1 = ids2Copy.subtract(ids1); + QSet idsIn2AndNotIn1Limited; + if (limit < idsIn2AndNotIn1.size()) + { + int ctr = 0; + for (QSet::const_iterator it = idsIn2AndNotIn1.begin(); it != idsIn2AndNotIn1.end(); ++it) + { + idsIn2AndNotIn1Limited.insert(*it); + ctr++; + + if (ctr == limit) + { + break; + } + } + } + else + { + idsIn2AndNotIn1Limited = idsIn2AndNotIn1; + } - LOG_WARN( - "\t" << elementType.toString() << "s in map 1 and not in map 2 (limit " << limit << "): " << - idsIn1AndNotIn2); - LOG_WARN( - "\t" << elementType.toString() << "s in map 2 and not in map 1 (limit " << limit << "): " << - idsIn2AndNotIn1); + if (idsIn1AndNotIn2Limited.size() > 0) + { + LOG_WARN( + "\t" << elementType.toString() << "s in map 1 and not in map 2 (limit " << limit << "): " << + idsIn1AndNotIn2Limited); + } + if (idsIn2AndNotIn1Limited.size() > 0) + { + LOG_WARN( + "\t" << elementType.toString() << "s in map 2 and not in map 1 (limit " << limit << "): " << + idsIn2AndNotIn1Limited); + } } bool MapComparator::isMatch(const std::shared_ptr& refMap, diff --git a/test-files/cases/differential/Config.conf b/test-files/cases/differential/Config.conf index eeac260bac..3463889df7 100644 --- a/test-files/cases/differential/Config.conf +++ b/test-files/cases/differential/Config.conf @@ -1,5 +1,6 @@ { "base.config": "UnifyingAlgorithm.conf,DifferentialConflation.conf", + "test.case.conflate.differential": "true", "uuid.helper.repeatable": "true", "writer.include.debug.tags": "true", "#": "end" diff --git a/test-files/cases/differential/reviews-as-matches-off-3387-1/Config.conf b/test-files/cases/differential/reviews-as-matches-off-3387-1/Config.conf new file mode 100644 index 0000000000..a661cd4a62 --- /dev/null +++ b/test-files/cases/differential/reviews-as-matches-off-3387-1/Config.conf @@ -0,0 +1,9 @@ +{ + "base.config": "UnifyingAlgorithm.conf,DifferentialConflation.conf", + "test.case.conflate.differential": "true", + "test.case.conflate.differential.include.tags": "true", + "differential.treat.reviews.as.matches": "false", + "uuid.helper.repeatable": "true", + "writer.include.debug.tags": "true", + "#": "end" +} diff --git a/test-files/cases/differential/reviews-as-matches-off-3387-1/Expected.osm b/test-files/cases/differential/reviews-as-matches-off-3387-1/Expected.osm new file mode 100644 index 0000000000..1386ee9e9a --- /dev/null +++ b/test-files/cases/differential/reviews-as-matches-off-3387-1/Expected.osm @@ -0,0 +1,709 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-files/cases/differential/reviews-as-matches-off-3387-1/Input1.osm b/test-files/cases/differential/reviews-as-matches-off-3387-1/Input1.osm new file mode 100644 index 0000000000..ca94ad2785 --- /dev/null +++ b/test-files/cases/differential/reviews-as-matches-off-3387-1/Input1.osm @@ -0,0 +1,297 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-files/cases/differential/reviews-as-matches-off-3387-1/Input2.osm b/test-files/cases/differential/reviews-as-matches-off-3387-1/Input2.osm new file mode 100644 index 0000000000..903630f6d2 --- /dev/null +++ b/test-files/cases/differential/reviews-as-matches-off-3387-1/Input2.osm @@ -0,0 +1,531 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-files/cases/differential/reviews-as-matches-off-3387-1/README.txt b/test-files/cases/differential/reviews-as-matches-off-3387-1/README.txt new file mode 100644 index 0000000000..d5b34e0fa4 --- /dev/null +++ b/test-files/cases/differential/reviews-as-matches-off-3387-1/README.txt @@ -0,0 +1,4 @@ +This is an Differential Conflation test that does not treat reviews as matches. Therefore, you should see a large group of restaurant POIs +involved in reviews passed through to output. If differential.treat.reviews.as.matches was set to the default value of true, you would not +see these POIs pass through to output, since the reviews they are in would be treated as matches and the features in those matches automatically +dropped from the output. diff --git a/test-files/cases/differential/roundabout-3580-network-1/Config.conf b/test-files/cases/differential/roundabout-3580-network-1/Config.conf new file mode 100644 index 0000000000..c4ab9e89fd --- /dev/null +++ b/test-files/cases/differential/roundabout-3580-network-1/Config.conf @@ -0,0 +1,8 @@ +{ + "base.config": "NetworkAlgorithm.conf,DifferentialConflation.conf", + "test.case.conflate.differential": "true", + "test.case.conflate.differential.include.tags": "true", + "uuid.helper.repeatable": "true", + "writer.include.debug.tags": "true", + "#": "end" +} diff --git a/test-files/cases/differential/roundabout-3580-network-1/Expected.osm b/test-files/cases/differential/roundabout-3580-network-1/Expected.osm new file mode 100644 index 0000000000..86b0097a4c --- /dev/null +++ b/test-files/cases/differential/roundabout-3580-network-1/Expected.osm @@ -0,0 +1,436 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-files/cases/differential/roundabout-3580-network-1/Input1.osm b/test-files/cases/differential/roundabout-3580-network-1/Input1.osm new file mode 100644 index 0000000000..3aa665484c --- /dev/null +++ b/test-files/cases/differential/roundabout-3580-network-1/Input1.osm @@ -0,0 +1,560 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-files/cases/differential/roundabout-3580-network-1/Input2.osm b/test-files/cases/differential/roundabout-3580-network-1/Input2.osm new file mode 100644 index 0000000000..c250a54ceb --- /dev/null +++ b/test-files/cases/differential/roundabout-3580-network-1/Input2.osm @@ -0,0 +1,606 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-files/cases/differential/roundabout-3580-network-1/README.txt b/test-files/cases/differential/roundabout-3580-network-1/README.txt new file mode 100644 index 0000000000..88bf9193e5 --- /dev/null +++ b/test-files/cases/differential/roundabout-3580-network-1/README.txt @@ -0,0 +1,2 @@ +This is an Differential Conflation test using the Network Roads Algorithm that attempts to ensure that a roundabout that matches between +reference and secondary data is not passed through to output. diff --git a/test-files/cases/differential/roundabout-3580-unifying-1/Config.conf b/test-files/cases/differential/roundabout-3580-unifying-1/Config.conf new file mode 100644 index 0000000000..08c743764d --- /dev/null +++ b/test-files/cases/differential/roundabout-3580-unifying-1/Config.conf @@ -0,0 +1,8 @@ +{ + "base.config": "UnifyingAlgorithm.conf,DifferentialConflation.conf", + "test.case.conflate.differential": "true", + "test.case.conflate.differential.include.tags": "true", + "uuid.helper.repeatable": "true", + "writer.include.debug.tags": "true", + "#": "end" +} diff --git a/test-files/cases/differential/roundabout-3580-unifying-1/Expected.osm b/test-files/cases/differential/roundabout-3580-unifying-1/Expected.osm new file mode 100644 index 0000000000..5290e51a69 --- /dev/null +++ b/test-files/cases/differential/roundabout-3580-unifying-1/Expected.osm @@ -0,0 +1,518 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-files/cases/differential/roundabout-3580-unifying-1/Input1.osm b/test-files/cases/differential/roundabout-3580-unifying-1/Input1.osm new file mode 100644 index 0000000000..3aa665484c --- /dev/null +++ b/test-files/cases/differential/roundabout-3580-unifying-1/Input1.osm @@ -0,0 +1,560 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-files/cases/differential/roundabout-3580-unifying-1/Input2.osm b/test-files/cases/differential/roundabout-3580-unifying-1/Input2.osm new file mode 100644 index 0000000000..c250a54ceb --- /dev/null +++ b/test-files/cases/differential/roundabout-3580-unifying-1/Input2.osm @@ -0,0 +1,606 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-files/cases/differential/roundabout-3580-unifying-1/README.txt b/test-files/cases/differential/roundabout-3580-unifying-1/README.txt new file mode 100644 index 0000000000..1fc36bea69 --- /dev/null +++ b/test-files/cases/differential/roundabout-3580-unifying-1/README.txt @@ -0,0 +1,2 @@ +This is an Differential Conflation test using the Unifying Roads Algorithm that ensures that a roundabout that matches between reference and +secondary data is not passed through to output. diff --git a/test-files/cases/hoot-rnd/multiary-poi/Config.conf b/test-files/cases/hoot-rnd/multiary-poi/Config.conf index 96a9f5d122..978908873e 100644 --- a/test-files/cases/hoot-rnd/multiary-poi/Config.conf +++ b/test-files/cases/hoot-rnd/multiary-poi/Config.conf @@ -1,5 +1,5 @@ { - "test.case.cmd": "hoot::MultiaryConflateCmd", + "test.case.conflate.cmd": "hoot::MultiaryConflateCmd", "conflate.pre.ops": "hoot::ImplicitPoiTypeTagger", "log.warn.message.limit": "100000000" } diff --git a/test-files/cmd/slow/DiffConflateTagChangeDifferingGeometriesTest/output.tags.osc b/test-files/cmd/slow/DiffConflateTagChangeDifferingGeometriesTest/output.tags.osc index 7f60cbe96f..2cb9ab4f51 100644 --- a/test-files/cmd/slow/DiffConflateTagChangeDifferingGeometriesTest/output.tags.osc +++ b/test-files/cmd/slow/DiffConflateTagChangeDifferingGeometriesTest/output.tags.osc @@ -46,30 +46,26 @@ - - - - - - - - - - + + + + + - + + + - - - - - + + + + - + - + @@ -90,10 +86,49 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -105,14 +140,22 @@ - - - - + + + + + + + + + + + + - + @@ -126,28 +169,14 @@ - - - - - - - - - - - - - - - + + + - - + - @@ -186,42 +215,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -245,16 +238,6 @@ - - - - - - - - - - @@ -277,28 +260,6 @@ - - - - - - - - - - - - - - - - - - - - - -