v0.2.55..v0.2.56 changeset ChangesetReplacementCreator.cpp
Garret Voltz edited this page Aug 14, 2020
·
3 revisions
diff --git a/hoot-core/src/main/cpp/hoot/core/algorithms/changeset/ChangesetReplacementCreator.cpp b/hoot-core/src/main/cpp/hoot/core/algorithms/changeset/ChangesetReplacementCreator.cpp
index c2f23e0..ce6d265 100644
--- a/hoot-core/src/main/cpp/hoot/core/algorithms/changeset/ChangesetReplacementCreator.cpp
+++ b/hoot-core/src/main/cpp/hoot/core/algorithms/changeset/ChangesetReplacementCreator.cpp
@@ -36,10 +36,10 @@
#include <hoot/core/conflate/CookieCutter.h>
#include <hoot/core/conflate/SuperfluousConflateOpRemover.h>
#include <hoot/core/conflate/UnifyingConflator.h>
-#include <hoot/core/conflate/network/NetworkMatchCreator.h>
#include <hoot/core/criterion/ConflatableElementCriterion.h>
#include <hoot/core/criterion/ElementTypeCriterion.h>
+#include <hoot/core/criterion/HighwayCriterion.h>
#include <hoot/core/criterion/InBoundsCriterion.h>
#include <hoot/core/criterion/LinearCriterion.h>
#include <hoot/core/criterion/NotCriterion.h>
@@ -90,7 +90,9 @@
#include <hoot/core/visitors/FilteredVisitor.h>
#include <hoot/core/visitors/RemoveElementsVisitor.h>
#include <hoot/core/visitors/RemoveDuplicateRelationMembersVisitor.h>
+#include <hoot/core/visitors/RemoveInvalidMultilineStringMembersVisitor.h>
#include <hoot/core/visitors/RemoveMissingElementsVisitor.h>
+#include <hoot/core/visitors/RemoveTagsVisitor.h>
#include <hoot/core/visitors/ReportMissingElementsVisitor.h>
#include <hoot/core/visitors/SetTagValueVisitor.h>
@@ -100,14 +102,15 @@ namespace hoot
ChangesetReplacementCreator::ChangesetReplacementCreator(
const bool printStats, const QString& statsOutputFile, const QString osmApiDbUrl) :
_fullReplacement(false),
-_lenientBounds(true),
+_boundsInterpretation(BoundsInterpretation::Lenient),
_geometryFiltersSpecified(false),
_chainReplacementFilters(false),
_chainRetainmentFilters(false),
_waySnappingEnabled(true),
_conflationEnabled(true),
_cleaningEnabled(true),
-_tagOobConnectedWays(false)
+_tagOobConnectedWays(false),
+_currentChangeDerivationPassIsLinear(false)
{
_changesetCreator.reset(new ChangesetCreator(printStats, statsOutputFile, osmApiDbUrl));
@@ -285,17 +288,32 @@ void ChangesetReplacementCreator::setReplacementFilterOptions(const QStringList&
_setInputFilterOptions(_replacementFilterOptions, optionKvps);
}
-QString ChangesetReplacementCreator::_getJobDescription(
- const QString& input1, const QString& input2, const QString& bounds,
- const QString& output) const
+QString ChangesetReplacementCreator::_boundsInterpretationToString(
+ const BoundsInterpretation& boundsInterpretation) const
{
- const int maxFilePrintLength = ConfigOptions().getProgressVarPrintLengthMax();
- QString lenientStr = "Bounds calculation is ";
- if (!_lenientBounds)
+ switch (boundsInterpretation)
{
- lenientStr += "not ";
+ case BoundsInterpretation::Lenient:
+ return "lenient";
+
+ case BoundsInterpretation::Strict:
+ return "strict";
+
+ case BoundsInterpretation::Hybrid:
+ return "hybrid";
+
+ default:
+ return "";
}
- lenientStr += "lenient.";
+}
+
+void ChangesetReplacementCreator::_printJobDescription(
+ const QString& input1, const QString& input2, const QString& bounds,
+ const QString& output) const
+{
+ const int maxFilePrintLength = ConfigOptions().getProgressVarPrintLengthMax() * 2;
+ QString boundsStr = "Bounds calculation is " +
+ _boundsInterpretationToString(_boundsInterpretation);
const QString replacementTypeStr = _fullReplacement ? "full" : "overlapping only";
QString geometryFiltersStr = "are ";
if (!_geometryFiltersSpecified)
@@ -345,7 +363,10 @@ QString ChangesetReplacementCreator::_getJobDescription(
str += "\nBeing replaced: ..." + input1.right(maxFilePrintLength);
str += "\nReplacing with ..." + input2.right(maxFilePrintLength);
str += "\nOutput Changeset: ..." + output.right(maxFilePrintLength);
- str += "\nBounds: " + bounds + lenientStr;
+ LOG_STATUS(str);
+
+ str = "";
+ str += "\nBounds interpretation: " + bounds + "; " + boundsStr;
str += "\nReplacement is: " + replacementTypeStr;
str += "\nGeometry filters: " + geometryFiltersStr;
str += "\nReplacement filter: " + replacementFiltersStr;
@@ -354,7 +375,7 @@ QString ChangesetReplacementCreator::_getJobDescription(
str += "\nCleaning: " + cleaningStr;
str += "\nWay snapping: " + waySnappingStr;
str += "\nOut of bounds way handling: " + oobWayHandlingStr;
- return str;
+ LOG_DEBUG(str);
}
void ChangesetReplacementCreator::setRetainmentFilterOptions(const QStringList& optionKvps)
@@ -369,16 +390,15 @@ void ChangesetReplacementCreator::create(
{
// INPUT VALIDATION AND SETUP
- _validateInputs(input1, input2);
+ _validateInputs(input1, input2, output);
const QString boundsStr = GeometryUtils::envelopeToConfigString(bounds);
_setGlobalOpts(boundsStr);
-
- LOG_INFO(_getJobDescription(input1, input2, boundsStr, output));
+ _printJobDescription(input1, input2, boundsStr, output);
// If a retainment filter was specified, we'll AND it together with each geometry type filter to
// further restrict what reference data gets replaced in the final changeset.
const QMap<GeometryTypeCriterion::GeometryType, ElementCriterionPtr> refFilters =
- _getCombinedFilters(_retainmentFilter);
+ _getCombinedFilters(_retainmentFilter);
// If a replacement filter was specified, we'll AND it together with each geometry type filter to
// further restrict what secondary replacement data goes into the final changeset.
const QMap<GeometryTypeCriterion::GeometryType, ElementCriterionPtr> secFilters =
@@ -395,8 +415,8 @@ void ChangesetReplacementCreator::create(
for (QMap<GeometryTypeCriterion::GeometryType, ElementCriterionPtr>::const_iterator itr =
refFilters.begin(); itr != refFilters.end(); ++itr)
{
- LOG_INFO("******************************************");
- LOG_INFO(
+ LOG_STATUS("******************************************");
+ LOG_STATUS(
"Preparing maps for changeset derivation given geometry type: "<<
GeometryTypeCriterion::typeToString(itr.key()) << ". Pass: " << passCtr << " / " <<
refFilters.size() << "...");
@@ -412,9 +432,7 @@ void ChangesetReplacementCreator::create(
}
ElementCriterionPtr refFilter = itr.value();
- LOG_VARD(refFilter->toString());
ElementCriterionPtr secFilter = secFilters[itr.key()];
- LOG_VARD(secFilter->toString());
_getMapsForGeometryType(
refMap, conflatedMap, input1, input2, boundsStr, refFilter, secFilter, itr.key(),
@@ -442,6 +460,8 @@ void ChangesetReplacementCreator::create(
"Adding ref map of size: " << refMap->size() << " and conflated map of size: " <<
conflatedMap->size() << " to changeset derivation queue for geometry type: " <<
GeometryTypeCriterion::typeToString(itr.key()) << "...");
+ // TODO: move set name here to inside _getMapsForGeometryType, so we can see the geometry type
+ // in the name??
refMap->setName(refMap->getName() + "-" + GeometryTypeCriterion::typeToString(itr.key()));
refMaps.append(refMap);
conflatedMap->setName(
@@ -502,19 +522,26 @@ void ChangesetReplacementCreator::_getMapsForGeometryType(
const GeometryTypeCriterion::GeometryType& geometryType,
const QStringList& linearFilterClassNames)
{
- LOG_VART(linearFilterClassNames);
- LOG_VART(secFeatureFilter);
+ LOG_VARD(linearFilterClassNames);
+ LOG_VARD(refFeatureFilter->toString());
+ LOG_VARD(secFeatureFilter->toString());
// INPUT VALIDATION AND SETUP
- _parseConfigOpts(_lenientBounds, geometryType);
+ _parseConfigOpts(geometryType);
// DATA LOAD AND INITIAL PREP
- // load the ref dataset and crop to the specified aoi
+ // load the ref dataset and crop to the specified aoi; can't cache here b/c the map is cropped
+ // during reading differently based on the geometry type
+ // TODO: we could maybe load the full map the first time and then crop the raw map only based
+ // on geometry type each time, rather than reload it from the source
refMap = _loadRefMap(input1);
MemoryUsageChecker::getInstance().check();
+ // always remove any existing missing child tags
+ RemoveTagsVisitor missingChildTagRemover(QStringList(MetadataTags::HootMissingChild()));
+ refMap->visitRw(missingChildTagRemover);
const bool markMissing =
ConfigOptions().getChangesetReplacementMarkElementsWithMissingChildren();
if (markMissing)
@@ -530,9 +557,9 @@ void ChangesetReplacementCreator::_getMapsForGeometryType(
// versions later.
const QMap<ElementId, long> refIdToVersionMappings = _getIdToVersionMappings(refMap);
- const bool isLinearCrit = !linearFilterClassNames.isEmpty();
- LOG_VART(isLinearCrit);
- if (_tagOobConnectedWays && _lenientBounds && isLinearCrit)
+ _currentChangeDerivationPassIsLinear = !linearFilterClassNames.isEmpty();
+ LOG_VART(_currentChangeDerivationPassIsLinear);
+ if (_tagOobConnectedWays && _currentChangeDerivationPassIsLinear)
{
// If we have a lenient bounds requirement and linear features, we need to exclude all ways
// outside of the bounds but immediately connected to a way crossing the bounds from deletion.
@@ -545,10 +572,11 @@ void ChangesetReplacementCreator::_getMapsForGeometryType(
refMap, refFeatureFilter, conf(),
"ref-after-" + GeometryTypeCriterion::typeToString(geometryType) + "-pruning");
- // load the sec dataset and crop to the specified aoi
+ // load the sec dataset and crop to the specified aoi; see note for ref map load
OsmMapPtr secMap = _loadSecMap(input2);
MemoryUsageChecker::getInstance().check();
+ secMap->visitRw(missingChildTagRemover);
if (markMissing)
{
_markElementsWithMissingChildren(secMap);
@@ -556,8 +584,10 @@ void ChangesetReplacementCreator::_getMapsForGeometryType(
// Prune the sec dataset down to just the feature types specified by the filter, so we don't end
// up modifying anything else.
+ const Settings secFilterSettings =
+ _replacementFilterOptions.size() == 0 ? conf() : _replacementFilterOptions;
_filterFeatures(
- secMap, secFeatureFilter, _replacementFilterOptions,
+ secMap, secFeatureFilter, secFilterSettings,
"sec-after-" + GeometryTypeCriterion::typeToString(geometryType) + "-pruning");
const int refMapSize = refMap->size();
@@ -569,8 +599,10 @@ void ChangesetReplacementCreator::_getMapsForGeometryType(
// CUT
+ const geos::geom::Envelope replacementBounds = GeometryUtils::envelopeFromConfigString(boundsStr);
+
// cut the secondary data out of the reference data
- OsmMapPtr cookieCutRefMap = _getCookieCutMap(refMap, secMap, geometryType);
+ OsmMapPtr cookieCutRefMap = _getCookieCutMap(refMap, secMap, geometryType, replacementBounds);
// At one point it was necessary to re-number the relations in the sec map, as they could have ID
// overlap with those in the cookie cut ref map at this point. It seemed that this was due to the
@@ -588,13 +620,15 @@ void ChangesetReplacementCreator::_getMapsForGeometryType(
// conflate the cookie cut ref map with the sec map if conflation is enabled
+ // TODO: rename var since this map isn't necessary conflated; also rename everything in terms of
+ // "toReplace" and "replacement"
conflatedMap = cookieCutRefMap;
if (secMapSize > 0)
{
if (_conflationEnabled)
{
// conflation cleans beforehand
- _conflate(conflatedMap, _lenientBounds);
+ _conflate(conflatedMap);
conflatedMap->setName("conflated");
if (!ConfigOptions().getChangesetReplacementPassConflateReviews())
@@ -614,7 +648,7 @@ void ChangesetReplacementCreator::_getMapsForGeometryType(
// SNAP
- if (isLinearCrit && _waySnappingEnabled)
+ if (_currentChangeDerivationPassIsLinear && _waySnappingEnabled)
{
// Snap secondary features back to reference features if dealing with linear features where
// ref features may have been cut along the bounds. We're being lenient here by snapping
@@ -622,6 +656,7 @@ void ChangesetReplacementCreator::_getMapsForGeometryType(
// want to snap ways of like types together, so we'll loop through each applicable linear type
// and snap them separately.
+ LOG_STATUS("Snapping unconnected ways to each other...");
QStringList snapWayStatuses("Input2");
snapWayStatuses.append("Conflated");
QStringList snapToWayStatuses("Input1");
@@ -642,7 +677,8 @@ void ChangesetReplacementCreator::_getMapsForGeometryType(
// PRE-CHANGESET DERIVATION DATA PREP
OsmMapPtr immediatelyConnectedOutOfBoundsWays;
- if (_lenientBounds && isLinearCrit)
+ if (_boundsInterpretation == BoundsInterpretation::Lenient &&
+ _currentChangeDerivationPassIsLinear)
{
// If we're conflating linear features with the lenient bounds requirement, copy the
// immediately connected out of bounds ways to a new temp map. We'll lose those ways once we
@@ -653,17 +689,15 @@ void ChangesetReplacementCreator::_getMapsForGeometryType(
}
// Crop the original ref and conflated maps appropriately for changeset derivation.
- const geos::geom::Envelope bounds = GeometryUtils::envelopeFromConfigString(boundsStr);
_cropMapForChangesetDerivation(
- refMap, bounds, _boundsOpts.changesetRefKeepEntireCrossingBounds,
+ refMap, replacementBounds, _boundsOpts.changesetRefKeepEntireCrossingBounds,
_boundsOpts.changesetRefKeepOnlyInsideBounds, "ref-cropped-for-changeset");
_cropMapForChangesetDerivation(
- conflatedMap, bounds, _boundsOpts.changesetSecKeepEntireCrossingBounds,
+ conflatedMap, replacementBounds, _boundsOpts.changesetSecKeepEntireCrossingBounds,
_boundsOpts.changesetSecKeepOnlyInsideBounds, "sec-cropped-for-changeset");
- LOG_VART(_lenientBounds);
- LOG_VART(isLinearCrit);
- if (_lenientBounds && isLinearCrit)
+ if (_boundsInterpretation == BoundsInterpretation::Lenient &&
+ _currentChangeDerivationPassIsLinear)
{
if (_waySnappingEnabled)
{
@@ -674,6 +708,7 @@ void ChangesetReplacementCreator::_getMapsForGeometryType(
// we're being as lenient as possible with the snapping here, allowing basically anything to
// join to anything else, which could end up causing problems...we'll go with it for now.
+ LOG_STATUS("Snapping unconnected ways to each other...");
QStringList snapWayStatuses("Input2");
snapWayStatuses.append("Conflated");
snapWayStatuses.append("Input1");
@@ -693,15 +728,21 @@ void ChangesetReplacementCreator::_getMapsForGeometryType(
_combineMaps(
conflatedMap, immediatelyConnectedOutOfBoundsWays, true, "conflated-connected-combined");
- // Snap only the connected ways to other ways in the conflated map. Mark the ways that were
+ // Snap the connected ways to other ways in the conflated map. Mark the ways that were
// snapped, as we'll need that info in the next step.
if (_waySnappingEnabled)
{
LOG_VART(linearFilterClassNames);
for (int i = 0; i < linearFilterClassNames.size(); i++)
{
+ QStringList snapWayStatuses("Input2");
+ snapWayStatuses.append("Conflated");
+ snapWayStatuses.append("Input1");
+ QStringList snapToWayStatuses("Input1");
+ snapToWayStatuses.append("Conflated");
+ snapToWayStatuses.append("Input2");
_snapUnconnectedWays(
- conflatedMap, QStringList("Input1"), QStringList("Input1"), linearFilterClassNames.at(i),
+ conflatedMap, snapWayStatuses, snapToWayStatuses, linearFilterClassNames.at(i),
true, "conflated-snapped-immediately-connected-out-of-bounds");
}
}
@@ -723,7 +764,7 @@ void ChangesetReplacementCreator::_getMapsForGeometryType(
_excludeFeaturesFromChangesetDeletion(refMap, boundsStr);
}
- // clean up introduced mistakes
+ // clean up any mistakes introduced
_cleanup(refMap);
_cleanup(conflatedMap);
@@ -731,7 +772,8 @@ void ChangesetReplacementCreator::_getMapsForGeometryType(
LOG_VART(conflatedMap->getElementCount());
}
-void ChangesetReplacementCreator::_validateInputs(const QString& input1, const QString& input2)
+void ChangesetReplacementCreator::_validateInputs(const QString& input1, const QString& input2,
+ const QString& output)
{
// Fail if the reader that supports either input doesn't implement Boundable.
std::shared_ptr<Boundable> boundable =
@@ -758,6 +800,16 @@ void ChangesetReplacementCreator::_validateInputs(const QString& input1, const Q
"GeoJSON inputs are not supported by replacement changeset derivation.");
}
+ QFile outputFile(output);
+ if (outputFile.exists())
+ {
+ if (!outputFile.remove())
+ {
+ throw HootException("Unable to remove changeset output file: " + output);
+ }
+ }
+
+ LOG_VARD(_fullReplacement);
if (_fullReplacement && _retainmentFilter)
{
throw IllegalArgumentException(
@@ -765,7 +817,7 @@ void ChangesetReplacementCreator::_validateInputs(const QString& input1, const Q
"be specified for replacement changeset derivation.");
}
- if (ConfigOptions().getConvertOps().size())
+ if (ConfigOptions().getConvertOps().size() > 0)
{
throw IllegalArgumentException(
"Replacement changeset derivation does not support convert operations.");
@@ -800,9 +852,38 @@ void ChangesetReplacementCreator::_setGlobalOpts(const QString& boundsStr)
ConfigUtils::removeListOpEntry(
ConfigOptions::getConflatePostOpsKey(),
QString::fromStdString(RemoveMissingElementsVisitor::className()));
+ // Having to set multiple different settings to prevent missing elements from being dropped here
+ // is convoluted...may need to look into changing at some point.
conf().set(ConfigOptions::getConvertBoundingBoxRemoveMissingElementsKey(), false);
+ conf().set(ConfigOptions::getMapReaderAddChildRefsWhenMissingKey(), true);
+ conf().set(ConfigOptions::getLogWarningsForMissingElementsKey(), false);
- // These don't change between scenarios (or at least we haven't needed to yet).
+ // If we're adding missing child element tags to parents, then we need to explicitly specify that
+ // they are allowed to pass through to the changeset output. See notes where
+ // _markElementsWithMissingChildren is called for more info on why this tag is added.
+ if (ConfigOptions().getChangesetReplacementMarkElementsWithMissingChildren())
+ {
+ QStringList metadataAllowTagKeys(MetadataTags::HootMissingChild());
+ conf().set(ConfigOptions::getChangesetMetadataAllowedTagKeysKey(), metadataAllowTagKeys);
+ }
+
+ // Came across a very odd bug in #4101, where if RemoveInvalidMultilineStringMembersVisitor ran
+ // as part of the pre-conflate map cleaning during replacement with conflation enabled, the match
+ // conflict resolution would slow down to a crawl. When it was removed from the cleaning ops, the
+ // conflate operation ran very quickly. So as a not so great workaround (aka hack), removing that
+ // pre-op here when running conflation. It still will run post conflate, though. This change had
+ // a very minor affect on changeset replacement test output where one test got slightly better
+ // output after the change and another slightly worse. See more details in #4101, which is closed,
+ // but if we can figure out what's going on at some point maybe this situation can be handled
+ // properly.
+ if (_conflationEnabled)
+ {
+ ConfigUtils::removeListOpEntry(
+ ConfigOptions::getMapCleanerTransformsKey(),
+ QString::fromStdString(RemoveInvalidMultilineStringMembersVisitor::className()));
+ }
+
+ // These don't change between scenarios (or at least we haven't needed to change them yet).
_boundsOpts.loadRefKeepOnlyInsideBounds = false;
_boundsOpts.cookieCutKeepOnlyInsideBounds = false;
_boundsOpts.changesetRefKeepOnlyInsideBounds = false;
@@ -812,11 +893,13 @@ void ChangesetReplacementCreator::_setGlobalOpts(const QString& boundsStr)
}
void ChangesetReplacementCreator::_parseConfigOpts(
- const bool lenientBounds, const GeometryTypeCriterion::GeometryType& geometryType)
+ const GeometryTypeCriterion::GeometryType& geometryType)
{
if (!_cleaningEnabled && _conflationEnabled)
{
- throw IllegalArgumentException("If conflation is enabled, cleaning cannot be disabled.");
+ throw IllegalArgumentException(
+ "If conflation is enabled during changeset replacement derivation, cleaning cannot be "
+ "disabled.");
}
// These settings have been are customized for each geometry type and bounds handling preference.
@@ -825,19 +908,6 @@ void ChangesetReplacementCreator::_parseConfigOpts(
if (geometryType == GeometryTypeCriterion::GeometryType::Point)
{
- if (lenientBounds)
- {
- const QString msg = "--lenient-bounds option ignored with point datasets.";
- if (_geometryFiltersSpecified)
- {
- LOG_WARN(msg);
- }
- else
- {
- LOG_DEBUG(msg);
- }
- }
-
_boundsOpts.loadRefKeepEntireCrossingBounds = false;
_boundsOpts.loadRefKeepImmediateConnectedWaysOutsideBounds = false;
_boundsOpts.loadSecKeepEntireCrossingBounds = false;
@@ -851,7 +921,7 @@ void ChangesetReplacementCreator::_parseConfigOpts(
}
else if (geometryType == GeometryTypeCriterion::GeometryType::Line)
{
- if (lenientBounds)
+ if (_boundsInterpretation == BoundsInterpretation::Lenient)
{
_boundsOpts.loadRefKeepEntireCrossingBounds = true;
_boundsOpts.loadRefKeepImmediateConnectedWaysOutsideBounds = true;
@@ -878,7 +948,7 @@ void ChangesetReplacementCreator::_parseConfigOpts(
_boundsOpts.inBoundsStrict = false;
// Conflate way joining needs to happen later in the post ops for strict linear replacements.
- // Changing the default ordering of the post ops to accomodate this had detrimental effects
+ // Changing the default ordering of the post ops to accommodate this had detrimental effects
// on other conflation. The best location seems to be at the end just before tag truncation.
// would like to get rid of this...isn't a foolproof fix by any means if the conflate post
// ops end up getting reordered for some reason.
@@ -896,7 +966,8 @@ void ChangesetReplacementCreator::_parseConfigOpts(
}
else if (geometryType == GeometryTypeCriterion::GeometryType::Polygon)
{
- if (lenientBounds)
+ if (_boundsInterpretation == BoundsInterpretation::Lenient ||
+ _boundsInterpretation == BoundsInterpretation::Hybrid)
{
_boundsOpts.loadRefKeepEntireCrossingBounds = true;
_boundsOpts.loadRefKeepImmediateConnectedWaysOutsideBounds = false;
@@ -965,8 +1036,9 @@ QMap<GeometryTypeCriterion::GeometryType, ElementCriterionPtr>
// duplicated in the output. This is why we run a de-duplication routine just before changeset
// derivation...kind of a band-aid unfortunately :-(
- // The map will get set on this point crit by the RemoveElementsVisitor later on, right before its
- // needed.
+ // The maps will get set on the crits here that need them by the RemoveElementsVisitor later on,
+ // right before its needed.
+
ElementCriterionPtr pointCrit(new PointCriterion());
std::shared_ptr<RelationWithPointMembersCriterion> relationPointCrit(
new RelationWithPointMembersCriterion());
@@ -981,12 +1053,11 @@ QMap<GeometryTypeCriterion::GeometryType, ElementCriterionPtr>
OrCriterionPtr lineOr(new OrCriterion(lineCrit, relationLinearCrit));
featureFilters[GeometryTypeCriterion::GeometryType::Line] = lineOr;
- ElementCriterionPtr polyCrit(new PolygonCriterion());
- std::shared_ptr<RelationWithPolygonMembersCriterion> relationPolyCrit(
- new RelationWithPolygonMembersCriterion());
- relationPolyCrit->setAllowMixedChildren(false);
- OrCriterionPtr polyOr(new OrCriterion(polyCrit, relationPolyCrit));
- featureFilters[GeometryTypeCriterion::GeometryType::Polygon] = polyOr;
+ // Poly crit has been converted over to encapsulate RelationWithGeometryMembersCriterion, while
+ // the other types have not yet (#4151).
+ std::shared_ptr<PolygonCriterion> polyCrit(new PolygonCriterion());
+ polyCrit->setAllowMixedChildren(false);
+ featureFilters[GeometryTypeCriterion::GeometryType::Polygon] = polyCrit;
return featureFilters;
}
@@ -1063,7 +1134,7 @@ QMap<GeometryTypeCriterion::GeometryType, ElementCriterionPtr>
}
else
{
- LOG_VART(_geometryTypeFilters.size());
+ LOG_VARD(_geometryTypeFilters.size());
if (_geometryTypeFilters.isEmpty())
{
_geometryTypeFilters = _getDefaultGeometryFilters();
@@ -1114,13 +1185,13 @@ QMap<GeometryTypeCriterion::GeometryType, ElementCriterionPtr>
LOG_TRACE("New combined filter: " << combinedFilters[geomType]->toString());
}
}
- LOG_VART(combinedFilters.size());
+ LOG_VARD(combinedFilters.size());
return combinedFilters;
}
OsmMapPtr ChangesetReplacementCreator::_loadRefMap(const QString& input)
{
- LOG_INFO("Loading reference map: " << input << "...");
+ LOG_STATUS("Loading reference map: " << input << "...");
// We want to alert the user to the fact their ref versions *could* be being populated incorrectly
// to avoid difficulties during changeset application at the end. Its likely if they are incorrect
@@ -1139,7 +1210,7 @@ OsmMapPtr ChangesetReplacementCreator::_loadRefMap(const QString& input)
_boundsOpts.loadRefKeepImmediateConnectedWaysOutsideBounds);
// Here and with sec map loading, attempted to cache the initial map to avoid unnecessary
- // reloading, but it wreaked havoc on the element IDs. May try doing it again later.
+ // reloading, but it wreaked havoc on the element IDs. May try debugging it again later.
OsmMapPtr refMap;
refMap.reset(new OsmMap());
refMap->setName("ref");
@@ -1155,7 +1226,7 @@ OsmMapPtr ChangesetReplacementCreator::_loadRefMap(const QString& input)
OsmMapPtr ChangesetReplacementCreator::_loadSecMap(const QString& input)
{
- LOG_INFO("Loading secondary map: " << input << "...");
+ LOG_STATUS("Loading secondary map: " << input << "...");
conf().set(
ConfigOptions::getConvertBoundingBoxKeepEntireFeaturesCrossingBoundsKey(),
@@ -1180,15 +1251,19 @@ OsmMapPtr ChangesetReplacementCreator::_loadSecMap(const QString& input)
void ChangesetReplacementCreator::_markElementsWithMissingChildren(OsmMapPtr& map)
{
ReportMissingElementsVisitor elementMarker;
- // Originally, this was going to add reviews rather than tagging elements but there was an ID
- // provenance problem with reviews.
+ // Originally, this was going to add reviews rather than tagging elements, but there was an ID
+ // provenance problem when using reviews.
elementMarker.setMarkRelationsForReview(false);
elementMarker.setMarkWaysForReview(false);
elementMarker.setRelationKvp(MetadataTags::HootMissingChild() + "=yes");
elementMarker.setWayKvp(MetadataTags::HootMissingChild() + "=yes");
- LOG_STATUS("\t" << elementMarker.getInitStatusMessage());
+ LOG_STATUS("Marking elements with missing child elements...");
map->visitRelationsRw(elementMarker);
- LOG_STATUS("\t" << elementMarker.getCompletedStatusMessage());
+ LOG_DEBUG(
+ "Marked " << elementMarker.getNumWaysTagged() << " ways with missing child elements.");
+ LOG_DEBUG(
+ "Marked " << elementMarker.getNumRelationsTagged() <<
+ " relations with missing child elements.");
OsmMapWriterFactory::writeDebugMap(map, map->getName() + "-after-missing-marked");
}
@@ -1197,7 +1272,7 @@ void ChangesetReplacementCreator::_filterFeatures(
OsmMapPtr& map, const ElementCriterionPtr& featureFilter, const Settings& config,
const QString& debugFileName)
{
- LOG_INFO(
+ LOG_STATUS(
"Filtering features for: " << map->getName() << " based on input filter: " +
featureFilter->toString() << "...");
@@ -1208,54 +1283,147 @@ void ChangesetReplacementCreator::_filterFeatures(
elementPruner.addCriterion(featureFilter);
elementPruner.setConfiguration(config);
elementPruner.setOsmMap(map.get());
- // If recursion isn't used here, nasty crashes that are hard to track down occur at times. I'm
- // not completely convinced recursion should be used here, though.
+ // If recursion isn't used here, nasty crashes that are hard to track down occur at times. Not
+ // completely convinced recursion should be used here, though.
elementPruner.setRecursive(true);
- LOG_STATUS("\t" << elementPruner.getInitStatusMessage());
+ //LOG_STATUS("\t" << elementPruner.getInitStatusMessage());
map->visitRw(elementPruner);
- LOG_STATUS("\t" << elementPruner.getCompletedStatusMessage());
+ LOG_INFO(elementPruner.getCompletedStatusMessage());
LOG_VART(MapProjector::toWkt(map->getProjection()));
OsmMapWriterFactory::writeDebugMap(map, debugFileName);
}
OsmMapPtr ChangesetReplacementCreator::_getCookieCutMap(
- OsmMapPtr doughMap, OsmMapPtr cutterMap, const GeometryTypeCriterion::GeometryType& geometryType)
+ OsmMapPtr doughMap, OsmMapPtr cutterMap, const GeometryTypeCriterion::GeometryType& geometryType,
+ const geos::geom::Envelope& replacementBounds)
{
- // could use some refactoring here after the addition of _fullReplacement
-
- // If the passed in dough map is empty, there's nothing to be cut out.
- if (doughMap->getElementCount() == 0)
+ // This logic has become extremely complicated over time to handle all the different cut
+ // and replace use cases. There may be way to simplify some of this logic related to
+ // strict/lenient bounds in here by changing some of the initial crop related opts set in
+ // _parseConfigOpts...not sure.
+
+ LOG_VARD(_fullReplacement);
+ LOG_VARD(_boundsInterpretationToString(_boundsInterpretation));
+ LOG_VARD(_currentChangeDerivationPassIsLinear);
+ LOG_VARD(doughMap->size());
+ LOG_VARD(cutterMap->size());
+ OsmMapWriterFactory::writeDebugMap(doughMap, "dough-map-input");
+ OsmMapWriterFactory::writeDebugMap(cutterMap, "cutter-map-input");
+
+ // It could just be an byproduct of how data is being read out by core scripts during testing, but
+ // when doing adjacent cell updates I'm getting cropped data with a bunch of empty relations in
+ // them as input. That eventually needs to be dealt with, but regardless, checking node/way count
+ // and not including relations in the size count is a better check for the total map size so that
+ // the alpha shape gets calculated correctly.
+ const int doughMapInputSize = doughMap->getWayCount() + doughMap->getNodeCount();
+ const int cutterMapInputSize = cutterMap->getWayCount() + cutterMap->getNodeCount();
+
+ /*
+ * lenient/overlapping - cutter shape is all overlapping sec data inside the bounds and
+ * immediately connected outside the bounds OR all ref data inside the
+ * bounds and immediately connected outside the bounds (if linear) if sec
+ * map is empty
+ lenient/full - cutter shape is all ref data inside the bounds and immediately connected
+ outside the bounds (if linear)
+ strict/overlapping - cutter shape is all overlapping sec data inside the bounds
+ strict/full - cutter shape is all ref data inside the bounds
+
+ hybrid bounds acts like strict for linear features and lenient for polygon features.
+ */
+
+ // If the passed in dough map is empty, there's nothing to be cut out. So, just return the empty
+ // ref map.
+ if (doughMapInputSize == 0)
{
- LOG_DEBUG("Nothing to cut from dough map, so returning the dough map as the cut map...");
+ LOG_DEBUG(
+ "Nothing to cut from dough map, so returning the empty dough map as the map after " <<
+ "cutting: " << doughMap->getName() << "...");
+ OsmMapWriterFactory::writeDebugMap(doughMap, "cookie-cut");
return doughMap;
}
- else if (cutterMap->size() == 0)
+ else if (cutterMapInputSize == 0)
{
- if (_fullReplacement)
+ // Linear features need to be handled slightly differently, due to the need to snap cut features
+ // back to reference features when the strict bounds interpretation is enabled.
+ if (!_currentChangeDerivationPassIsLinear)
{
- // If the sec map is empty and we're doing full replacement, we want everything deleted out
- // of the ref for the current feature type in the changeset. So, return an empty map.
- LOG_DEBUG(
- "Nothing in cutter map. Full replacement not enabled, so returning an empty map " <<
- "as the cut map...");
- return OsmMapPtr(new OsmMap());
+ // The bounds interpretation doesn't seem to matter here for non-linear features.
+ if (_fullReplacement)
+ {
+ // If the sec map is empty and we're doing full replacement on non-linear features, we want
+ // everything deleted out of the ref inside the the replacement bounds. So, return an empty
+ // map.
+ LOG_DEBUG(
+ "Nothing in cutter map. Full replacement enabled, so returning an empty map " <<
+ "as the map after cutting...");
+ return OsmMapPtr(new OsmMap());
+ }
+ else
+ {
+ // If the sec map is empty and we're not doing full replacement, there's nothing in the sec
+ // to overlap with the ref, so leave the ref untouched.
+ LOG_DEBUG(
+ "Nothing in cutter map. Full replacement not enabled, so returning the entire dough " <<
+ "map as the map after cutting: " << doughMap->getName() << "...");
+ OsmMapWriterFactory::writeDebugMap(doughMap, "cookie-cut");
+ return doughMap;
+ }
}
else
{
- // If the sec map is empty and we're not doing full replacement, there's nothing in the sec
- // to overlap with the ref, so leave the ref untouched.
- LOG_DEBUG(
- "Nothing in cutter map. Full replacement enabled, so returning the entire dough map " <<
- "as the cut map...");
- return doughMap;
+ if (_fullReplacement && _boundsInterpretation == BoundsInterpretation::Lenient)
+ {
+ // If our map contains linear features only, the sec map is empty, we're doing full
+ // replacement, AND there isn't a strict interpretation of the bounds, we want everything
+ // deleted out of the ref inside the replacement bounds and features immediately connected
+ // outside of the bounds. So, return an empty map.
+ LOG_DEBUG(
+ "Nothing in cutter map for linear features. Full replacement and lenient bounds "
+ "interpretation, so returning an empty map as the map after cutting...");
+ return OsmMapPtr(new OsmMap());
+ }
+ else if (_fullReplacement && _boundsInterpretation != BoundsInterpretation::Lenient )
+ {
+ // With the strict bounds interpretation, full replacement, and an empty secondary map,
+ // we want simply the rectangular replacement bounds cut out. No need to use the cookie
+ // cutter here. Just use the map cropper.
+ LOG_DEBUG(
+ "Nothing in cutter map. Full replacement with strict bounds enabled, so cropping out " <<
+ "the rectangular bounds area of the dough map to be the map after cutting: " <<
+ doughMap->getName() << "...");
+ OsmMapPtr cookieCutMap(new OsmMap(doughMap));
+ cookieCutMap->setName("cookie-cut");
+ MapCropper cropper(replacementBounds);
+ cropper.setRemoveSuperflousFeatures(false);
+ cropper.setKeepEntireFeaturesCrossingBounds(false);
+ cropper.setKeepOnlyFeaturesInsideBounds(false);
+ cropper.setInvert(true);
+ // We're not going to remove missing elements, as we want to have as minimal of an impact on
+ // the resulting changeset as possible.
+ cropper.setRemoveMissingElements(false);
+ LOG_STATUS(cropper.getInitStatusMessage());
+ cropper.apply(cookieCutMap);
+ LOG_INFO(cropper.getCompletedStatusMessage());
+ OsmMapWriterFactory::writeDebugMap(cookieCutMap, "cookie-cut");
+ return cookieCutMap;
+ }
+ else
+ {
+ // If the sec map is empty and we're not doing full replacement, there's nothing in the sec
+ // to overlap with the ref, so leave the ref untouched.
+ LOG_DEBUG(
+ "Nothing in cutter map for linear features. Full replacement not enabled, so returning the "
+ "entire dough map as the map after cutting: " << doughMap->getName() << "...");
+ OsmMapWriterFactory::writeDebugMap(doughMap, "cookie-cut");
+ return doughMap;
+ }
}
}
- LOG_VART(doughMap->getElementCount());
+ LOG_VART(doughMap->size());
LOG_VART(MapProjector::toWkt(doughMap->getProjection()));
- OsmMapWriterFactory::writeDebugMap(doughMap, "dough-map");
- LOG_VART(cutterMap->getElementCount());
+ OsmMapWriterFactory::writeDebugMap(doughMap, "dough-map");;
LOG_VART(MapProjector::toWkt(cutterMap->getProjection()));
OsmMapPtr cookieCutMap(new OsmMap(doughMap));
@@ -1264,50 +1432,71 @@ OsmMapPtr ChangesetReplacementCreator::_getCookieCutMap(
LOG_DEBUG("Preparing to cookie cut: " << cookieCutMap->getName() << "...");
OsmMapPtr cutterMapToUse;
- LOG_VART(cutterMap->getElementCount());
ConfigOptions opts(conf());
LOG_VART(MapUtils::mapIsPointsOnly(cutterMap));
const double cookieCutterAlpha = opts.getCookieCutterAlpha();
double cookieCutterAlphaShapeBuffer = opts.getCookieCutterAlphaShapeBuffer();
- LOG_VART(_fullReplacement);
- if (_fullReplacement)
+ if (_currentChangeDerivationPassIsLinear) // See related note above when the cutter map is empty.
{
- // Generate a cutter shape based on the ref map, which will cause all the ref data to be
- // replaced.
- LOG_DEBUG("Using dough map as cutter shape map...");
- cutterMapToUse = doughMap;
- // TODO: riverbank test fails with missing POIs without this and the single point test has
- // extra POIs in output without this; explain
- cookieCutterAlphaShapeBuffer = 10.0;
+ if (_boundsInterpretation == BoundsInterpretation::Lenient && _fullReplacement)
+ {
+ // Generate a cutter shape based on the ref map, which will cause all the ref data to be
+ // replaced.
+ LOG_DEBUG("Using dough map: " << doughMap->getName() << " as cutter shape map...");
+ cutterMapToUse = doughMap;
+ // TODO: riverbank test fails with missing POIs without this and the single point test has
+ // extra POIs in output without this; explain
+ cookieCutterAlphaShapeBuffer = 10.0;
+ }
+ else
+ {
+ LOG_DEBUG("Using cutter map: " << cutterMap->getName() << " as cutter shape map...");
+ cutterMapToUse = cutterMap;
+ }
}
else
{
- // Generate a cutter shape based on the cropped secondary map, which will cause only
- // overlapping data between the two datasets to be replaced.
- LOG_DEBUG("Using cutter map as cutter shape map...");
- cutterMapToUse = cutterMap;
+ if (_fullReplacement)
+ {
+ // Generate a cutter shape based on the ref map, which will cause all the ref data to be
+ // replaced.
+ LOG_DEBUG("Using dough map: " << doughMap->getName() << " as cutter shape map...");
+ cutterMapToUse = doughMap;
+ // TODO: riverbank test fails with missing POIs without this and the single point test has
+ // extra POIs in output without this; explain
+ cookieCutterAlphaShapeBuffer = 10.0;
+ }
+ else
+ {
+ // Generate a cutter shape based on the cropped secondary map, which will cause only
+ // overlapping data between the two datasets to be replaced.
+ LOG_DEBUG("Using cutter map: " << cutterMap->getName() << " as cutter shape map...");
+ cutterMapToUse = cutterMap;
+ }
}
// Found that if a map only has a couple points or less, generating an alpha shape from them may
- // not be possible (or at least don't know how to yet). So instead, go through the points in
- // the map and replace them with small square polys...from that we can generate the alpha shape.
- if ((int)cutterMapToUse->getElementCount() < 3 && MapUtils::mapIsPointsOnly(cutterMapToUse))
+ // not be possible (or at least don't know how to yet). So instead, go through the points in the
+ // map and replace them with small square shaped polys...from that we can generate the alpha
+ // shape.
+ const int cutterMapToUseSize = cutterMapToUse->getNodeCount();
+ if ((int)cutterMapToUseSize < 3 && MapUtils::mapIsPointsOnly(cutterMapToUse))
{
LOG_DEBUG("Creating a cutter shape map transformation for point map...");
// Make a copy here since we're making destructive changes to the geometry here for alpha shape
// generation purposes only.
cutterMapToUse.reset(new OsmMap(cutterMap));
- PointsToPolysConverter pointConverter/*(1.0)*/;
- LOG_STATUS("\t" << pointConverter.getInitStatusMessage());
+ PointsToPolysConverter pointConverter;
+ LOG_STATUS(pointConverter.getInitStatusMessage());
pointConverter.apply(cutterMapToUse);
- LOG_STATUS("\t" << pointConverter.getCompletedStatusMessage());
+ LOG_INFO(pointConverter.getCompletedStatusMessage());
MapProjector::projectToWgs84(cutterMapToUse);
}
- LOG_VART(cutterMapToUse->getElementCount());
- OsmMapWriterFactory::writeDebugMap(cutterMapToUse, "cutter-map");
+ LOG_VART(cutterMapToUse->size());
+ OsmMapWriterFactory::writeDebugMap(cutterMapToUse, "cutter-map-to-use");
- LOG_INFO("Generating cutter shape map from: " << cutterMapToUse->getName() << "...");
+ LOG_STATUS("Generating cutter shape map from: " << cutterMapToUse->getName() << "...");
LOG_VART(cookieCutterAlpha);
LOG_VART(cookieCutterAlphaShapeBuffer);
@@ -1337,7 +1526,7 @@ OsmMapPtr ChangesetReplacementCreator::_getCookieCutMap(
OsmMapWriterFactory::writeDebugMap(cutterShapeOutlineMap, "cutter-shape");
// Cookie cut the shape of the cutter shape map out of the cropped ref map.
- LOG_INFO("Cookie cutting cutter shape out of: " << cookieCutMap->getName() << "...");
+ LOG_STATUS("Cutting cutter shape out of: " << cookieCutMap->getName() << "...");
// We're not going to remove missing elements, as we want to have as minimal of an impact on
// the resulting changeset as possible.
@@ -1346,9 +1535,8 @@ OsmMapPtr ChangesetReplacementCreator::_getCookieCutMap(
_boundsOpts.cookieCutKeepOnlyInsideBounds, false)
.cut(cutterShapeOutlineMap, cookieCutMap);
MapProjector::projectToWgs84(cookieCutMap); // not exactly sure yet why this needs to be done
- LOG_VARD(cookieCutMap->getElementCount());
+ LOG_VARD(cookieCutMap->size());
MapProjector::projectToWgs84(doughMap);
- LOG_VART(doughMap->getElementCount());
LOG_VART(MapProjector::toWkt(cookieCutMap->getProjection()));
MemoryUsageChecker::getInstance().check();
OsmMapWriterFactory::writeDebugMap(cookieCutMap, "cookie-cut");
@@ -1359,13 +1547,13 @@ OsmMapPtr ChangesetReplacementCreator::_getCookieCutMap(
QMap<ElementId, long> ChangesetReplacementCreator::_getIdToVersionMappings(
const OsmMapPtr& map) const
{
- LOG_DEBUG("Mapping element IDs to element versions for: " << map->getName() << "...");
+ LOG_STATUS("Mapping element IDs to element versions for: " << map->getName() << "...");
ElementIdToVersionMapper idToVersionMapper;
- LOG_STATUS("\t" << idToVersionMapper.getInitStatusMessage());
+ //LOG_STATUS("\t" << idToVersionMapper.getInitStatusMessage());
idToVersionMapper.apply(map);
MemoryUsageChecker::getInstance().check();
- LOG_STATUS("\t" << idToVersionMapper.getCompletedStatusMessage());
+ LOG_DEBUG(idToVersionMapper.getCompletedStatusMessage());
const QMap<ElementId, long> idToVersionMappings = idToVersionMapper.getMappings();
LOG_VART(idToVersionMappings.size());
return idToVersionMappings;
@@ -1373,21 +1561,21 @@ QMap<ElementId, long> ChangesetReplacementCreator::_getIdToVersionMappings(
void ChangesetReplacementCreator::_addChangesetDeleteExclusionTags(OsmMapPtr& map)
{
- LOG_INFO(
+ LOG_STATUS(
"Setting connected way features outside of bounds to be excluded from deletion for: " <<
map->getName() << "...");
// Add the changeset deletion exclusion tag to all connected ways previously tagged upon load.
SetTagValueVisitor addTagVis(MetadataTags::HootChangeExcludeDelete(), "yes");
- LOG_STATUS("\t" << addTagVis.getInitStatusMessage());
+ //LOG_STATUS("\t" << addTagVis.getInitStatusMessage());
ChainCriterion addTagCrit(
std::shared_ptr<WayCriterion>(new WayCriterion()),
std::shared_ptr<TagKeyCriterion>(
new TagKeyCriterion(MetadataTags::HootConnectedWayOutsideBounds())));
FilteredVisitor deleteExcludeTagVis(addTagCrit, addTagVis);
map->visitRw(deleteExcludeTagVis);
- LOG_STATUS("\t" << addTagVis.getCompletedStatusMessage());
+ LOG_DEBUG(addTagVis.getCompletedStatusMessage());
// Add the changeset deletion exclusion tag to all children of those connected ways.
@@ -1398,9 +1586,9 @@ void ChangesetReplacementCreator::_addChangesetDeleteExclusionTags(OsmMapPtr& ma
new TagKeyCriterion(MetadataTags::HootChangeExcludeDelete()))));
RecursiveSetTagValueOp childDeletionExcludeTagOp(
MetadataTags::HootChangeExcludeDelete(), "yes", childAddTagCrit);
- LOG_STATUS("\t" << childDeletionExcludeTagOp.getInitStatusMessage());
+ //LOG_STATUS("\t" << childDeletionExcludeTagOp.getInitStatusMessage());
childDeletionExcludeTagOp.apply(map);
- LOG_STATUS("\t" << childDeletionExcludeTagOp.getCompletedStatusMessage());
+ LOG_DEBUG(childDeletionExcludeTagOp.getCompletedStatusMessage());
MemoryUsageChecker::getInstance().check();
OsmMapWriterFactory::writeDebugMap(map, map->getName() + "-after-delete-exclusion-tagging");
@@ -1421,7 +1609,7 @@ void ChangesetReplacementCreator::_combineMaps(
return;
}
- LOG_INFO("Combining maps: " << map1->getName() << " and " << map2->getName() << "...");
+ LOG_STATUS("Combining maps: " << map1->getName() << " and " << map2->getName() << "...");
map1->append(map2, throwOutDupes);
LOG_VART(MapProjector::toWkt(map1->getProjection()));
@@ -1431,23 +1619,26 @@ void ChangesetReplacementCreator::_combineMaps(
OsmMapWriterFactory::writeDebugMap(map1, debugFileName);
}
-void ChangesetReplacementCreator::_conflate(OsmMapPtr& map, const bool lenientBounds)
+void ChangesetReplacementCreator::_conflate(OsmMapPtr& map)
{
map->setName("conflated");
- LOG_INFO(
+ LOG_STATUS(
"Conflating the cookie cut reference map with the secondary map into " << map->getName() <<
"...");
conf().set(ConfigOptions::getWayJoinerLeaveParentIdKey(), true);
- if (!lenientBounds) // not exactly sure yet why this needs to be done
+ if (_boundsInterpretation != BoundsInterpretation::Lenient)
{
+ // not exactly sure yet why this needs to be done
conf().set(ConfigOptions::getWayJoinerKey(), WayJoinerAdvanced::className());
}
else
{
conf().set(ConfigOptions::getWayJoinerKey(), WayJoinerBasic::className());
}
- conf().set(ConfigOptions::getWayJoinerAdvancedStrictNameMatchKey(), !_isNetworkConflate());
+ conf().set(
+ ConfigOptions::getWayJoinerAdvancedStrictNameMatchKey(),
+ !UnifyingConflator::isNetworkConflate());
if (ConfigOptions().getConflateRemoveSuperfluousOps())
{
@@ -1470,7 +1661,7 @@ void ChangesetReplacementCreator::_conflate(OsmMapPtr& map, const bool lenientBo
void ChangesetReplacementCreator::_removeConflateReviews(OsmMapPtr& map)
{
- LOG_INFO("Removing reviews added during conflation from " << map->getName() << "...");
+ LOG_STATUS("Removing reviews added during conflation from " << map->getName() << "...");
RemoveElementsVisitor removeVis;
removeVis.addCriterion(ElementCriterionPtr(new RelationCriterion("review")));
@@ -1483,9 +1674,9 @@ void ChangesetReplacementCreator::_removeConflateReviews(OsmMapPtr& map)
QString::fromStdString(ReportMissingElementsVisitor::className()))))));
removeVis.setChainCriteria(true);
removeVis.setRecursive(false);
- LOG_STATUS("\t" << removeVis.getInitStatusMessage());
+ //LOG_STATUS("\t" << removeVis.getInitStatusMessage());
map->visitRw(removeVis);
- LOG_STATUS("\t" << removeVis.getCompletedStatusMessage());
+ LOG_DEBUG(removeVis.getCompletedStatusMessage());
MemoryUsageChecker::getInstance().check();
LOG_VART(MapProjector::toWkt(map->getProjection()));
@@ -1495,7 +1686,7 @@ void ChangesetReplacementCreator::_removeConflateReviews(OsmMapPtr& map)
void ChangesetReplacementCreator::_clean(OsmMapPtr& map)
{
map->setName("cleaned");
- LOG_INFO(
+ LOG_STATUS(
"Cleaning the combined cookie cut reference and secondary maps: " << map->getName() << "...");
// TODO: since we're never conflating when we call clean, should we remove cleaning ops like
@@ -1512,7 +1703,7 @@ void ChangesetReplacementCreator::_snapUnconnectedWays(
OsmMapPtr& map, const QStringList& snapWayStatuses, const QStringList& snapToWayStatuses,
const QString& typeCriterionClassName, const bool markSnappedWays, const QString& debugFileName)
{
- LOG_INFO(
+ LOG_DEBUG(
"Snapping ways for map: " << map->getName() << ", with filter type: " <<
typeCriterionClassName << ", snap way statuses: " << snapWayStatuses <<
", snap to way statuses: " << snapToWayStatuses << " ...");
@@ -1528,9 +1719,9 @@ void ChangesetReplacementCreator::_snapUnconnectedWays(
QString::fromStdString(WayNodeCriterion::className()));
lineSnapper.setWayToSnapCriterionClassName(typeCriterionClassName);
lineSnapper.setWayToSnapToCriterionClassName(typeCriterionClassName);
- LOG_STATUS("\t" << lineSnapper.getInitStatusMessage());
+ //LOG_STATUS("\t" << lineSnapper.getInitStatusMessage());
lineSnapper.apply(map);
- LOG_STATUS("\t" << lineSnapper.getCompletedStatusMessage());
+ LOG_DEBUG(lineSnapper.getCompletedStatusMessage());
MapProjector::projectToWgs84(map); // snapping works in planar
LOG_VART(MapProjector::toWkt(map->getProjection()));
@@ -1542,7 +1733,7 @@ OsmMapPtr ChangesetReplacementCreator::_getImmediatelyConnectedOutOfBoundsWays(
const ConstOsmMapPtr& map) const
{
const QString outputMapName = "connected-ways";
- LOG_INFO(
+ LOG_STATUS(
"Copying immediately connected out of bounds ways from: " << map->getName() <<
" to new map: " << outputMapName << "...");
@@ -1569,7 +1760,7 @@ void ChangesetReplacementCreator::_cropMapForChangesetDerivation(
return;
}
- LOG_INFO("Cropping map: " << map->getName() << " for changeset derivation...");
+ LOG_STATUS("Cropping map: " << map->getName() << " for changeset derivation...");
LOG_VART(MapProjector::toWkt(map->getProjection()));
MapCropper cropper(bounds);
@@ -1578,9 +1769,10 @@ void ChangesetReplacementCreator::_cropMapForChangesetDerivation(
// We're not going to remove missing elements, as we want to have as minimal of an impact on
// the resulting changeset as possible.
cropper.setRemoveMissingElements(false);
- LOG_STATUS("\t" << cropper.getInitStatusMessage());
+ // TODO: should removing superfluous features be suppressed here?
+ //LOG_STATUS("\t" << cropper.getInitStatusMessage());
cropper.apply(map);
- LOG_STATUS("\t" << cropper.getCompletedStatusMessage());
+ LOG_DEBUG(cropper.getCompletedStatusMessage());
MemoryUsageChecker::getInstance().check();
LOG_VART(MapProjector::toWkt(map->getProjection()));
@@ -1591,7 +1783,7 @@ void ChangesetReplacementCreator::_cropMapForChangesetDerivation(
void ChangesetReplacementCreator::_removeUnsnappedImmediatelyConnectedOutOfBoundsWays(
OsmMapPtr& map)
{
- LOG_INFO(
+ LOG_STATUS(
"Removing any immediately connected ways that were not previously snapped in: " <<
map->getName() << "...");
@@ -1606,9 +1798,9 @@ void ChangesetReplacementCreator::_removeUnsnappedImmediatelyConnectedOutOfBound
new TagCriterion(MetadataTags::HootSnapped(), "snapped_way")))));
removeVis.setChainCriteria(true);
removeVis.setRecursive(true);
- LOG_STATUS("\t" << removeVis.getInitStatusMessage());
+ //LOG_STATUS("\t" << removeVis.getInitStatusMessage());
map->visitRw(removeVis);
- LOG_STATUS("\t" << removeVis.getCompletedStatusMessage());
+ LOG_DEBUG(removeVis.getCompletedStatusMessage());
MemoryUsageChecker::getInstance().check();
LOG_VART(MapProjector::toWkt(map->getProjection()));
@@ -1623,7 +1815,7 @@ void ChangesetReplacementCreator::_excludeFeaturesFromChangesetDeletion(
return;
}
- LOG_INFO(
+ LOG_STATUS(
"Marking reference features in: " << map->getName() << " for exclusion from deletion...");
std::shared_ptr<InBoundsCriterion> boundsCrit(new InBoundsCriterion(_boundsOpts.inBoundsStrict));
@@ -1634,9 +1826,9 @@ void ChangesetReplacementCreator::_excludeFeaturesFromChangesetDeletion(
new ChainCriterion(std::shared_ptr<WayCriterion>(new WayCriterion()), notInBoundsCrit));
RecursiveSetTagValueOp tagSetter(MetadataTags::HootChangeExcludeDelete(), "yes", elementCrit);
- LOG_STATUS("\t" << tagSetter.getInitStatusMessage());
+ //LOG_STATUS("\t" << tagSetter.getInitStatusMessage());
tagSetter.apply(map);
- LOG_STATUS("\t" << tagSetter.getCompletedStatusMessage());
+ LOG_DEBUG(tagSetter.getCompletedStatusMessage());
MemoryUsageChecker::getInstance().check();
LOG_VART(MapProjector::toWkt(map->getProjection()));
@@ -1687,42 +1879,30 @@ void ChangesetReplacementCreator::_dedupeMaps(const QList<OsmMapPtr>& maps)
void ChangesetReplacementCreator::_cleanup(OsmMapPtr& map)
{
- LOG_INFO("Cleaning up missing elements for " << map->getName() << "...");
-
- // This will handle removing refs in relation members we've cropped out.
-// RemoveMissingElementsVisitor missingElementsRemover;
-// LOG_STATUS("\t" << missingElementsRemover.getInitStatusMessage());
-// map->visitRw(missingElementsRemover);
-// LOG_STATUS("\t" << missingElementsRemover.getCompletedStatusMessage());
+ LOG_STATUS("Cleaning up duplicated elements for " << map->getName() << "...");
// Due to mixed geometry type relations explained in _getDefaultGeometryFilters, we may have
- // introduced some duplicate relation members.
+ // introduced some duplicate relation members by this point.
RemoveDuplicateRelationMembersVisitor dupeMembersRemover;
- LOG_STATUS("\t" << dupeMembersRemover.getInitStatusMessage());
+ //LOG_STATUS("\t" << dupeMembersRemover.getInitStatusMessage());
map->visitRw(dupeMembersRemover);
- LOG_STATUS("\t" << dupeMembersRemover.getCompletedStatusMessage());
+ LOG_DEBUG(dupeMembersRemover.getCompletedStatusMessage());
// get rid of straggling nodes
SuperfluousNodeRemover orphanedNodeRemover;
- LOG_STATUS("\t" << orphanedNodeRemover.getInitStatusMessage());
+ //LOG_STATUS("\t" << orphanedNodeRemover.getInitStatusMessage());
orphanedNodeRemover.apply(map);
- LOG_STATUS("\t" << orphanedNodeRemover.getCompletedStatusMessage());
+ LOG_DEBUG(orphanedNodeRemover.getCompletedStatusMessage());
- // This will remove any relations that were already empty or became empty after we removed missing
- // members.
+ // This will remove any relations that were already empty or became empty after we removed
+ // duplicated members.
RemoveEmptyRelationsOp emptyRelationRemover;
- LOG_STATUS("\t" << emptyRelationRemover.getInitStatusMessage());
+ //LOG_STATUS("\t" << emptyRelationRemover.getInitStatusMessage());
emptyRelationRemover.apply(map);
- LOG_STATUS("\t" << emptyRelationRemover.getCompletedStatusMessage());
+ LOG_DEBUG(emptyRelationRemover.getCompletedStatusMessage());
+ // get out of orthographic
MapProjector::projectToWgs84(map);
}
-bool ChangesetReplacementCreator::_isNetworkConflate() const
-{
- return
- ConfigOptions().getMatchCreators().contains(
- QString::fromStdString(NetworkMatchCreator::className()));
-}
-
}