From dc87c60cb70751a439e188464141237bfcf2b4de Mon Sep 17 00:00:00 2001 From: Brandon Witham <303724+bwitham@users.noreply.github.com> Date: Thu, 31 Oct 2019 12:36:52 -0400 Subject: [PATCH] 3387 - Add option to diff conflate to keep reviews in output and more (#3588) * Added an option, `differential.treat.reviews.as.matches`, that allows for not treating reviews as matches in Differential Conflation, which will let them pass to the diff output. The use case for this was a situation where a one to many POI review was preventing several secondary POIs from being added to the diff. Since some of these reviews were questionable, the longer term solution to this is some reworking of POI reviews (#3579). In the meantime, this config option may be useful. * Disabled the removal/replacement of roundabouts during Differential Conflation. in #3580 there was a situation where roundabouts were being mangled badly during roundabout replacement. The original point of roundabout removal/replacement was to preserve them, since we don't conflate them very well some of the time. However with diff conflate, there's no chance to mangle them since we're only keeping non-matches in the secondary data and not actually trying to merge ref and secondary roundabouts...so removing the logic was the simplest solution. * Downgraded warning logged when diff conflate w/ tags encounters a relation to a debug statement, since that is normal operation for now. #3449 can be re-opened to handle relations if need be. * Fixed a NPE in the Network alg when running ref conflate with the same data from #3387 * Fixed issue where diff conflate case tests were not actually running diff conflate * Fxied handling of output size limit in `MapComparator::_printIdDiff` * Added in some utilities to `Roundabout`, `OsmUtils`, `Node`, and `Way` that make debugging roundabout conflate problems easier --- conf/core/ConfigOptions.asciidoc | 27 +- conf/services/conflationTypes.json | 1 + .../cpp/hoot/core/test/ConflateCaseTest.cpp | 24 +- .../NaiveWayMatchStringMapping.h | 2 + .../linearreference/WayMatchStringMapping.h | 3 + .../optimizer/IntegerProgrammingSolver.cpp | 6 +- .../main/cpp/hoot/core/cmd/ConflateCmd.cpp | 50 +- .../src/main/cpp/hoot/core/cmd/ConflateCmd.h | 3 +- .../cpp/hoot/core/conflate/DiffConflator.cpp | 70 +- .../cpp/hoot/core/conflate/DiffConflator.h | 17 +- .../hoot/core/conflate/highway/Roundabout.cpp | 246 ++++-- .../hoot/core/conflate/highway/Roundabout.h | 32 +- .../core/conflate/matching/MatchThreshold.cpp | 18 +- .../core/conflate/network/NetworkDetails.cpp | 7 + .../conflate/network/PartialNetworkMerger.cpp | 31 +- .../src/main/cpp/hoot/core/elements/Node.cpp | 18 + .../src/main/cpp/hoot/core/elements/Node.h | 9 + .../main/cpp/hoot/core/elements/OsmUtils.cpp | 104 ++- .../main/cpp/hoot/core/elements/OsmUtils.h | 70 +- .../src/main/cpp/hoot/core/elements/Way.cpp | 5 + .../src/main/cpp/hoot/core/elements/Way.h | 9 + .../src/main/cpp/hoot/core/ops/NamedOp.cpp | 4 + .../cpp/hoot/core/ops/RemoveRoundabouts.cpp | 19 +- .../cpp/hoot/core/ops/ReplaceRoundabouts.cpp | 13 + .../hoot/core/ops/UnconnectedWaySnapper.cpp | 4 + .../cpp/hoot/core/scoring/MapComparator.cpp | 57 +- test-files/cases/differential/Config.conf | 1 + .../reviews-as-matches-off-3387-1/Config.conf | 9 + .../Expected.osm | 709 ++++++++++++++++++ .../reviews-as-matches-off-3387-1/Input1.osm | 297 ++++++++ .../reviews-as-matches-off-3387-1/Input2.osm | 531 +++++++++++++ .../reviews-as-matches-off-3387-1/README.txt | 4 + .../roundabout-3580-network-1/Config.conf | 8 + .../roundabout-3580-network-1/Expected.osm | 436 +++++++++++ .../roundabout-3580-network-1/Input1.osm | 560 ++++++++++++++ .../roundabout-3580-network-1/Input2.osm | 606 +++++++++++++++ .../roundabout-3580-network-1/README.txt | 2 + .../roundabout-3580-unifying-1/Config.conf | 8 + .../roundabout-3580-unifying-1/Expected.osm | 518 +++++++++++++ .../roundabout-3580-unifying-1/Input1.osm | 560 ++++++++++++++ .../roundabout-3580-unifying-1/Input2.osm | 606 +++++++++++++++ .../roundabout-3580-unifying-1/README.txt | 2 + .../cases/hoot-rnd/multiary-poi/Config.conf | 2 +- .../output.tags.osc | 181 ++--- 44 files changed, 5627 insertions(+), 262 deletions(-) create mode 100644 test-files/cases/differential/reviews-as-matches-off-3387-1/Config.conf create mode 100644 test-files/cases/differential/reviews-as-matches-off-3387-1/Expected.osm create mode 100644 test-files/cases/differential/reviews-as-matches-off-3387-1/Input1.osm create mode 100644 test-files/cases/differential/reviews-as-matches-off-3387-1/Input2.osm create mode 100644 test-files/cases/differential/reviews-as-matches-off-3387-1/README.txt create mode 100644 test-files/cases/differential/roundabout-3580-network-1/Config.conf create mode 100644 test-files/cases/differential/roundabout-3580-network-1/Expected.osm create mode 100644 test-files/cases/differential/roundabout-3580-network-1/Input1.osm create mode 100644 test-files/cases/differential/roundabout-3580-network-1/Input2.osm create mode 100644 test-files/cases/differential/roundabout-3580-network-1/README.txt create mode 100644 test-files/cases/differential/roundabout-3580-unifying-1/Config.conf create mode 100644 test-files/cases/differential/roundabout-3580-unifying-1/Expected.osm create mode 100644 test-files/cases/differential/roundabout-3580-unifying-1/Input1.osm create mode 100644 test-files/cases/differential/roundabout-3580-unifying-1/Input2.osm create mode 100644 test-files/cases/differential/roundabout-3580-unifying-1/README.txt 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 @@ - - - - - - - - - - - - - - - - - - - - - -