Skip to content

Commit f71956c

Browse files
authored
Add option for allowing POI/Poly cross conflation (#3186)
* Helps solve some of the Building Attribute Conflation problems identified in https://github.com/DigitalGlobe/VGI-team-repo/issues/1846 * Added option poi.polygon.allow.cross.conflation.merging, which allows for merging matches that occur with both POI/Polygon Conflation and some other type of conflation (e.g. Building Conflation). The option is enabled for Attribute Conflation only. The default behavior in hoot is for a review to occur in this situation instead. * The new config option could also possibly be made to work with conflicts between POI/Poly Conflation and Area Conflation as well, but holding off on that change until there's a need for it. * Fixed bug with PreserveTypesTagMerger where types were duplicated in the alt_types tag
1 parent 81e37c2 commit f71956c

33 files changed

+484
-156
lines changed

conf/core/AttributeConflation.conf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"corner.splitter.rounded.split": "true",
1212
"duplicate.name.preserve.original.name": "true",
1313
"highway.merge.tags.only": "true",
14+
"poi.polygon.allow.cross.conflation.merging": "true",
1415
"poi.polygon.auto.merge.many.poi.to.one.poly.matches": "true",
1516
"reader.conflate.use.data.source.ids.1": "false",
1617
"remove.elements.visitor.chain.element.criteria": "false",

conf/core/ConfigOptions.asciidoc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2935,6 +2935,15 @@ is enabled, POI/Polygon conflation will use additional to English language trans
29352935
address normalization. Disable this only if libpostal's language translation is not adequate for
29362936
your language translation needs.
29372937

2938+
=== poi.polygon.allow.cross.conflation.merging
2939+
2940+
* Data Type: bool
2941+
* Default Value: `false`
2942+
2943+
If false, when a match found by Building Conflation involves the same feature in a match found by
2944+
POI to Polygon Conflation, a review will be generated. If true, then that situation will result in
2945+
a merge between all features involved in the Building and POI to Polygon conflation matches.
2946+
29382947
=== poi.polygon.auto.merge.many.poi.to.one.poly.matches
29392948

29402949
* Data Type: bool

conf/services/conflateAdvOps.json

Lines changed: 60 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -750,12 +750,30 @@
750750
"onchange":"true"
751751
},
752752
{
753-
"id":"building_review_if_secondary_newer",
754-
"elem_type":"bool",
755-
"defaultvalue":"false",
756-
"description":"If true, any buildings in the secondary layer will be automatically reviewed against potentially matching features in the reference layer if they are marked with a more recent date than that of the reference feature.",
757-
"name":"Review If Secondary Layer Building Newer",
758-
"hoot_key":"building.review.if.secondary.newer"
753+
"id":"building_match_creator",
754+
"elem_type":"string",
755+
"description":"List of MatchCreators to use during conflation. This can modify what features will be conflated (e.g. buildings, roads, etc.).",
756+
"name":"Match Creator",
757+
"required":"true",
758+
"defaultvalue":"hoot::BuildingMatchCreator",
759+
"override":{
760+
"defaultvalue":"hoot::BuildingMatchCreator"
761+
},
762+
"hoot_key":"match.creators",
763+
"required":"true"
764+
},
765+
{
766+
"id":"building_merger_creator",
767+
"elem_type":"string",
768+
"description":"List of MergerCreators to use during conflation. This can modify what features will be conflated (e.g. buildings, roads, etc.).",
769+
"name":"Merger Creator",
770+
"required":"true",
771+
"defaultvalue":"hoot::BuildingMergerCreator",
772+
"override":{
773+
"defaultvalue":"hoot::BuildingMergerCreator"
774+
},
775+
"hoot_key":"merger.creators",
776+
"required":"true"
759777
},
760778
{
761779
"id":"building_date_format",
@@ -784,30 +802,28 @@
784802
"hoot_key":"building.keep.more.complex.geometry.when.auto.merging"
785803
},
786804
{
787-
"id":"building_match_creator",
788-
"elem_type":"string",
789-
"description":"List of MatchCreators to use during conflation. This can modify what features will be conflated (e.g. buildings, roads, etc.).",
790-
"name":"Match Creator",
791-
"required":"true",
792-
"defaultvalue":"hoot::BuildingMatchCreator",
793-
"override":{
794-
"defaultvalue":"hoot::BuildingMatchCreator"
795-
},
796-
"hoot_key":"match.creators",
797-
"required":"true"
805+
"id":"building_merge_many_to_many_matches",
806+
"elem_type":"bool",
807+
"defaultvalue":"false",
808+
"description":"If false, many to many building matches will result in a review. If true, they will all be merged together when matched.",
809+
"name":"Merge Many to Many Matches",
810+
"hoot_key":"building.merge.many.to.many.matches"
798811
},
799812
{
800-
"id":"building_merger_creator",
801-
"elem_type":"string",
802-
"description":"List of MergerCreators to use during conflation. This can modify what features will be conflated (e.g. buildings, roads, etc.).",
803-
"name":"Merger Creator",
804-
"required":"true",
805-
"defaultvalue":"hoot::BuildingMergerCreator",
806-
"override":{
807-
"defaultvalue":"hoot::BuildingMergerCreator"
808-
},
809-
"hoot_key":"merger.creators",
810-
"required":"true"
813+
"id":"building_outline_update_op_remove_building_relations",
814+
"elem_type":"bool",
815+
"defaultvalue":"false",
816+
"description":"If true, when building outlines are updated the updater will remove the source building relations used to create the outline multipolygon relation. If false, both source building relations and outline multipolygon relations will remain.",
817+
"name":"Remove Building Relations",
818+
"hoot_key":"building.outline.update.op.remove.building.relations"
819+
},
820+
{
821+
"id":"building_review_if_secondary_newer",
822+
"elem_type":"bool",
823+
"defaultvalue":"false",
824+
"description":"If true, any buildings in the secondary layer will be automatically reviewed against potentially matching features in the reference layer if they are marked with a more recent date than that of the reference feature.",
825+
"name":"Review If Secondary Layer Building Newer",
826+
"hoot_key":"building.review.if.secondary.newer"
811827
},
812828
{
813829
"id":"building_review_matches_other_than_one_to_one",
@@ -914,6 +930,14 @@
914930
"hoot_key":"address.additional.tag.keys",
915931
"onchange":"true"
916932
},
933+
{
934+
"id":"poipolygon_address_allow_lenient_house_number_matching",
935+
"elem_type":"bool",
936+
"defaultvalue":"true",
937+
"description":"If true, POI/Polygon conflation will allow house number subletter mismatches for the addresses with the same house number. e.g. when enabled, 23a Elm Street matches 23 Elm Street",
938+
"name":"Allow Lenient House Number Matching",
939+
"hoot_key":"poi.polygon.address.allow.lenient.house.number.matching"
940+
},
917941
{
918942
"id":"poipolygon_address_match_enabled",
919943
"elem_type":"bool",
@@ -922,6 +946,14 @@
922946
"name":"Address Match Enabled",
923947
"hoot_key":"poi.polygon.address.match.enabled"
924948
},
949+
{
950+
"id":"poipolygon_allow_cross_conflation_merging",
951+
"elem_type":"bool",
952+
"defaultvalue":"false",
953+
"description":"If false, when a match found by Building Conflation involves the same feature in a match found by POI to Polygon Conflation, a review will be generated. If true, then that situation will result in a merge between all features involved in the Building and POI to Polygon conflation matches.",
954+
"name":"Allow Cross Conflation Merging",
955+
"hoot_key":"poi.polygon.allow.cross.conflation.merging"
956+
},
925957
{
926958
"id":"poipolygon_auto_merge_many_poi_to_one_poly_matches",
927959
"elem_type":"bool",

hoot-core-test/src/test/cpp/hoot/core/conflate/poi-polygon/PoiPolygonMatchCreatorTest.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,12 @@ class PoiPolygonMatchCreatorTest : public HootTestFixture
9494
std::shared_ptr<const MatchThreshold> threshold(new MatchThreshold(0.5, 0.5, 0.5));
9595
uut.createMatches(map, matches, threshold);
9696
HOOT_STR_EQUALS(2, matches.size());
97-
HOOT_STR_EQUALS("PoiPolygonMatch Node(1) Way(-1) P: match: 1 miss: 0 review: 0, distance: 0, close match: 1, type score: 0, name score: 1, address score: -1",
98-
matches[0]->toString());
99-
HOOT_STR_EQUALS("PoiPolygonMatch Node(2) Way(-1) P: match: 0 miss: 0 review: 1, distance: 0, close match: 1, type score: 0, name score: 0, address score: 0",
100-
matches[1]->toString());
97+
HOOT_STR_EQUALS(
98+
"PoiPolygonMatch: POI: Node(1), Poly: Way(-1), P: match: 1 miss: 0 review: 0, distance: 0, close match: 1, type score: 0, name score: 1, address score: -1",
99+
matches[0]->toString());
100+
HOOT_STR_EQUALS(
101+
"PoiPolygonMatch: POI: Node(2), Poly: Way(-1), P: match: 0 miss: 0 review: 1, distance: 0, close match: 1, type score: 0, name score: 0, address score: 0",
102+
matches[1]->toString());
101103
}
102104
}
103105

hoot-core-test/src/test/cpp/hoot/core/conflate/poi-polygon/PoiPolygonMergerCreatorTest.cpp

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
#include <hoot/core/conflate/poi-polygon/PoiPolygonMerger.h>
3434
#include <hoot/core/conflate/poi-polygon/PoiPolygonMergerCreator.h>
3535
#include <hoot/core/conflate/polygon/BuildingMatchCreator.h>
36+
#include <hoot/core/conflate/polygon/BuildingMatch.h>
37+
#include <hoot/core/conflate/polygon/BuildingRfClassifier.h>
3638
#include <hoot/core/io/OsmJsonWriter.h>
3739
#include <hoot/core/util/ConfigOptions.h>
3840
#include <hoot/core/util/Log.h>
@@ -48,6 +50,7 @@ class PoiPolygonMergerCreatorTest : public HootTestFixture
4850
CPPUNIT_TEST_SUITE(PoiPolygonMergerCreatorTest);
4951
CPPUNIT_TEST(basicTest);
5052
CPPUNIT_TEST(reviewTest);
53+
CPPUNIT_TEST(crossConflateMergeTest);
5154
CPPUNIT_TEST_SUITE_END();
5255

5356
public:
@@ -70,11 +73,10 @@ class PoiPolygonMergerCreatorTest : public HootTestFixture
7073
conf().set(ConfigOptions().getMergerCreatorsKey(), ConfigOptions().getMergerCreatorsDefaultValue());
7174
}
7275

73-
/**
74-
* Creates a single match and should result in a PoiPolygonMerger
75-
*/
7676
void basicTest()
7777
{
78+
// Creates a single match and should result in a PoiPolygonMerger
79+
7880
OsmMapPtr map(new OsmMap());
7981

8082
Coordinate c1[] = { Coordinate(0.0, 0.0), Coordinate(20.0, 0.0),
@@ -106,11 +108,11 @@ class PoiPolygonMergerCreatorTest : public HootTestFixture
106108
HOOT_STR_EQUALS(1, (dynamic_cast<PoiPolygonMerger*>(mergers[0]) != 0));
107109
}
108110

109-
/**
110-
* Creates two matches with overlap and should create a MarkForReviewMerger
111-
*/
112111
void reviewTest()
113112
{
113+
// Create a building and poi/poly match with feature overlap and ensure they create reviews and
114+
// don't merge together when cross feature conflate merging is not allowed.
115+
114116
OsmMapPtr map(new OsmMap());
115117

116118
Coordinate c1[] = { Coordinate(0.0, 0.0), Coordinate(20.0, 0.0),
@@ -151,18 +153,55 @@ class PoiPolygonMergerCreatorTest : public HootTestFixture
151153
match2.setMatchEvidenceThreshold(3);
152154
match2.setReviewEvidenceThreshold(1);
153155
match2.calculateMatch(w2->getElementId(), n1->getElementId());
156+
matchesV.push_back(&match2);
154157
LOG_VAR(match2);
155158

156159
MatchSet matches;
157160
matches.insert(matchesV.begin(), matchesV.end());
158161
vector<Merger*> mergers;
159162
PoiPolygonMergerCreator uut;
160163
uut.setOsmMap(map.get());
164+
161165
HOOT_STR_EQUALS(1, uut.createMergers(matches, mergers));
162166
HOOT_STR_EQUALS(1, mergers.size());
163-
LOG_VAR(*mergers[0]);
167+
LOG_VART(*mergers[0]);
164168
HOOT_STR_EQUALS(1, (dynamic_cast<MarkForReviewMerger*>(mergers[0]) != 0));
165169
}
170+
171+
void crossConflateMergeTest()
172+
{
173+
// Create a building and poi/poly match with feature overlap and ensure they all merge together
174+
// when cross feature conflate merging is allowed.
175+
176+
vector<const Match*> matchesV;
177+
178+
BuildingMatch match1(std::shared_ptr<const MatchThreshold>(new MatchThreshold(0.5, 0.5, 0.5)));
179+
match1._p.setMatch();
180+
match1._eid1 = ElementId(ElementType::Way, 1);
181+
match1._eid2 = ElementId(ElementType::Node, 1);
182+
matchesV.push_back(&match1);
183+
184+
PoiPolygonMatch match2(std::shared_ptr<const MatchThreshold>(new MatchThreshold(0.6, 0.6, 0.6)));
185+
match2._class.setMatch();
186+
match2._eid1 = ElementId(ElementType::Way, 2);
187+
match2._eid2 = ElementId(ElementType::Node, 1);
188+
matchesV.push_back(&match2);
189+
190+
MatchSet matches;
191+
matches.insert(matchesV.begin(), matchesV.end());
192+
vector<Merger*> mergers;
193+
PoiPolygonMergerCreator uut;
194+
// Neither of the match types used here actually require a map to calculate isConflicting, but
195+
// since the merger creator requires a map we'll pass in an empty one.
196+
OsmMapPtr emptyMap(new OsmMap());
197+
uut.setOsmMap(emptyMap.get());
198+
uut.setAllowCrossConflationMerging(true);
199+
200+
HOOT_STR_EQUALS(1, uut.createMergers(matches, mergers));
201+
HOOT_STR_EQUALS(1, mergers.size());
202+
LOG_VART(*mergers[0]);
203+
HOOT_STR_EQUALS(1, (dynamic_cast<PoiPolygonMerger*>(mergers[0]) != 0));
204+
}
166205
};
167206

168207
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(PoiPolygonMergerCreatorTest, "quick");

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ MatchClassification RfExtractorClassifier::classify(const ConstOsmMapPtr& map,
6969
result.setMatchP(scores["match"]);
7070
result.setReviewP(scores["review"]);
7171

72+
LOG_VART(result);
7273
return result;
7374
}
7475

@@ -79,7 +80,6 @@ const vector<std::shared_ptr<const FeatureExtractor>>& RfExtractorClassifier::_g
7980
{
8081
_createExtractors();
8182
}
82-
8383
return _extractors;
8484
}
8585

@@ -94,7 +94,7 @@ map<QString, double> RfExtractorClassifier::getFeatures(const ConstOsmMapPtr& m,
9494
_getExtractors();
9595
for (size_t i = 0; i < _extractors.size(); i++)
9696
{
97-
double v = _extractors[i]->extract(*m, e1, e2);
97+
const double v = _extractors[i]->extract(*m, e1, e2);
9898
// if it isn't null then include it.
9999
if (!FeatureExtractor::isNull(v))
100100
{

hoot-core/src/main/cpp/hoot/core/conflate/merging/MarkForReviewMerger.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ void MarkForReviewMerger::apply(const OsmMapPtr& map,
7373
}
7474
else
7575
{
76-
for (set<pair<ElementId, ElementId>>::const_iterator it = _pairs.begin();
77-
it != _pairs.end(); ++it)
76+
for (set<pair<ElementId, ElementId>>::const_iterator it = _pairs.begin(); it != _pairs.end();
77+
++it)
7878
{
7979
ElementId eid1 = it->first;
8080
ElementId eid2 = it->second;
@@ -152,7 +152,6 @@ void MarkForReviewMerger::replace(ElementId oldEid, ElementId newEid)
152152

153153
QString MarkForReviewMerger::toString() const
154154
{
155-
//return QString("MarkForReviewMerger");
156155
return QString("MarkForReviewMerger, pairs: ") + hoot::toString(_pairs);
157156
}
158157

hoot-core/src/main/cpp/hoot/core/conflate/merging/MergerCreator.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ namespace hoot
4343
class Match;
4444
class Merger;
4545

46+
/**
47+
* Abstract base class for creating conflation feature mergers
48+
*/
4649
class MergerCreator
4750
{
4851
public:

hoot-core/src/main/cpp/hoot/core/conflate/merging/MergerFactory.cpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,9 @@
3030
#include <hoot/core/util/Factory.h>
3131
#include <hoot/core/elements/OsmMapConsumer.h>
3232
#include <hoot/core/conflate/matching/Match.h>
33-
#include <hoot/core/conflate/polygon/BuildingMergerCreator.h>
3433
#include <hoot/core/util/ConfigOptions.h>
3534
#include <hoot/core/util/HootException.h>
3635
#include <hoot/core/util/Log.h>
37-
#include <hoot/core/conflate/matching/MatchGraph.h>
3836

3937
using namespace std;
4038

@@ -72,7 +70,6 @@ void MergerFactory::createMergers(const OsmMapPtr& map, const MatchSet& matches,
7270
PROGRESS_DEBUG("Creating merger " << i + 1 << " / " << _creators.size() << "...");
7371

7472
OsmMapConsumer* omc = dynamic_cast<OsmMapConsumer*>(_creators[i]);
75-
7673
if (omc)
7774
{
7875
omc->setOsmMap(map.get());
@@ -81,7 +78,6 @@ void MergerFactory::createMergers(const OsmMapPtr& map, const MatchSet& matches,
8178
{
8279
return;
8380
}
84-
8581
// we don't want the creators to hold onto a map pointer that will go out of scope
8682
if (omc)
8783
{
@@ -141,8 +137,8 @@ MergerFactory& MergerFactory::getInstance()
141137
return *_theInstance;
142138
}
143139

144-
bool MergerFactory::isConflicting(const ConstOsmMapPtr& map, const Match* m1, const Match* m2)
145-
const
140+
bool MergerFactory::isConflicting(const ConstOsmMapPtr& map, const Match* m1,
141+
const Match* m2) const
146142
{
147143
LOG_VART(_creators.size());
148144
// if any creator considers a match conflicting then it is a conflict

hoot-core/src/main/cpp/hoot/core/conflate/network/NetworkDetails.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -768,7 +768,7 @@ double NetworkDetails::getPartialEdgeMatchScore(ConstNetworkEdgePtr e1, ConstNet
768768
{
769769
if (logWarnCount < Log::getWarnMessageLimit())
770770
{
771-
LOG_WARN("Unable to retieve partial match score. One or more ways is null.");
771+
LOG_WARN("Unable to retrieve partial match score. One or more ways is null.");
772772
if (!w1.get())
773773
{
774774
LOG_DEBUG("Way 1 is null.");

0 commit comments

Comments
 (0)