Skip to content

Commit dc87c60

Browse files
authored
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
1 parent 26e93e0 commit dc87c60

File tree

44 files changed

+5627
-262
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+5627
-262
lines changed

conf/core/ConfigOptions.asciidoc

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -924,6 +924,15 @@ secondary road endpoint nodes to the nearest reference road.
924924

925925
List of tags to ignore when performing differential conflation with tags.
926926

927+
=== differential.treat.reviews.as.matches
928+
929+
* Data Type: bool
930+
* Default Value: `true`
931+
932+
If true reviews are treated as matches by Differential Conflation and removed from the output if
933+
differential.remove.reference.data is enabled. If set to false, reviews are not treated as matches
934+
and will pass through to the differential output.
935+
927936
=== direction.finder.angle.threshold
928937

929938
* Data Type: double
@@ -4316,14 +4325,30 @@ Minimum tag numeric value that will allow the TagValueNumericRangeCriterion to b
43164325
For commands supporting it, the iteration count at which a status message should be logged. This
43174326
setting may have a negative impact on performance if set to a very low value.
43184327

4319-
=== test.case.cmd
4328+
=== test.case.conflate.cmd
43204329

43214330
* Data Type: string
43224331
* Default Value: `hoot::ConflateCmd`
43234332

43244333
Set the conflate command that should be used in a test case. This is only useful when writing
43254334
test cases (`test-files/cases/`) and was originally added to support the MultiaryPoiConflateCmd.
43264335

4336+
=== test.case.conflate.differential
4337+
4338+
* Data Type: bool
4339+
* Default Value: `false`
4340+
4341+
When activated, this runs the conflate case test conflate command with the --differential option.
4342+
4343+
=== test.case.conflate.differential.include.tags
4344+
4345+
* Data Type: bool
4346+
* Default Value: `false`
4347+
4348+
When activated, this runs the conflate case test conflate command with both the --differential
4349+
and --include-tags options (setting this to true automatically sets test.case.conflate.differential
4350+
to true).
4351+
43274352
=== test.force.orthographic.projection
43284353

43294354
* Data Type: bool

conf/services/conflationTypes.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"members": {
2828
"differential.remove.unconflatable.data": "Pass unconflatable data from the secondary input to output",
2929
"differential.snap.unconnected.roads": "Snap unconnected secondary roads to reference roads",
30+
"differential.treat.reviews.as.matches": "Treat reviews as matches and remove from output",
3031
"snap.unconnected.ways.snap.tolerance": "Maximum distance, in meters, to allow snapping unconnected roads to neighboring roads",
3132
"snap.unconnected.ways.use.existing.way.nodes": "Reuse highway nodes when snapping unconnected roads",
3233
"snap.unconnected.ways.existing.way.node.tolerance": "Maximum distance, in meters, to allow snapping unconnected highway nodes to neighboring roads"

hoot-core-test/src/test/cpp/hoot/core/test/ConflateCaseTest.cpp

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,22 @@ void ConflateCaseTest::_runConflateCmd()
7272
args << in1.absoluteFilePath();
7373
args << in2.absoluteFilePath();
7474
args << testOutput;
75+
bool differential = ConfigOptions().getTestCaseConflateDifferential();
76+
const bool differentialWithTags = ConfigOptions().getTestCaseConflateDifferentialIncludeTags();
77+
if (differentialWithTags)
78+
{
79+
// let this override and correct what would otherwise be an invalid config
80+
differential = true;
81+
}
82+
if (differential)
83+
{
84+
args << "--differential";
85+
}
86+
if (differentialWithTags)
87+
{
88+
args << "--include-tags";
89+
}
90+
7591
int result = -1;
7692
try
7793
{
@@ -85,8 +101,8 @@ void ConflateCaseTest::_runConflateCmd()
85101
QFileInfo expected(_d, "Expected.osm");
86102
if (expected.exists() == false)
87103
{
88-
throw IllegalArgumentException("Unable to find Expected.osm in conflate case: " +
89-
_d.absolutePath());
104+
throw IllegalArgumentException(
105+
"Unable to find Expected.osm in conflate case: " + _d.absolutePath());
90106
}
91107

92108
if (result != 0)
@@ -176,11 +192,11 @@ void ConflateCaseTest::runTest()
176192
// configures and cleans up the conf() environment
177193
TestSetup st(_confs);
178194

179-
if (ConfigOptions().getTestCaseCmd().toStdString() == ConflateCmd::className())
195+
if (ConfigOptions().getTestCaseConflateCmd().toStdString() == ConflateCmd::className())
180196
{
181197
_runConflateCmd();
182198
}
183-
else if (ConfigOptions().getTestCaseCmd() == multiaryConflateClass)
199+
else if (ConfigOptions().getTestCaseConflateCmd() == multiaryConflateClass)
184200
{
185201
_runMultiaryConflateCmd();
186202
}

hoot-core/src/main/cpp/hoot/core/algorithms/linearreference/NaiveWayMatchStringMapping.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class WayString;
3737
class NaiveWayMatchStringMapping : public WayMatchStringMapping
3838
{
3939
public:
40+
4041
NaiveWayMatchStringMapping(WayStringPtr str1, WayStringPtr str2);
4142

4243
virtual WayStringPtr getWayString1() { return _ws1; }
@@ -52,6 +53,7 @@ class NaiveWayMatchStringMapping : public WayMatchStringMapping
5253
virtual void setWayString2(const WayStringPtr& ws2) { _ws2 = ws2; }
5354

5455
private:
56+
5557
WayStringPtr _ws1, _ws2;
5658
Meters _length1, _length2;
5759
};

hoot-core/src/main/cpp/hoot/core/algorithms/linearreference/WayMatchStringMapping.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ class WayMatchStringMapping
8787
virtual void setWayString2(const WayStringPtr& ws2) = 0;
8888
void setWayString(WayNumber way, const WayStringPtr& ws)
8989
{ (way == WayNumber::Way1) ? setWayString1(ws) : setWayString2(ws); }
90+
91+
QString toString()
92+
{ return "1: " + getWayString1()->toString() + "; 2: " + getWayString2()->toString(); }
9093
};
9194

9295
typedef std::shared_ptr<WayMatchStringMapping> WayMatchStringMappingPtr;

hoot-core/src/main/cpp/hoot/core/algorithms/optimizer/IntegerProgrammingSolver.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
* This will properly maintain the copyright information. DigitalGlobe
2323
* copyrights will be updated automatically.
2424
*
25-
* @copyright Copyright (C) 2015, 2017, 2018 DigitalGlobe (http://www.digitalglobe.com/)
25+
* @copyright Copyright (C) 2015, 2017, 2018, 2019 DigitalGlobe (http://www.digitalglobe.com/)
2626
*/
2727
#include "IntegerProgrammingSolver.h"
2828

@@ -82,6 +82,8 @@ void IntegerProgrammingSolver::solve()
8282

8383
void IntegerProgrammingSolver::solveBranchAndCut()
8484
{
85+
LOG_DEBUG("solveBranchAndCut");
86+
8587
glp_iocp iocp;
8688
glp_init_iocp(&iocp);
8789
// Turn on the presolver so that glp_intopt works correctly
@@ -133,6 +135,8 @@ void IntegerProgrammingSolver::solveBranchAndCut()
133135

134136
void IntegerProgrammingSolver::solveSimplex()
135137
{
138+
LOG_DEBUG("solveSimplex");
139+
136140
glp_smcp smcp;
137141
glp_init_smcp(&smcp);
138142
// Setup the time limit if necessary

hoot-core/src/main/cpp/hoot/core/cmd/ConflateCmd.cpp

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@
5555
#include <hoot/core/visitors/CountUniqueReviewsVisitor.h>
5656
#include <hoot/core/util/ConfigUtils.h>
5757
#include <hoot/core/elements/OsmUtils.h>
58+
#include <hoot/core/ops/RemoveRoundabouts.h>
59+
#include <hoot/core/ops/ReplaceRoundabouts.h>
5860

5961
// Standard
6062
#include <fstream>
@@ -163,19 +165,33 @@ int ConflateCmd::runSimple(QStringList& args)
163165
Progress progress(ConfigOptions().getJobId(), JOB_SOURCE, Progress::JobState::Running);
164166
const int maxFilePrintLength = ConfigOptions().getProgressVarPrintLengthMax();
165167
QString msg =
166-
"Conflating ..." + input1.right(maxFilePrintLength) + " with ..." +
167-
input2.right(maxFilePrintLength) + " and writing the output to ..." +
168+
"Conflating " + input1.right(maxFilePrintLength) + " with " +
169+
input2.right(maxFilePrintLength) + " and writing the output to " +
168170
output.right(maxFilePrintLength);
169171
if (isDiffConflate)
170172
{
171-
msg = msg.prepend("Differentially ");
173+
if (diffConflator.conflatingTags())
174+
{
175+
msg = msg.replace("Conflating", "Differentially conflating (tags only) ");
176+
}
177+
else
178+
{
179+
msg = msg.replace("Conflating", "Differentially conflating ");
180+
}
172181
}
182+
173183
progress.set(0.0, msg);
174184

175185
double bytesRead = IoSingleStat(IoSingleStat::RChar).value;
176186
LOG_VART(bytesRead);
177187
QList<QList<SingleStat>> allStats;
178188

189+
_updateConfigOptionsForAttributeConflation();
190+
if (isDiffConflate)
191+
{
192+
_updateConfigOptionsForDifferentialConflation();
193+
}
194+
179195
// The number of steps here must be updated as you add/remove job steps in the logic.
180196
_numTotalTasks = 5;
181197
if (displayStats)
@@ -334,7 +350,6 @@ int ConflateCmd::runSimple(QStringList& args)
334350
stats.append(SingleStat("Conflation Time (sec)", t.getElapsedAndRestart()));
335351
currentTask++;
336352

337-
_updatePostConfigOptionsForAttributeConflation();
338353
if (ConfigOptions().getConflatePostOps().size() > 0)
339354
{
340355
// apply any user specified post-conflate operations
@@ -476,7 +491,32 @@ float ConflateCmd::_getJobPercentComplete(const int currentTaskNum) const
476491
return (float)currentTaskNum / (float)_numTotalTasks;
477492
}
478493

479-
void ConflateCmd::_updatePostConfigOptionsForAttributeConflation()
494+
void ConflateCmd::_updateConfigOptionsForDifferentialConflation()
495+
{
496+
// Since Differential throws out all matches, there's no way we can have a bad merge between
497+
// ref/secondary roundabouts. Therefore, no need to replace/remove them. If there's a match, we'll
498+
// end with no secondary roundabout in the diff output and only the ref roundabout when the diff
499+
// is applied back to the ref.
500+
501+
QStringList preConflateOps = ConfigOptions().getConflatePreOps();
502+
const QString removeRoundaboutsClassName = QString::fromStdString(RemoveRoundabouts::className());
503+
if (preConflateOps.contains(removeRoundaboutsClassName))
504+
{
505+
preConflateOps.removeAll(removeRoundaboutsClassName);
506+
conf().set(ConfigOptions::getConflatePreOpsKey(), preConflateOps);
507+
}
508+
509+
QStringList postConflateOps = ConfigOptions().getConflatePostOps();
510+
const QString replaceRoundaboutsClassName =
511+
QString::fromStdString(ReplaceRoundabouts::className());
512+
if (postConflateOps.contains(replaceRoundaboutsClassName))
513+
{
514+
postConflateOps.removeAll(replaceRoundaboutsClassName);
515+
conf().set(ConfigOptions::getConflatePostOpsKey(), postConflateOps);
516+
}
517+
}
518+
519+
void ConflateCmd::_updateConfigOptionsForAttributeConflation()
480520
{
481521
// These are some custom adjustments to config opts that must be done for Attribute Conflation.
482522
// There may be a way to eliminate these by adding more custom behavior to the UI.

hoot-core/src/main/cpp/hoot/core/cmd/ConflateCmd.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ class ConflateCmd : public BaseCommand
6767

6868
int _numTotalTasks;
6969

70-
void _updatePostConfigOptionsForAttributeConflation();
70+
void _updateConfigOptionsForAttributeConflation();
71+
void _updateConfigOptionsForDifferentialConflation();
7172
void _checkForTagValueTruncationOverride();
7273

7374
float _getJobPercentComplete(const int currentTaskNum) const;

hoot-core/src/main/cpp/hoot/core/conflate/DiffConflator.cpp

Lines changed: 39 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ void DiffConflator::apply(OsmMapPtr& map)
125125

126126
_updateProgress(currentStep - 1, "Matching features...");
127127

128-
// If we don't do this, then any non-matchable data will simply pass through to output.
128+
// If we skip this part, then any non-matchable data will simply pass through to output.
129129
if (ConfigOptions().getDifferentialRemoveUnconflatableData())
130130
{
131131
LOG_INFO("Discarding unconflatable elements...");
@@ -161,9 +161,8 @@ void DiffConflator::apply(OsmMapPtr& map)
161161

162162
currentStep++;
163163

164-
// Use matches to calculate and store tag diff. We must do this before we
165-
// create the map diff, because that operation deletes all of the info needed
166-
// for calculating the tag diff.
164+
// Use matches to calculate and store tag diff. We must do this before we create the map diff,
165+
// because that operation deletes all of the info needed for calculating the tag diff.
167166
_updateProgress(currentStep - 1, "Storing tag differentials...");
168167
_calcAndStoreTagChanges();
169168
currentStep++;
@@ -219,28 +218,37 @@ void DiffConflator::_snapSecondaryRoadsBackToRef()
219218
void DiffConflator::_removeMatches(const Status& status)
220219
{
221220
LOG_DEBUG("\tRemoving match elements with status: " << status.toString() << "...");
221+
222+
const bool treatReviewsAsMatches = ConfigOptions().getDifferentialTreatReviewsAsMatches();
223+
LOG_VARD(treatReviewsAsMatches);
222224
for (std::vector<ConstMatchPtr>::iterator mit = _matches.begin(); mit != _matches.end(); ++mit)
223225
{
224-
std::set<std::pair<ElementId, ElementId>> pairs = (*mit)->getMatchPairs();
225-
for (std::set<std::pair<ElementId, ElementId>>::iterator pit = pairs.begin();
226-
pit != pairs.end(); ++pit)
226+
ConstMatchPtr match = *mit;
227+
if (treatReviewsAsMatches || match->getType() != MatchType::Review)
227228
{
228-
if (!pit->first.isNull())
229+
std::set<std::pair<ElementId, ElementId>> pairs = (*mit)->getMatchPairs();
230+
for (std::set<std::pair<ElementId, ElementId>>::iterator pit = pairs.begin();
231+
pit != pairs.end(); ++pit)
229232
{
230-
LOG_VART(pit->first);
231-
ElementPtr e = _pMap->getElement(pit->first);
232-
if (e && e->getStatus() == status)
233+
if (!pit->first.isNull())
233234
{
234-
RecursiveElementRemover(pit->first).apply(_pMap);
235+
LOG_VART(pit->first);
236+
ElementPtr e = _pMap->getElement(pit->first);
237+
if (e && e->getStatus() == status)
238+
{
239+
//LOG_VART(e->getTags().get("name"));
240+
RecursiveElementRemover(pit->first).apply(_pMap);
241+
}
235242
}
236-
}
237-
if (!pit->second.isNull())
238-
{
239-
LOG_VART(pit->second);
240-
ElementPtr e = _pMap->getElement(pit->second);
241-
if (e && e->getStatus() == status)
243+
if (!pit->second.isNull())
242244
{
243-
RecursiveElementRemover(pit->second).apply(_pMap);
245+
LOG_VART(pit->second);
246+
ElementPtr e = _pMap->getElement(pit->second);
247+
if (e && e->getStatus() == status)
248+
{
249+
//LOG_VART(e->getTags().get("name"));
250+
RecursiveElementRemover(pit->second).apply(_pMap);
251+
}
244252
}
245253
}
246254
}
@@ -326,21 +334,18 @@ void DiffConflator::addChangesToMap(OsmMapPtr pMap, ChangesetProviderPtr pChange
326334
}
327335
else if (ElementType::Relation == c.getElement()->getElementType().getEnum())
328336
{
329-
// Diff conflation doesn't do relations yet
337+
// Diff conflation w/ tags doesn't handle relations. Changed this to silently log that the
338+
// relations are being skipped for now. #3449 was created to deal with adding relation support
339+
// and then closed since we lack a use case currently that requires it. If we ever get one,
340+
// then we can re-open that issue.
330341

331-
if (logWarnCount < Log::getWarnMessageLimit())
342+
LOG_DEBUG("Relation handling not implemented with differential conflation: " << c);
343+
if (Log::getInstance().getLevel() <= Log::Trace)
332344
{
333-
LOG_WARN("Relation handling not implemented with differential conflation: " << c);
334-
LOG_VART(c);
335345
ConstRelationPtr relation = std::dynamic_pointer_cast<const Relation>(c.getElement());
336346
LOG_VART(relation->getElementId());
337347
LOG_VART(OsmUtils::getRelationDetailedString(relation, _pOriginalMap));
338348
}
339-
else if (logWarnCount == Log::getWarnMessageLimit())
340-
{
341-
LOG_WARN(className() << ": " << Log::LOG_WARN_LIMIT_REACHED_MESSAGE);
342-
}
343-
logWarnCount++;
344349
}
345350
}
346351
OsmMapWriterFactory::writeDebugMap(pMap, "after-adding-diff-tag-changes");
@@ -394,13 +399,16 @@ void DiffConflator::_calcAndStoreTagChanges()
394399
}
395400

396401
LOG_VART(pOldElement->getElementId());
402+
//LOG_VART(pOldElement->getTags().get("name"));
397403
LOG_VART(pNewElement->getElementId());
404+
//LOG_VART(pNewElement->getTags().get("name"));
398405

399-
// Apparently a NetworkMatch can be a node/way pair. See note in
406+
// Apparently, a NetworkMatch can be a node/way pair. See note in
400407
// NetworkMatch::_discoverWayPairs as to why its allowed. However, tag changes between
401408
// node/way match pairs other than poi/poly don't seem to make any sense. Clearly, if we add
402-
// other conflation type other than poi/poly which matches differing geometry types then this
403-
// will need to be updated.
409+
// a conflation type other than poi/poly which matches differing geometry types then this will
410+
// need to be updated.
411+
404412
if (match->getMatchName() != PoiPolygonMatch().getMatchName() &&
405413
pOldElement->getElementType() != pNewElement->getElementType())
406414
{

0 commit comments

Comments
 (0)