v0.2.49..v0.2.50 changeset PoiPolygonReviewReducer.cpp
Garret Voltz edited this page Nov 6, 2019
·
1 revision
diff --git a/hoot-core/src/main/cpp/hoot/core/conflate/poi-polygon/PoiPolygonReviewReducer.cpp b/hoot-core/src/main/cpp/hoot/core/conflate/poi-polygon/PoiPolygonReviewReducer.cpp
index e0a5e19..e56142b 100644
--- a/hoot-core/src/main/cpp/hoot/core/conflate/poi-polygon/PoiPolygonReviewReducer.cpp
+++ b/hoot-core/src/main/cpp/hoot/core/conflate/poi-polygon/PoiPolygonReviewReducer.cpp
@@ -26,43 +26,34 @@
*/
#include "PoiPolygonReviewReducer.h"
-// geos
-#include <geos/geom/LineString.h>
-#include <geos/util/TopologyException.h>
-#include <geos/geom/Geometry.h>
-
// hoot
#include <hoot/core/conflate/matching/MatchClassification.h>
-#include <hoot/core/algorithms/extractors/AngleHistogramExtractor.h>
-#include <hoot/core/algorithms/extractors/OverlapExtractor.h>
-#include <hoot/core/algorithms/extractors/poi-polygon/PoiPolygonAddressScoreExtractor.h>
-#include <hoot/core/algorithms/extractors/poi-polygon/PoiPolygonNameScoreExtractor.h>
-#include <hoot/core/algorithms/extractors/poi-polygon/PoiPolygonTypeScoreExtractor.h>
-#include <hoot/core/criterion/BuildingWayNodeCriterion.h>
+#include <hoot/core/criterion/BuildingCriterion.h>
+#include <hoot/core/criterion/MultiUseCriterion.h>
#include <hoot/core/schema/OsmSchema.h>
#include <hoot/core/util/ConfigOptions.h>
-#include <hoot/core/elements/ElementConverter.h>
#include <hoot/core/util/Log.h>
-#include <hoot/core/criterion/MultiUseCriterion.h>
-#include <hoot/core/criterion/BuildingCriterion.h>
+#include <hoot/core/algorithms/extractors/poi-polygon/PoiPolygonTypeScoreExtractor.h>
+#include <hoot/core/algorithms/extractors/poi-polygon/PoiPolygonNameScoreExtractor.h>
+#include <hoot/core/algorithms/extractors/AngleHistogramExtractor.h>
+#include <hoot/core/algorithms/extractors/OverlapExtractor.h>
+#include <hoot/core/criterion/BuildingWayNodeCriterion.h>
+// Std
#include <float.h>
-using namespace geos::geom;
-using namespace std;
+// Qt
+#include <QElapsedTimer>
namespace hoot
{
-PoiPolygonReviewReducer::PoiPolygonReviewReducer(const ConstOsmMapPtr& map,
- const set<ElementId>& polyNeighborIds,
- const set<ElementId>& poiNeighborIds,
- double distance, double nameScoreThreshold,
- double nameScore, bool nameMatch,
- bool exactNameMatch, double typeScoreThreshold,
- double typeScore, bool typeMatch,
- double matchDistanceThreshold, bool addressMatch,
- bool addressParsingEnabled) :
+PoiPolygonReviewReducer::PoiPolygonReviewReducer(
+ const ConstOsmMapPtr& map,
+ const std::set<ElementId>& polyNeighborIds, const std::set<ElementId>& poiNeighborIds,
+ double distance, double nameScoreThreshold, double nameScore, bool nameMatch, bool exactNameMatch,
+ double typeScoreThreshold, double typeScore, bool typeMatch, double matchDistanceThreshold,
+ bool addressMatch, bool addressParsingEnabled, PoiPolygonCachePtr infoCache) :
_map(map),
_polyNeighborIds(polyNeighborIds),
_poiNeighborIds(poiNeighborIds),
@@ -76,9 +67,9 @@ _typeScore(typeScore),
_typeMatch(typeMatch),
_matchDistanceThreshold(matchDistanceThreshold),
_addressMatch(addressMatch),
-_badGeomCount(0),
_keepClosestMatchesOnly(ConfigOptions().getPoiPolygonKeepClosestMatchesOnly()),
-_addressParsingEnabled(addressParsingEnabled)
+_addressParsingEnabled(addressParsingEnabled),
+_infoCache(infoCache)
{
LOG_VART(_polyNeighborIds.size());
LOG_VART(_poiNeighborIds.size());
@@ -92,6 +83,8 @@ _addressParsingEnabled(addressParsingEnabled)
LOG_VART(_matchDistanceThreshold);
LOG_VART(_addressMatch);
LOG_VART(_addressParsingEnabled);
+
+ LOG_VART(_infoCache.get());
}
void PoiPolygonReviewReducer::setConfiguration(const Settings& conf)
@@ -99,32 +92,52 @@ void PoiPolygonReviewReducer::setConfiguration(const Settings& conf)
_addressParser.setConfiguration(conf);
}
+bool PoiPolygonReviewReducer::_hasAddress(ConstElementPtr element)
+{
+ return _addressParser.numAddressesRecursive(element, *_map) > 0;
+}
+
bool PoiPolygonReviewReducer::_nonDistanceSimilaritiesPresent() const
{
return _typeScore > 0.03 || _nameScore > 0.35 || _addressMatch;
}
-bool PoiPolygonReviewReducer::_polyContainsPoiAsMember(ConstElementPtr poly,
+bool PoiPolygonReviewReducer::_polyContainsPoiAsMember(ConstWayPtr poly,
ConstElementPtr poi) const
{
- ConstWayPtr polyWay = std::dynamic_pointer_cast<const Way>(poly);
- if (polyWay && polyWay->containsNodeId(poi->getId()))
- {
- return true;
- }
- ConstRelationPtr polyRelation = std::dynamic_pointer_cast<const Relation>(poly);
- if (polyRelation && polyRelation->contains(ElementId(ElementType::Node, poi->getId())))
- {
- return true;
- }
- return false;
+ return poly && poly->containsNodeId(poi->getId());
+}
+
+bool PoiPolygonReviewReducer::_polyContainsPoiAsMember(ConstRelationPtr poly,
+ ConstElementPtr poi) const
+{
+ return poly && poly->contains(poi->getElementId());
+}
+
+bool PoiPolygonReviewReducer::_inCategory(ConstElementPtr element,
+ const OsmSchemaCategory& category)
+{
+ return OsmSchema::getInstance().getCategories(element->getTags()).intersects(category);
}
-bool PoiPolygonReviewReducer::triggersRule(ConstElementPtr poi, ConstElementPtr poly)
+bool PoiPolygonReviewReducer::triggersRule(ConstNodePtr poi, ConstElementPtr poly)
{
LOG_TRACE("Checking review reduction rules...");
+ //QElapsedTimer timer;
+ //timer.start();
+
+ ConstWayPtr polyAsWay;
+ ConstRelationPtr polyAsRelation;
+ if (poly->getElementType() == ElementType::Way)
+ {
+ polyAsWay = std::dynamic_pointer_cast<const Way>(poly);
+ }
+ else if (poly->getElementType() == ElementType::Relation)
+ {
+ polyAsRelation = std::dynamic_pointer_cast<const Relation>(poly);
+ }
- // Some of these rules may be obsolete...they need to be checked.
+ // Some of these rules could be obsolete.
const Tags& poiTags = poi->getTags();
const Tags& polyTags = poly->getTags();
@@ -137,18 +150,18 @@ bool PoiPolygonReviewReducer::triggersRule(ConstElementPtr poi, ConstElementPtr
const bool polyHasType = PoiPolygonTypeScoreExtractor::hasType(poly);
LOG_VART(polyHasType);
+ LOG_TRACE("Checking rule #1...");
if (_addressParsingEnabled)
{
- const int numPolyAddresses = _addressParser.hasAddressRecursive(poly, *_map);
- const bool polyHasAddress = numPolyAddresses > 0;
-
//if both have addresses and they explicitly contradict each other, throw out the review; don't
//do it if the poly has more than one address, like in many multi-use buildings.
- if (!_addressMatch && _addressParser.hasAddressRecursive(poi, *_map) && polyHasAddress)
+ if (!_addressMatch && _hasAddress(poi) && _hasAddress(poly))
{
//check to make sure the only address the poly has isn't the poi itself as a way node /
//relation member
- if (_polyContainsPoiAsMember(poly, poi) && numPolyAddresses < 2)
+ if (((polyAsWay && _polyContainsPoiAsMember(polyAsWay, poi)) ||
+ (polyAsRelation && _polyContainsPoiAsMember(polyAsRelation, poi))) &&
+ _addressParser.numAddressesRecursive(poly, *_map) < 2)
{
}
else
@@ -159,7 +172,9 @@ bool PoiPolygonReviewReducer::triggersRule(ConstElementPtr poi, ConstElementPtr
}
}
- if (MultiUseCriterion().isSatisfied(poly) && poiHasType && _typeScore < 0.4)
+ LOG_TRACE("Checking rule #2...");
+ if (_infoCache->hasCriterion(poly, QString::fromStdString(MultiUseCriterion::className())) &&
+ poiHasType && _typeScore < 0.4)
{
LOG_TRACE("Returning miss per review reduction rule #2...");
return true;
@@ -169,6 +184,7 @@ bool PoiPolygonReviewReducer::triggersRule(ConstElementPtr poi, ConstElementPtr
const QString polyPlaceVal = polyTags.get("place").toLower();
//be a little stricter on place related reviews
+ LOG_TRACE("Checking rule #3...");
if ((poiPlaceVal == "neighbourhood" || poiPlaceVal == "suburb") && !polyTags.contains("place"))
{
LOG_TRACE("Returning miss per review reduction rule #3...");
@@ -181,6 +197,7 @@ bool PoiPolygonReviewReducer::triggersRule(ConstElementPtr poi, ConstElementPtr
const bool polyHasLanduse = !polyLanduseVal.trimmed().isEmpty();
// I think this one will eventually go away.
+ LOG_TRACE("Checking rule #4...");
if (poiTags.get("man_made").toLower() == "mine" && polyLanduseVal == "quarry" &&
polyTags.get("man_made").toLower() != "mine")
{
@@ -189,13 +206,14 @@ bool PoiPolygonReviewReducer::triggersRule(ConstElementPtr poi, ConstElementPtr
}
//points sitting on islands need to have an island type, or the match doesn't make any sense
+ LOG_TRACE("Checking rule #5...");
if ((poiPlaceVal == "island" || polyPlaceVal == "island") && !_typeMatch)
{
LOG_TRACE("Returning miss per review reduction rule #5...");
return true;
}
- const bool polyIsPark = PoiPolygonTypeScoreExtractor::isPark(poly);
+ const bool polyIsPark = _infoCache->isType(poly, "park");
LOG_VART(polyIsPark);
const QString poiLeisureVal = poiTags.get("leisure").toLower();
@@ -207,6 +225,7 @@ bool PoiPolygonReviewReducer::triggersRule(ConstElementPtr poi, ConstElementPtr
const bool polyHasName = !polyName.isEmpty();
//similar to above, but for gardens
+ LOG_TRACE("Checking rule #6...");
if ((poiLeisureVal == "garden" || polyLeisureVal == "garden") &&
(!_nonDistanceSimilaritiesPresent() ||
(polyIsPark && !polyName.toLower().contains("garden"))))
@@ -216,6 +235,7 @@ bool PoiPolygonReviewReducer::triggersRule(ConstElementPtr poi, ConstElementPtr
}
//lots of things have fountains, so let's raise the requirements a bit
+ LOG_TRACE("Checking rule #7...");
if (poiTags.get("amenity") == "fountain" && _nameScore < 0.5)
{
LOG_TRACE("Returning miss per review reduction rule #7...");
@@ -225,31 +245,27 @@ bool PoiPolygonReviewReducer::triggersRule(ConstElementPtr poi, ConstElementPtr
//these seem to be clustered together tightly a lot in cities, so up the requirement a bit
// TODO: using custom match/review distances or custom score requirements may be a better way to
// handle these types
+ LOG_TRACE("Checking rule #8...");
if (poiTags.get("tourism") == "hotel" && polyTags.get("tourism") == "hotel" &&
poiHasName && polyHasName && _nameScore < 0.75 && !_addressMatch)
{
LOG_TRACE("Returning miss per review reduction rule #8...");
return true;
}
- //this is too destructive
-// if (PoiPolygonTypeScoreExtractor::isSchool(poi) && PoiPolygonTypeScoreExtractor::isSchool(poly) &&
-// poiHasName && polyHasName && _nameScore < 0.5 && !_addressMatch)
-// {
-// LOG_TRACE("Returning miss per review reduction rule #5d...");
-// return true;
-// }
- if (PoiPolygonTypeScoreExtractor::isRestaurant(poi) &&
- PoiPolygonTypeScoreExtractor::isRestaurant(poly) && poiHasName && polyHasName &&
- _nameScore < 0.5 && !_addressMatch)
+
+ LOG_TRACE("Checking rule #9...");
+ if (_infoCache->isType(poi, "restaurant") && _infoCache->isType(poly, "restaurant") &&
+ poiHasName && polyHasName && _nameScore < 0.5 && !_addressMatch)
{
LOG_TRACE("Returning miss per review reduction rule #9...");
return true;
}
//similar to above, but for sport fields
+ LOG_TRACE("Checking rule #10...");
const bool poiNameEndsWithField = poiName.endsWith("field");
LOG_VART(poiNameEndsWithField);
- const bool polyIsSport = PoiPolygonTypeScoreExtractor::isSport(poly);
+ const bool polyIsSport = _infoCache->isType(poly, "sport");
LOG_VART(polyIsSport);
//we'll let this review pass if the poi ends with "field" in the name and is sitting on top of a
//sport poly
@@ -265,35 +281,34 @@ bool PoiPolygonReviewReducer::triggersRule(ConstElementPtr poi, ConstElementPtr
//Landuse polys often wrap a bunch of other features and don't necessarily match to POI's, so
//be more strict with their reviews.
+ LOG_TRACE("Checking rule #11...");
if (polyHasLanduse && !_nonDistanceSimilaritiesPresent())
{
LOG_TRACE("Returning miss per review reduction rule #11...");
return true;
}
- LOG_VART(PoiPolygonTypeScoreExtractor::isSpecificSchool(poi));
- LOG_VART(PoiPolygonTypeScoreExtractor::isSpecificSchool(poly));
- LOG_VART(PoiPolygonTypeScoreExtractor::specificSchoolMatch(poi, poly));
- if (PoiPolygonTypeScoreExtractor::isSpecificSchool(poi) &&
- PoiPolygonTypeScoreExtractor::isSpecificSchool(poly) &&
+ LOG_TRACE("Checking rule #12...");
+ if (_infoCache->isType(poi, "specificSchool") && _infoCache->isType(poly, "specificSchool") &&
!PoiPolygonTypeScoreExtractor::specificSchoolMatch(poi, poly))
{
LOG_TRACE("Returning miss per review reduction rule #12...");
return true;
}
- const bool poiIsNatural = PoiPolygonTypeScoreExtractor::isNatural(poi);
- const bool polyIsNatural = PoiPolygonTypeScoreExtractor::isNatural(poly);
+ const bool poiIsNatural = _infoCache->isType(poi, "natural");
+ const bool polyIsNatural = _infoCache->isType(poly, "natural");
//Be more strict reviewing natural features and parks against building features. This could be
//extended
- if ((polyIsNatural || polyIsPark) &&
- OsmSchema::getInstance().getCategories(poiTags).intersects(OsmSchemaCategory::building()))
+ LOG_TRACE("Checking rule #13...");
+ if ((polyIsNatural || polyIsPark) && _inCategory(poi, OsmSchemaCategory::building()))
{
LOG_TRACE("Returning miss per review reduction rule #13...");
return true;
}
+ LOG_TRACE("Checking rule #14...");
if (poiHasType && polyIsNatural && !_typeMatch)
{
LOG_TRACE("Returning miss per review reduction rule #14...");
@@ -301,6 +316,7 @@ bool PoiPolygonReviewReducer::triggersRule(ConstElementPtr poi, ConstElementPtr
}
//inverse of above
+ LOG_TRACE("Checking rule #15...");
if (polyHasType && poiIsNatural && !_typeMatch)
{
LOG_TRACE("Returning miss per review reduction rule #15...");
@@ -308,52 +324,57 @@ bool PoiPolygonReviewReducer::triggersRule(ConstElementPtr poi, ConstElementPtr
}
//prevent athletic POIs within a park poly from being reviewed against that park poly
+ LOG_TRACE("Checking rule #16...");
if (_distance == 0 && polyIsPark && poiLeisureVal == "pitch")
{
LOG_TRACE("Returning miss per review reduction rule #16...");
return true;
}
- const bool poiIsPark = PoiPolygonTypeScoreExtractor::isPark(poi);
+ const bool poiIsPark = _infoCache->isType(poi, "park");
LOG_VART(poiIsPark);
//Don't match a park poi to a sport poly. Simpler version of some rules above.
//may make some previous rules obsolete
+ LOG_TRACE("Checking rule #17...");
if (poiIsPark && polyIsSport)
{
LOG_TRACE("Returning miss per review reduction rule #17...");
return true;
}
- BuildingCriterion buildingCrit;
- const bool polyIsBuilding = buildingCrit.isSatisfied(poly);
+ const bool polyIsBuilding =
+ _infoCache->hasCriterion(poly, QString::fromStdString(BuildingCriterion::className()));
LOG_VART(polyIsBuilding);
- //Similar to previous, except more focused for restrooms.
- if (poiHasType && polyHasType && _typeScore != 1.0 &&
- PoiPolygonTypeScoreExtractor::isRestroom(poi) &&
- !OsmSchema::getInstance().getCategories(polyTags).intersects(OsmSchemaCategory::building()))
+ // similar to previous, except more focused for restrooms
+ LOG_TRACE("Checking rule #18...");
+ if (poiHasType && polyHasType && _typeScore != 1.0 && _infoCache->isType(poi, "restroom") &&
+ !_inCategory(poly, OsmSchemaCategory::building()))
{
LOG_TRACE("Returning miss per review reduction rule #18...");
return true;
}
- //Be more strict reviewing parking lots against other features.
- if (poiHasType && polyHasType && PoiPolygonTypeScoreExtractor::isParking(poly) &&
- !_typeMatch && polyTags.get("parking") != "multi-storey")
+ //Be more strict reviewing parking lots against other features
+ LOG_TRACE("Checking rule #19...");
+ if (poiHasType && polyHasType && _infoCache->isType(poly, "parking") && !_typeMatch &&
+ polyTags.get("parking") != "multi-storey")
{
LOG_TRACE("Returning miss per review reduction rule #19...");
return true;
}
//Don't review schools against their sports fields.
- if (PoiPolygonTypeScoreExtractor::isSchool(poi) && polyIsSport)
+ LOG_TRACE("Checking rule #20...");
+ if (_infoCache->isType(poi, "school") && polyIsSport)
{
LOG_TRACE("Returning miss per review reduction rule #20...");
return true;
}
//Need to be stricter on tunnels since we don't want above ground things to review against them.
+ LOG_TRACE("Checking rule #21...");
if (polyTags.get("tunnel") == "yes" && poiHasType &&
(!(_typeMatch || _nameMatch) || (_nameMatch && _typeScore < 0.2)))
{
@@ -361,32 +382,11 @@ bool PoiPolygonReviewReducer::triggersRule(ConstElementPtr poi, ConstElementPtr
return true;
}
- ElementConverter elementConverter(_map);
- std::shared_ptr<Geometry> polyGeom = elementConverter.convertToGeometry(poly);
- if (QString::fromStdString(polyGeom->toString()).toUpper().contains("EMPTY"))
- {
- throw geos::util::TopologyException();
- }
- std::shared_ptr<Geometry> poiGeom = elementConverter.convertToGeometry(poi);
-
- double polyArea = -1.0;
- try
- {
- polyArea = polyGeom->getArea();
- }
- catch (const geos::util::TopologyException& e)
- {
- if (_badGeomCount <= Log::getWarnMessageLimit())
- {
- LOG_TRACE(
- "Feature passed to PoiPolygonMatchCreator caused topology exception on conversion to a " <<
- "geometry: " << polyGeom->toString() << "\n" << e.what());
- _badGeomCount++;
- }
- }
-
+ const double polyArea = _infoCache->getArea(poly);
+ LOG_VART(polyArea);
//Don't review park poi's against large non-park polys.
- if (poiHasType && polyHasType && !_nameMatch && !polyIsPark &&
+ LOG_TRACE("Checking rule #22...");
+ if (polyArea != -1.0 && poiHasType && polyHasType && !_nameMatch && !polyIsPark &&
(((polyHasLanduse && !poiHasLanduse) ||
(polyIsNatural && !poiIsNatural) ||
polyLeisureVal == "common") ||
@@ -396,34 +396,34 @@ bool PoiPolygonReviewReducer::triggersRule(ConstElementPtr poi, ConstElementPtr
return true;
}
- const bool polyIsPlayground = PoiPolygonTypeScoreExtractor::isPlayground(poly);
+ const bool polyIsPlayground = _infoCache->isType(poly, "playground");
LOG_VART(polyIsPlayground);
const bool polyHasMoreThanOneType = PoiPolygonTypeScoreExtractor::hasMoreThanOneType(poly);
LOG_VART(polyHasMoreThanOneType);
- const bool poiIsParkish = PoiPolygonTypeScoreExtractor::isParkish(poi);
+ const bool poiIsParkish = _infoCache->isType(poi, "parkish");
LOG_VART(poiIsParkish);
//This is a simple rule to prevent matching poi's not at all like a park with park polys.
//this may render some of the previous rules obsolete.
+ LOG_TRACE("Checking rule #23...");
if (!poiIsPark && !poiIsParkish && poiHasType && polyIsPark && !polyHasMoreThanOneType)
{
LOG_TRACE("Returning miss per review reduction rule #23...");
return true;
}
- PoiPolygonTypeScoreExtractor typeScorer;
-
//If the poi is a way node, it belongs to a building way, and there is a type match between the
//poi and the building way, then don't review the two. This allows for tagged poi way nodes to
//conflate cleanly with building ways they belong to, rather than being reviewed against other
//building ways.
+ LOG_TRACE("Checking rule #24...");
const long matchingWayId = BuildingWayNodeCriterion(_map).getMatchingWayId(poi);
if (matchingWayId != 0)
{
ConstWayPtr matchingWay = _map->getWay(matchingWayId);
assert(matchingWay.get());
if (poly->getElementId() != matchingWay->getElementId() &&
- typeScorer.extract(*_map, poi, matchingWay) >= _typeScoreThreshold)
+ PoiPolygonTypeScoreExtractor().extract(*_map, poi, matchingWay) >= _typeScoreThreshold)
{
LOG_TRACE("Returning miss per review reduction rule #24...");
return true;
@@ -445,290 +445,198 @@ bool PoiPolygonReviewReducer::triggersRule(ConstElementPtr poi, ConstElementPtr
bool poiContainedInAnotherParkPoly = false;
bool sportPoiOnOtherSportPolyWithTypeMatch = false;
bool poiOnBuilding = false;
- const bool poiIsSport = PoiPolygonTypeScoreExtractor::isSport(poi);
+ const bool poiIsSport = _infoCache->isType(poi, "sport");
LOG_VART(poiIsSport);
const bool poiContainedInParkPoly =
poiContainedInAnotherParkPoly || (polyIsPark && _distance == 0);
LOG_VART(poiContainedInParkPoly);
- const bool poiIsBuilding = buildingCrit.isSatisfied(poi);
+ const bool poiIsBuilding =
+ _infoCache->hasCriterion(poi, QString::fromStdString(BuildingCriterion::className()));
LOG_VART(poiIsBuilding);
- PoiPolygonNameScoreExtractor nameScorer;
-
//This will check the current poi against all neighboring pois. If any neighboring poi is
//closer to the current poly than the current poi, then the current poi will not be matched or
//reviewed against the current poly.
- if (_keepClosestMatchesOnly && _poiNeighborIsCloserToPolyThanPoi(poi, poly))
+ LOG_TRACE("Checking rule #25...");
+ if (_keepClosestMatchesOnly &&
+ _infoCache->polyHasPoiNeighborCloserThanPoi(polyAsWay, poi, _poiNeighborIds, _distance))
{
+ LOG_TRACE("Returning miss per review reduction rule #25...");
return true;
}
- LOG_VART(_polyNeighborIds);
- //The loop becomes more expensive as the search radius is increased.
- for (set<ElementId>::const_iterator polyNeighborItr = _polyNeighborIds.begin();
+ LOG_VART(_polyNeighborIds.size());
+ //LOG_VART(_polyNeighborIds);
+ // This loop becomes more expensive as the search radius is increased.
+ for (std::set<ElementId>::const_iterator polyNeighborItr = _polyNeighborIds.begin();
polyNeighborItr != _polyNeighborIds.end(); ++polyNeighborItr)
{
ConstElementPtr polyNeighbor = _map->getElement(*polyNeighborItr);
+ ConstWayPtr polyNeighborAsWay;
+ if (polyNeighbor->getElementType() == ElementType::Way)
+ {
+ polyNeighborAsWay = std::dynamic_pointer_cast<const Way>(polyNeighbor);
+ }
if (polyNeighbor->getElementId() != poly->getElementId())
{
- std::shared_ptr<Geometry> polyNeighborGeom;
- try
+ //This will check the current poly against all neighboring polys. If any neighboring
+ //poly is closer to the current poi than the current poly, then the current poi will
+ //not be matched or reviewed against the current poly.
+ if (_keepClosestMatchesOnly && poly->getElementType() == ElementType::Way &&
+ polyNeighbor->getElementType() == ElementType::Way)
{
- polyNeighborGeom = ElementConverter(_map).convertToGeometry(polyNeighbor);
-
- if (polyNeighborGeom.get() &&
- QString::fromStdString(polyNeighborGeom->toString()).toUpper().contains("EMPTY"))
- {
- if (_badGeomCount <= Log::getWarnMessageLimit())
- {
- LOG_TRACE(
- "Invalid area neighbor polygon passed to PoiPolygonMatchCreator: " <<
- polyNeighborGeom->toString());
- _badGeomCount++;
- }
- }
- else if (polyNeighborGeom.get())
- {
-
- //This will check the current poly against all neighboring polys. If any neighboring
- //poly is closer to the current poi than the current poly, then the current poi will
- //not be matched or reviewed against the current poly.
- if (_keepClosestMatchesOnly && poly->getElementType() == ElementType::Way &&
- polyNeighbor->getElementType() == ElementType::Way)
- {
- LOG_VART(poly);
- LOG_VART(polyNeighbor);
- ConstWayPtr polyNeighborWay = std::dynamic_pointer_cast<const Way>(polyNeighbor);
- std::shared_ptr<const LineString> polyNeighborLineStr =
- std::dynamic_pointer_cast<const LineString>(
- ElementConverter(_map).convertToLineString(polyNeighborWay));
- const long poiToNeighborPolyDist = polyNeighborLineStr->distance(poiGeom.get());
- LOG_VART(poiToNeighborPolyDist);
- if (_distance > poiToNeighborPolyDist)
- {
- LOG_TRACE("Returning miss per review reduction rule #25b...");
- return true;
- }
- }
-
- if (PoiPolygonTypeScoreExtractor::isPark(polyNeighbor))
- {
- // Should this be OsmSchema::elementHasName instead?
- otherParkPolyHasName = !polyNeighbor->getTags().get("name").trimmed().isEmpty();
- otherParkPolyNameScore = nameScorer.extract(*_map, poi, polyNeighbor);
- otherParkPolyNameMatch = otherParkPolyNameScore >= _nameScoreThreshold;
-
- if (polyNeighborGeom->contains(poiGeom.get()))
- {
- poiContainedInAnotherParkPoly = true;
-
- LOG_TRACE(
- "poi examined and found to be contained within a park poly outside of this match " <<
- "comparison: " << poi->toString());
- LOG_TRACE("park poly it is very close to: " << polyNeighbor->toString());
- }
-
- if (polyNeighborGeom->intersects(polyGeom.get()))
- {
- parkPolyAngleHistVal = AngleHistogramExtractor().extract(*_map, polyNeighbor, poly);
- LOG_VART(parkPolyAngleHistVal);
- parkPolyOverlapVal = OverlapExtractor().extract(*_map, polyNeighbor, poly);
- LOG_VART(parkPolyOverlapVal);
-
- //When just using intersection as the criteria, only found one instance when something
- //was considered as "very close" to a park poly when I didn't want it to be...so these
- //values set very low to weed that instance out...overlap at least.
- if (parkPolyAngleHistVal >= 0.05 && parkPolyOverlapVal >= 0.02)
- {
- polyVeryCloseToAnotherParkPoly = true;
-
- if (poly->getElementType() == ElementType::Way &&
- polyNeighbor->getElementType() == ElementType::Way)
- {
- //Calc the distance from the poi to the poly line instead of the poly itself.
- //Calcing distance to the poly itself will always return 0 when the poi is in the
- //poly.
- ConstWayPtr polyWay = std::dynamic_pointer_cast<const Way>(poly);
- std::shared_ptr<const LineString> polyLineStr =
- std::dynamic_pointer_cast<const LineString>(
- ElementConverter(_map).convertToLineString(polyWay));
- poiToPolyNodeDist = polyLineStr->distance(poiGeom.get());
- ConstWayPtr polyNeighborWay = std::dynamic_pointer_cast<const Way>(polyNeighbor);
- std::shared_ptr<const LineString> polyNeighborLineStr =
- std::dynamic_pointer_cast<const LineString>(
- ElementConverter(_map).convertToLineString(polyNeighborWay));
- poiToOtherParkPolyNodeDist = polyNeighborLineStr->distance(poiGeom.get());
- }
- LOG_TRACE(
- "poly examined and found very close to a another park poly: " <<
- poly->toString());
- LOG_TRACE("park poly it is very close to: " << polyNeighbor->toString());
- }
- }
- }
- else if (poiIsSport)
- {
- //this is a little loose, b/c there could be more than one type match set of tags...
- if (PoiPolygonTypeScoreExtractor::isSport(polyNeighbor) &&
- polyNeighborGeom->contains(poiGeom.get()) &&
- typeScorer.extract(*_map, poi, polyNeighbor) >= _typeScoreThreshold)
- {
- sportPoiOnOtherSportPolyWithTypeMatch = true;
- }
- }
- else if (buildingCrit.isSatisfied(polyNeighbor))
- {
- if (polyNeighborGeom->contains(poiGeom.get()))
- {
- poiOnBuilding = true;
- }
- }
- }
-
- LOG_VART(poiToOtherParkPolyNodeDist);
- LOG_VART(polyVeryCloseToAnotherParkPoly);
- LOG_VART(poiToPolyNodeDist);
- LOG_VART(poiToOtherParkPolyNodeDist);
- LOG_VART(otherParkPolyHasName);
- LOG_VART(otherParkPolyNameMatch);
- LOG_VART(otherParkPolyNameScore);
- LOG_VART(poiContainedInAnotherParkPoly);
- LOG_VART(sportPoiOnOtherSportPolyWithTypeMatch);
- LOG_VART(poiOnBuilding);
-
- //If the POI is inside a poly that is very close to another park poly, declare miss if
- //the distance to the outer ring of the other park poly is shorter than the distance to the
- //outer ring of this poly and the other park poly has a name.
- if ((poiIsPark || poiIsParkish) && polyVeryCloseToAnotherParkPoly && _distance == 0 &&
- poiToOtherParkPolyNodeDist < poiToPolyNodeDist && poiToPolyNodeDist != DBL_MAX &&
- poiToOtherParkPolyNodeDist != DBL_MAX && otherParkPolyHasName &&
- parkPolyOverlapVal < 0.9)
+ LOG_VART(poly);
+ LOG_VART(polyNeighbor);
+
+ LOG_TRACE("Checking rule #26...");
+ const double poiToNeighborPolyDist =
+ _infoCache->getPolyToPointDistance(polyNeighborAsWay, poi);
+ LOG_VART(poiToNeighborPolyDist);
+ if (poiToNeighborPolyDist != -1.0 && _distance > poiToNeighborPolyDist)
{
LOG_TRACE("Returning miss per review reduction rule #26...");
return true;
}
+ }
- //If the poi is a park, the poly it is being compared to is not a park or building, and that
- //poly is "very close" to another park poly that has a name match with the poi, then
- //declare a miss (exclude poly playgrounds from this).
- if (poiIsPark && !polyIsPark && !polyIsBuilding && polyVeryCloseToAnotherParkPoly &&
- //Unfortunately, include polyIsPlayground here blows up too many matches.
- otherParkPolyNameMatch /*&& !polyIsPlayground*/)
- {
- LOG_TRACE("Returning miss per review reduction rule #27...");
- return true;
- }
+ if (_infoCache->isType(polyNeighbor, "park"))
+ {
+ // Should this be OsmSchema::elementHasName instead?
+ otherParkPolyHasName = !polyNeighbor->getTags().get("name").trimmed().isEmpty();
+ otherParkPolyNameScore = PoiPolygonNameScoreExtractor().extract(*_map, poi, polyNeighbor);
+ otherParkPolyNameMatch = otherParkPolyNameScore >= _nameScoreThreshold;
- //If a park poi is contained within one park poly, then there's no reason for it to trigger
- //reviews in another one that its not contained in.
- if (poiIsPark && polyIsPark && _distance > 0 && poiContainedInAnotherParkPoly)
+ if (_infoCache->polyContainsPoi(polyNeighborAsWay, poi))
{
- LOG_TRACE("Returning miss per review reduction rule #28...");
- return true;
+ poiContainedInAnotherParkPoly = true;
+ LOG_TRACE(
+ "poi examined and found to be contained within a park poly outside of this match " <<
+ "comparison: " << poi->toString());
+ LOG_TRACE("park poly it is very close to: " << polyNeighbor->toString());
}
- //If a sport poi is contained within a type match sport poi poly, don't let it be
- //matched against anything else.
- if (poiIsSport && poiContainedInParkPoly && sportPoiOnOtherSportPolyWithTypeMatch)
+ if (_infoCache->elementIntersectsElement(polyNeighbor, poly))
{
- LOG_TRACE("Returning miss per review reduction rule #29...");
- return true;
- }
+ parkPolyAngleHistVal = AngleHistogramExtractor().extract(*_map, polyNeighbor, poly);
+ LOG_VART(parkPolyAngleHistVal);
+ parkPolyOverlapVal = OverlapExtractor().extract(*_map, polyNeighbor, poly);
+ LOG_VART(parkPolyOverlapVal);
+
+ //When just using intersection as the criteria, only found one instance when something
+ //was considered as "very close" to a park poly when I didn't want it to be...so these
+ //values set very low to weed that instance out...overlap at least.
+ if (parkPolyAngleHistVal != -1.0 && parkPolyOverlapVal != 1.0 &&
+ parkPolyAngleHistVal >= 0.05 && parkPolyOverlapVal >= 0.02)
+ {
+ polyVeryCloseToAnotherParkPoly = true;
- //If a poi is like and on top of a building, don't review it against a non-building poly.
- if (poiIsBuilding && poiOnBuilding && !polyIsBuilding)
- {
- LOG_TRACE("Returning miss per review reduction rule #30...");
- return true;
+ if (poly->getElementType() == ElementType::Way &&
+ polyNeighbor->getElementType() == ElementType::Way)
+ {
+ //Calc the distance from the poi to the poly line instead of the poly itself.
+ //Calcing distance to the poly itself will always return 0 when the poi is in the
+ //poly.
+ poiToPolyNodeDist = _infoCache->getPolyToPointDistance(polyAsWay, poi);
+ poiToOtherParkPolyNodeDist =
+ _infoCache->getPolyToPointDistance(polyNeighborAsWay, poi);
+ }
+ LOG_TRACE(
+ "poly examined and found very close to a another park poly: " << poly->toString());
+ LOG_TRACE("park poly it is very close to: " << polyNeighbor->toString());
+ }
}
-
- //If the poi is not a park and being compared to a park polygon or a polygon that is
- //"very close" to another park poly, we want to be more restrictive on type matching, but
- //only if the poi has any type at all. If the poi has no type, then behave as normal.
- //Also, let an exact name match cause a review here, rather than a miss.
- if ((polyIsPark || (polyVeryCloseToAnotherParkPoly && !polyHasType)) &&
- !polyHasMoreThanOneType && !poiIsPark && !poiIsParkish && poiHasType)
+ }
+ else if (poiIsSport)
+ {
+ //this is a little loose, b/c there could be more than one type match set of tags...
+ if (_infoCache->isType(polyNeighbor, "sport") &&
+ _infoCache->polyContainsPoi(polyNeighborAsWay, poi) &&
+ PoiPolygonTypeScoreExtractor().extract(*_map, poi, polyNeighbor) >= _typeScoreThreshold)
{
- if (!_exactNameMatch)
- {
- LOG_TRACE("Returning miss per review reduction rule #31...");
- return true;
- }
+ sportPoiOnOtherSportPolyWithTypeMatch = true;
}
}
- catch (const geos::util::TopologyException& e)
+ else if (_infoCache->hasCriterion(
+ polyNeighbor, QString::fromStdString(BuildingCriterion::className())))
{
- if (_badGeomCount <= Log::getWarnMessageLimit())
+ if (_infoCache->polyContainsPoi(polyNeighborAsWay, poi))
{
- LOG_TRACE(
- "Feature passed to PoiPolygonMatchCreator caused topology exception on conversion to a " <<
- "geometry: " << polyNeighbor->toString() << "\n" << e.what());
- _badGeomCount++;
+ poiOnBuilding = true;
}
}
- }
- }
- return false;
-}
+ LOG_VART(poiToOtherParkPolyNodeDist);
+ LOG_VART(polyVeryCloseToAnotherParkPoly);
+ LOG_VART(poiToPolyNodeDist);
+ LOG_VART(poiToOtherParkPolyNodeDist);
+ LOG_VART(otherParkPolyHasName);
+ LOG_VART(otherParkPolyNameMatch);
+ LOG_VART(otherParkPolyNameScore);
+ LOG_VART(poiContainedInAnotherParkPoly);
+ LOG_VART(sportPoiOnOtherSportPolyWithTypeMatch);
+ LOG_VART(poiOnBuilding);
+
+ //If the POI is inside a poly that is very close to another park poly, declare miss if
+ //the distance to the outer ring of the other park poly is shorter than the distance to the
+ //outer ring of this poly and the other park poly has a name.
+ LOG_TRACE("Checking rule #27...");
+ if ((poiIsPark || poiIsParkish) && polyVeryCloseToAnotherParkPoly && _distance == 0 &&
+ poiToOtherParkPolyNodeDist < poiToPolyNodeDist && poiToPolyNodeDist != DBL_MAX &&
+ poiToPolyNodeDist != -1.0 && poiToOtherParkPolyNodeDist != DBL_MAX &&
+ poiToOtherParkPolyNodeDist != -1.0 && otherParkPolyHasName && parkPolyOverlapVal < 0.9)
+ {
+ LOG_TRACE("Returning miss per review reduction rule #27...");
+ return true;
+ }
-bool PoiPolygonReviewReducer::_poiNeighborIsCloserToPolyThanPoi(ConstElementPtr poi,
- ConstElementPtr poly)
-{
- LOG_VART(_poiNeighborIds);
- for (set<ElementId>::const_iterator poiNeighborItr = _poiNeighborIds.begin();
- poiNeighborItr != _poiNeighborIds.end(); ++poiNeighborItr)
- {
- ConstElementPtr poiNeighbor = _map->getElement(*poiNeighborItr);
- if (poiNeighbor->getElementId() != poi->getElementId())
- {
- std::shared_ptr<Geometry> poiNeighborGeom;
- try
+ //If the poi is a park, the poly it is being compared to is not a park or building, and that
+ //poly is "very close" to another park poly that has a name match with the poi, then
+ //declare a miss (exclude poly playgrounds from this).
+ LOG_TRACE("Checking rule #28...");
+ if (poiIsPark && !polyIsPark && !polyIsBuilding && polyVeryCloseToAnotherParkPoly &&
+ otherParkPolyNameMatch)
{
- poiNeighborGeom = ElementConverter(_map).convertToGeometry(poiNeighbor);
+ LOG_TRACE("Returning miss per review reduction rule #28...");
+ return true;
+ }
- if (poiNeighborGeom.get() &&
- QString::fromStdString(poiNeighborGeom->toString()).toUpper().contains("EMPTY"))
- {
- if (_badGeomCount <= Log::getWarnMessageLimit())
- {
- LOG_TRACE(
- "Invalid neighbor POI passed to PoiPolygonMatchCreator: " <<
- poiNeighborGeom->toString());
- _badGeomCount++;
- }
- }
- else if (poiNeighborGeom.get())
- {
- LOG_VART(poi);
- LOG_VART(poiNeighbor);
- // This only handles ways as polygons and not relations
- ConstWayPtr polyWay = std::dynamic_pointer_cast<const Way>(poly);
- if (polyWay)
- {
- std::shared_ptr<const LineString> polyLineStr =
- std::dynamic_pointer_cast<const LineString>(
- ElementConverter(_map).convertToLineString(polyWay));
- const long neighborPoiToPolyDist = polyLineStr->distance(poiNeighborGeom.get());
- LOG_VART(neighborPoiToPolyDist);
- if (_distance > neighborPoiToPolyDist)
- {
- LOG_TRACE("Returning miss per review reduction rule #25a...");
- return true;
- }
- }
- }
+ //If a park poi is contained within one park poly, then there's no reason for it to trigger
+ //reviews in another one that its not contained in.
+ LOG_TRACE("Checking rule #29...");
+ if (poiIsPark && polyIsPark && _distance > 0 && poiContainedInAnotherParkPoly)
+ {
+ LOG_TRACE("Returning miss per review reduction rule #29...");
+ return true;
}
- catch (const geos::util::TopologyException& e)
+
+ //If a sport poi is contained within a type match sport poi poly, don't let it be
+ //matched against anything else.
+ LOG_TRACE("Checking rule #30...");
+ if (poiIsSport && poiContainedInParkPoly && sportPoiOnOtherSportPolyWithTypeMatch)
{
- if (_badGeomCount <= Log::getWarnMessageLimit())
- {
- LOG_TRACE(
- "Feature passed to PoiPolygonMatchCreator caused topology exception on conversion to a " <<
- "geometry: " << poiNeighbor->toString() << "\n" << e.what());
- _badGeomCount++;
- }
+ LOG_TRACE("Returning miss per review reduction rule #30...");
+ return true;
+ }
+
+ //If a poi is like and on top of a building, don't review it against a non-building poly.
+ LOG_TRACE("Checking rule #31...");
+ if (poiIsBuilding && poiOnBuilding && !polyIsBuilding)
+ {
+ LOG_TRACE("Returning miss per review reduction rule #31...");
+ return true;
+ }
+
+ //If the poi is not a park and being compared to a park polygon or a polygon that is
+ //"very close" to another park poly, we want to be more restrictive on type matching, but
+ //only if the poi has any type at all. If the poi has no type, then behave as normal.
+ //Also, let an exact name match cause a review here, rather than a miss.
+ LOG_TRACE("Checking rule #32...");
+ if ((polyIsPark || (polyVeryCloseToAnotherParkPoly && !polyHasType)) &&
+ !polyHasMoreThanOneType && !poiIsPark && !poiIsParkish && poiHasType && _exactNameMatch)
+ {
+ LOG_TRACE("Returning miss per review reduction rule #32...");
+ return true;
}
}
}