v0.2.48..v0.2.49 changeset ChangesetReplacementCreator.cpp
Garret Voltz edited this page Oct 2, 2019
·
1 revision
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 4fc65c6..f39e472 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
@@ -27,126 +27,397 @@
#include "ChangesetReplacementCreator.h"
// Hoot
-#include <hoot/core/util/GeometryUtils.h>
-#include <hoot/core/util/ConfigOptions.h>
-#include <hoot/core/util/IoUtils.h>
-#include <hoot/core/visitors/RemoveElementsVisitor.h>
#include <hoot/core/algorithms/alpha-shape/AlphaShapeGenerator.h>
+#include <hoot/core/algorithms/ReplacementSnappedWayJoiner.h>
+#include <hoot/core/algorithms/WayJoinerAdvanced.h>
+#include <hoot/core/algorithms/WayJoinerBasic.h>
+
#include <hoot/core/conflate/CookieCutter.h>
#include <hoot/core/conflate/UnifyingConflator.h>
-#include <hoot/core/ops/UnconnectedWaySnapper.h>
-#include <hoot/core/util/Factory.h>
-#include <hoot/core/algorithms/ReplacementSnappedWayJoiner.h>
-#include <hoot/core/ops/NamedOp.h>
-#include <hoot/core/visitors/RemoveUnknownVisitor.h>
-#include <hoot/core/ops/MapCropper.h>
-#include <hoot/core/io/OsmMapWriterFactory.h>
-#include <hoot/core/util/MapProjector.h>
-#include <hoot/core/ops/RecursiveSetTagValueOp.h>
+#include <hoot/core/conflate/network/NetworkMatchCreator.h>
+
+#include <hoot/core/criterion/ConflatableElementCriterion.h>
+#include <hoot/core/criterion/ElementTypeCriterion.h>
#include <hoot/core/criterion/InBoundsCriterion.h>
-#include <hoot/core/criterion/ChainCriterion.h>
+#include <hoot/core/criterion/LinearCriterion.h>
#include <hoot/core/criterion/NotCriterion.h>
-#include <hoot/core/criterion/ElementTypeCriterion.h>
-#include <hoot/core/ops/SuperfluousNodeRemover.h>
-#include <hoot/core/io/OsmMapReaderFactory.h>
-#include <hoot/core/util/Boundable.h>
-#include <hoot/core/io/OsmMapReader.h>
-#include <hoot/core/criterion/WayNodeCriterion.h>
-#include <hoot/core/ops/ElementIdToVersionMapper.h>
-#include <hoot/core/conflate/network/NetworkMatchCreator.h>
-#include <hoot/core/algorithms/WayJoinerAdvanced.h>
-#include <hoot/core/algorithms/WayJoinerBasic.h>
-#include <hoot/core/visitors/SetTagValueVisitor.h>
-#include <hoot/core/visitors/FilteredVisitor.h>
-#include <hoot/core/criterion/TagKeyCriterion.h>
-#include <hoot/core/visitors/RemoveElementsVisitor.h>
+#include <hoot/core/criterion/OrCriterion.h>
+#include <hoot/core/criterion/PointCriterion.h>
+#include <hoot/core/criterion/PolygonCriterion.h>
#include <hoot/core/criterion/TagCriterion.h>
+#include <hoot/core/criterion/TagKeyCriterion.h>
+#include <hoot/core/criterion/WayNodeCriterion.h>
+
+#include <hoot/core/elements/OsmUtils.h>
#include <hoot/core/io/OsmGeoJsonReader.h>
+#include <hoot/core/io/OsmMapReaderFactory.h>
+#include <hoot/core/io/OsmMapWriterFactory.h>
+
+#include <hoot/core/ops/ElementIdToVersionMapper.h>
+#include <hoot/core/ops/UnconnectedWaySnapper.h>
+
+#include <hoot/core/ops/MapCropper.h>
+#include <hoot/core/ops/NamedOp.h>
+#include <hoot/core/ops/PointsToPolysConverter.h>
+#include <hoot/core/ops/SuperfluousNodeRemover.h>
+#include <hoot/core/ops/RecursiveSetTagValueOp.h>
#include <hoot/core/ops/WayJoinerOp.h>
+
+#include <hoot/core/util/Boundable.h>
+#include <hoot/core/util/ConfigOptions.h>
+#include <hoot/core/util/Factory.h>
+#include <hoot/core/util/GeometryUtils.h>
+#include <hoot/core/util/IoUtils.h>
+#include <hoot/core/util/MapProjector.h>
+
#include <hoot/core/visitors/ApiTagTruncateVisitor.h>
-#include <hoot/core/visitors/ElementCountVisitor.h>
-#include <hoot/core/criterion/AttributeValueCriterion.h>
-#include <hoot/core/elements/OsmUtils.h>
+#include <hoot/core/visitors/FilteredVisitor.h>
+#include <hoot/core/visitors/RemoveElementsVisitor.h>
+#include <hoot/core/visitors/SetTagValueVisitor.h>
namespace hoot
{
ChangesetReplacementCreator::ChangesetReplacementCreator(const bool printStats,
- const QString osmApiDbUrl)
+ const QString osmApiDbUrl) :
+_fullReplacement(false),
+_lenientBounds(true),
+_chainReplacementFilters(false),
+_chainRetainmentFilters(false)
{
_changesetCreator.reset(new ChangesetCreator(printStats, osmApiDbUrl));
+ setGeometryFilters(QStringList());
+}
+
+void ChangesetReplacementCreator::setGeometryFilters(const QStringList& filterClassNames)
+{
+ LOG_VARD(filterClassNames);
+ if (!filterClassNames.isEmpty())
+ {
+ _geometryTypeFilters.clear();
+ _linearFilterClassNames.clear();
+
+ for (int i = 0; i < filterClassNames.size(); i++)
+ {
+ const QString filterClassName = filterClassNames.at(i);
+ LOG_VARD(filterClassName);
+
+ // Fail if the filter doesn't map to a geometry type.
+ std::shared_ptr<GeometryTypeCriterion> filter =
+ std::dynamic_pointer_cast<GeometryTypeCriterion>(
+ std::shared_ptr<ElementCriterion>(
+ Factory::getInstance().constructObject<ElementCriterion>(filterClassName)));
+ if (!filter)
+ {
+ throw IllegalArgumentException(
+ "Invalid feature geometry type filter: " + filterClassName +
+ ". Filter must be a GeometryTypeCriterion.");
+ }
+
+ ElementCriterionPtr currentFilter = _geometryTypeFilters[filter->getGeometryType()];
+ if (!currentFilter)
+ {
+ _geometryTypeFilters[filter->getGeometryType()] = filter;
+ }
+ else
+ {
+ _geometryTypeFilters[filter->getGeometryType()] =
+ std::shared_ptr<OrCriterion>(new OrCriterion(currentFilter, filter));
+ }
+
+ if (filter->getGeometryType() == GeometryTypeCriterion::GeometryType::Line)
+ {
+ _linearFilterClassNames.append(filterClassName);
+ }
+ }
+ }
+
+ LOG_VARD(_geometryTypeFilters.size());
+ if (_geometryTypeFilters.isEmpty())
+ {
+ _geometryTypeFilters = _getDefaultGeometryFilters();
+ _linearFilterClassNames =
+ ConflatableElementCriterion::getCriterionClassNamesByType(
+ GeometryTypeCriterion::GeometryType::Line);
+ }
+
+ LOG_VARD(_geometryTypeFilters.size());
+ LOG_VARD(_linearFilterClassNames);
+}
+
+void ChangesetReplacementCreator::_setInputFilter(
+ std::shared_ptr<ChainCriterion>& inputFilter, const QStringList& filterClassNames,
+ const bool chainFilters)
+{
+ LOG_VARD(filterClassNames.size());
+ if (!filterClassNames.isEmpty())
+ {
+ LOG_VARD(chainFilters);
+ if (!chainFilters)
+ {
+ inputFilter.reset(new OrCriterion());
+ }
+ else
+ {
+ inputFilter.reset(new ChainCriterion());
+ }
+
+ for (int i = 0; i < filterClassNames.size(); i++)
+ {
+ const QString filterClassName = filterClassNames.at(i);
+ LOG_VARD(filterClassName);
+
+ ElementCriterionPtr crit;
+ try
+ {
+ crit.reset(Factory::getInstance().constructObject<ElementCriterion>(filterClassName));
+ }
+ catch (const boost::bad_any_cast&)
+ {
+ }
+ if (!crit)
+ {
+ throw IllegalArgumentException(
+ "Invalid additional input filter: " + filterClassName +
+ ". Filter must be a ElementCriterion.");
+ }
+
+ // Fail if the filter maps to a geometry type.
+ std::shared_ptr<GeometryTypeCriterion> geometryTypeFilter;
+ try
+ {
+ geometryTypeFilter = std::dynamic_pointer_cast<GeometryTypeCriterion>(crit);
+ }
+ catch (const boost::bad_any_cast&)
+ {
+ }
+ if (geometryTypeFilter)
+ {
+ throw IllegalArgumentException(
+ "Invalid additional input filter: " + filterClassName +
+ ". May not be a GeometryTypeCriterion.");
+ }
+
+ inputFilter->addCriterion(crit);
+ }
+
+ LOG_VARD(inputFilter->toString());
+ }
+}
+
+void ChangesetReplacementCreator::setReplacementFilters(const QStringList& filterClassNames)
+{
+ LOG_VARD(filterClassNames.size());
+ if (filterClassNames.size() > 0)
+ {
+ LOG_DEBUG("Creating replacement filter...");
+ _setInputFilter(_replacementFilter, filterClassNames, _chainReplacementFilters);
+ }
+}
+
+void ChangesetReplacementCreator::setRetainmentFilters(const QStringList& filterClassNames)
+{
+ LOG_VARD(filterClassNames.size());
+ if (filterClassNames.size() > 0)
+ {
+ LOG_DEBUG("Creating retainment filter...");
+ _setInputFilter(_retainmentFilter, filterClassNames, _chainRetainmentFilters);
+ }
+}
+
+void ChangesetReplacementCreator::_setInputFilterOptions(Settings& opts,
+ const QStringList& optionKvps)
+{
+ LOG_VARD(optionKvps.size());
+ opts = conf();
+ LOG_DEBUG("Opts size before adding custom opts: " << opts.size());
+ for (int i = 0; i < optionKvps.size(); i++)
+ {
+ const QString kvp = optionKvps.at(i);
+ // split on the first occurrence of '=' since the opt value itself could have an '=' in it
+ const int firstEqualOccurrence = kvp.indexOf("=");
+ if (firstEqualOccurrence == -1)
+ {
+ throw IllegalArgumentException("Invalid filter configuration option: " + kvp);
+ }
+ const QString key = kvp.mid(0, firstEqualOccurrence).trimmed().remove("\"").remove("'");
+ LOG_VARD(key);
+ const QString val = kvp.mid(firstEqualOccurrence + 2).trimmed().remove("\"").remove("'");
+ LOG_VARD(val);
+ opts.set(key, val);
+ }
+ LOG_DEBUG("Opts size after adding custom opts: " << opts.size());
+}
+
+void ChangesetReplacementCreator::setReplacementFilterOptions(const QStringList& optionKvps)
+{
+ LOG_DEBUG("Creating replacement filter options...");
+ _setInputFilterOptions(_replacementFilterOptions, optionKvps);
+}
+
+void ChangesetReplacementCreator::setRetainmentFilterOptions(const QStringList& optionKvps)
+{
+ LOG_DEBUG("Creating retainment filter options...");
+ _setInputFilterOptions(_retainmentFilterOptions, optionKvps);
}
void ChangesetReplacementCreator::create(
const QString& input1, const QString& input2, const geos::geom::Envelope& bounds,
- const QString& featureTypeFilterClassName, const bool lenientBounds, const QString& output)
+ const QString& output)
{
+ LOG_VARD(_chainReplacementFilters);
+ LOG_VARD(_lenientBounds);
+ LOG_VARD(_fullReplacement);
+
// INPUT VALIDATION AND SETUP
_validateInputs(input1, input2);
- std::shared_ptr<ConflatableElementCriterion> featureFilter =
- _validateFilter(featureTypeFilterClassName);
- const bool isLinearCrit =
- featureFilter->getGeometryType() == ConflatableElementCriterion::ConflatableGeometryType::Line;
const QString boundsStr = GeometryUtils::envelopeToConfigString(bounds);
- _parseConfigOpts(lenientBounds, featureFilter, boundsStr);
+ _setGlobalOpts(boundsStr);
+ // 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);
+ // 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 =
+ _getCombinedFilters(_replacementFilter);
const int maxFilePrintLength = ConfigOptions().getProgressVarPrintLengthMax();
QString lenientStr = "Bounds calculation is ";
- if (! lenientBounds)
+ if (!_lenientBounds)
{
lenientStr += "not ";
}
lenientStr += "lenient.";
LOG_INFO(
"Deriving replacement output changeset: ..." << output.right(maxFilePrintLength) <<
- " from inputs: ..." << input1.right(maxFilePrintLength) + " and ..." <<
- input2.right(maxFilePrintLength) << ", with filter: " << featureTypeFilterClassName <<
- ", at bounds: " << boundsStr << ". " << lenientStr);
+ " from inputs: ..." << input1.right(maxFilePrintLength) << " and ..." <<
+ input2.right(maxFilePrintLength) << "" << ", at bounds: " << boundsStr << ". " << lenientStr);
+
+ // CHANGESET CALCULATION
+
+ // Since data with different geometry types require different settings, we'll calculate a separate
+ // pair of before/after maps for each geometry type.
+
+ QList<OsmMapPtr> refMaps;
+ QList<OsmMapPtr> conflatedMaps;
+ int passCtr = 1;
+ for (QMap<GeometryTypeCriterion::GeometryType, ElementCriterionPtr>::const_iterator itr =
+ refFilters.begin(); itr != refFilters.end(); ++itr)
+ {
+ LOG_DEBUG(
+ "Preparing maps for changeset derivation given geometry type: "<<
+ GeometryTypeCriterion::typeToString(itr.key()) << ". Pass: " << passCtr << " / " <<
+ refFilters.size() << "...");
+
+ OsmMapPtr refMap;
+ OsmMapPtr conflatedMap;
+ QStringList linearFilterClassNames;
+ LOG_VARD(itr.value().get());
+ if (itr.key() == GeometryTypeCriterion::GeometryType::Line)
+ {
+ linearFilterClassNames = _linearFilterClassNames;
+ }
+ _getMapsForGeometryType(
+ refMap, conflatedMap, input1, input2, boundsStr, itr.value(), secFilters[itr.key()],
+ itr.key(), linearFilterClassNames);
+
+ LOG_VARD(refMap.get());
+ LOG_VARD(conflatedMap.get());
+ if (refMap && conflatedMap && conflatedMap->size() > 0)
+ {
+ LOG_VARD(refMap->size());
+ LOG_VARD(conflatedMap.get());
+ refMaps.append(refMap);
+ conflatedMaps.append(conflatedMap);
+ }
+
+ passCtr++;
+ }
+
+ LOG_VARD(refMaps.size());
+ LOG_VARD(conflatedMaps.size());
+ if (refMaps.size() == 0 || conflatedMaps.size() == 0)
+ {
+ LOG_DEBUG("No features remain after filtering. Skipping changeset generation...");
+ return;
+ }
+ assert(refMaps.size() == conflatedMaps.size());
+
+ // CHANGESET GENERATION
+
+ // Derive a changeset between the ref and conflated maps that replaces ref features with
+ // secondary features within the bounds and write it out.
+
+ _changesetCreator->create(refMaps, conflatedMaps, output);
+
+ LOG_INFO("Derived replacement changeset: " << output.right(maxFilePrintLength));
+}
+
+void ChangesetReplacementCreator::_getMapsForGeometryType(
+ OsmMapPtr& refMap, OsmMapPtr& conflatedMap, const QString& input1, const QString& input2,
+ const QString& boundsStr, const ElementCriterionPtr& refFeatureFilter,
+ const ElementCriterionPtr& secFeatureFilter,
+ const GeometryTypeCriterion::GeometryType& geometryType,
+ const QStringList& linearFilterClassNames)
+{
+ LOG_VARD(linearFilterClassNames);
+ LOG_VARD(secFeatureFilter);
+
+ // INPUT VALIDATION AND SETUP
+
+ _parseConfigOpts(_lenientBounds, geometryType);
// DATA LOAD AND INITIAL PREP
// Load the ref dataset and crop to the specified aoi.
- OsmMapPtr refMap = _loadRefMap(input1);
+ refMap = _loadRefMap(input1);
// We want to alert the user to the fact their ref versions *could* be being populated incorectly
// to avoid difficulties during changeset application at the end. Its likely if they are
// incorrect at this point the changeset derivation will fail at the end anyway, but let's warn
// now to give the chance to back out earlier.
- const int numberOfRefElementsWithVersionLessThan1 = _versionLessThanOneCount(refMap);
- if (numberOfRefElementsWithVersionLessThan1 > 0)
- {
- LOG_WARN(
- StringUtils::formatLargeNumber(numberOfRefElementsWithVersionLessThan1) << " features in " <<
- "the reference map have a version less than one. This could lead to difficulties when " <<
- "applying the resulting changeset back to an authoritative data store. Are the versions " <<
- "on the features being populated correctly?")
- }
+ OsmUtils::checkVersionLessThanOneCountAndLogWarning(refMap);
// Keep a mapping of the original ref element ids to versions, as we'll need the original
// versions later.
const QMap<ElementId, long> refIdToVersionMappings = _getIdToVersionMappings(refMap);
- if (lenientBounds && isLinearCrit)
+ const bool isLinearCrit = !linearFilterClassNames.isEmpty();
+ LOG_VARD(isLinearCrit);
+ if (_lenientBounds && isLinearCrit)
{
// 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.
_addChangesetDeleteExclusionTags(refMap);
}
- // Prune down the elements to just the feature types specified by the filter.
+ // Prune the ref dataset down to just the geometry types specified by the filter, so we don't end
+ // up modifying anything else.
- _filterFeatures(refMap, featureFilter, "ref-after-type-pruning");
+ _filterFeatures(refMap, refFeatureFilter, conf(), "ref-after-type-pruning");
// Load the sec dataset and crop to the specified aoi.
OsmMapPtr secMap = _loadSecMap(input2);
- // Prune down the elements to just the feature types specified by the filter.
+ // Prune the sec dataset down to just the feature types specified by the filter, so we don't end
+ // up modifying anything else.
+
+ _filterFeatures(secMap, secFeatureFilter, _replacementFilterOptions, "sec-after-type-pruning");
- _filterFeatures(secMap, featureFilter, "sec-after-type-pruning");
+ LOG_VARD(refMap->getElementCount());
+ LOG_VARD(secMap->getElementCount());
+ // If we're empty here, then the filtering must have removed everything...no changeset to
+ // calculate.
+ if (refMap->getElementCount() == 0 && secMap->getElementCount() == 0)
+ {
+ LOG_DEBUG("Both input maps empty after filtering. Skipping changeset generation...");
+ return;
+ }
// COOKIE CUT
@@ -161,18 +432,19 @@ void ChangesetReplacementCreator::create(
// situation again, we can go back in the history to resurrect the use of the ElementIdRemapper
// for relations here, which has since been removed from the codebase.
- // Combine the cookie cut map back with the secondary map, so we can conflate it with the ref map.
+ // Combine the cookie cut ref map back with the secondary map, so we can conflate the two
+ // together.
_combineMaps(cookieCutRefMap, secMap, false, "combined-before-conflation");
secMap.reset();
// CONFLATE
- // Conflate the cookie cut ref map with the cropped sec map.
+ // Conflate the cookie cut ref map with the sec map.
- OsmMapPtr conflatedMap = cookieCutRefMap;
+ conflatedMap = cookieCutRefMap;
// TODO: do something with reviews - #3361
- _conflate(conflatedMap, lenientBounds);
+ _conflate(conflatedMap, _lenientBounds);
if (isLinearCrit)
{
@@ -180,9 +452,19 @@ void ChangesetReplacementCreator::create(
// ref features may have been cut along the bounds. We're being lenient here by snapping
// secondary to reference *and* allowing conflated data to be snapped to either dataset.
- _snapUnconnectedWays(
- conflatedMap, "Input2;Conflated", "Input1;Conflated", featureTypeFilterClassName, false,
- "conflated-snapped-sec-to-ref-1");
+ // We only want to snap ways of like types together, so we'll loop through each applicable
+ // linear type and snap them separately.
+
+ QStringList snapWayStatuses("Input2");
+ snapWayStatuses.append("Conflated");
+ QStringList snapToWayStatuses("Input1");
+ snapToWayStatuses.append("Conflated");
+ for (int i = 0; i < linearFilterClassNames.size(); i++)
+ {
+ _snapUnconnectedWays(
+ conflatedMap, snapWayStatuses, snapToWayStatuses, linearFilterClassNames.at(i), false,
+ "conflated-snapped-sec-to-ref-1");
+ }
// After snapping, perform joining to prevent unnecessary create/delete statements for the ref
// data in the resulting changeset and generate modify statements instead.
@@ -194,7 +476,7 @@ void ChangesetReplacementCreator::create(
// PRE-CHANGESET DERIVATION DATA PREP
OsmMapPtr immediatelyConnectedOutOfBoundsWays;
- if (lenientBounds && isLinearCrit)
+ if (_lenientBounds && isLinearCrit)
{
// 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
@@ -203,26 +485,40 @@ void ChangesetReplacementCreator::create(
immediatelyConnectedOutOfBoundsWays = _getImmediatelyConnectedOutOfBoundsWays(refMap);
}
- // Crop the ref and conflated maps appropriately for changeset derivation.
+ // Crop the original ref and conflated maps appropriately for changeset derivation.
+
+ const geos::geom::Envelope bounds = GeometryUtils::envelopeFromConfigString(boundsStr);
_cropMapForChangesetDerivation(
- refMap, bounds, _changesetRefKeepEntireCrossingBounds, _changesetRefKeepOnlyInsideBounds,
- isLinearCrit, "ref-cropped-for-changeset");
+ refMap, bounds, _boundsOpts.changesetRefKeepEntireCrossingBounds,
+ _boundsOpts.changesetRefKeepOnlyInsideBounds, isLinearCrit, "ref-cropped-for-changeset");
_cropMapForChangesetDerivation(
- conflatedMap, bounds, _changesetSecKeepEntireCrossingBounds, _changesetSecKeepOnlyInsideBounds,
- isLinearCrit, "sec-cropped-for-changeset");
- if (lenientBounds && isLinearCrit)
+ conflatedMap, bounds, _boundsOpts.changesetSecKeepEntireCrossingBounds,
+ _boundsOpts.changesetSecKeepOnlyInsideBounds, isLinearCrit, "sec-cropped-for-changeset");
+ LOG_VARD(_lenientBounds);
+ LOG_VARD(isLinearCrit);
+ if (_lenientBounds && isLinearCrit)
{
// The non-strict way replacement workflow benefits from a second snapping run right before
// changeset derivation due to there being ways connected to replacement ways that fall
// completely outside of the bounds. However, joining after this snapping caused changeset
// errors with some datasets and hasn't seem to be needed for now...so skipping it. Note that
// we're being as lenient as possible with the snapping here, allowing basically anything to
- // join to anything else...could end up causing problems...but we'll go with it for now.
-
- _snapUnconnectedWays(
- conflatedMap, "Input2;Conflated;Input1", "Input1;Conflated;Input2",
- featureTypeFilterClassName, false, "conflated-snapped-sec-to-ref-2");
+ // join to anything else, which could end up causing problems...we'll go with it for now.
+
+ QStringList snapWayStatuses("Input2");
+ snapWayStatuses.append("Conflated");
+ snapWayStatuses.append("Input1");
+ QStringList snapToWayStatuses("Input1");
+ snapToWayStatuses.append("Conflated");
+ snapToWayStatuses.append("Input2");
+ LOG_VARD(linearFilterClassNames);
+ for (int i = 0; i < linearFilterClassNames.size(); i++)
+ {
+ _snapUnconnectedWays(
+ conflatedMap, snapWayStatuses, snapToWayStatuses, linearFilterClassNames.at(i), false,
+ "conflated-snapped-sec-to-ref-2");
+ }
// Combine the conflated map with the immediately connected out of bounds ways.
@@ -232,9 +528,13 @@ void ChangesetReplacementCreator::create(
// Snap only 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.
- _snapUnconnectedWays(
- conflatedMap, "Input1", "Input1", featureTypeFilterClassName, true,
- "conflated-snapped-immediately-connected-out-of-bounds");
+ LOG_VARD(linearFilterClassNames);
+ for (int i = 0; i < linearFilterClassNames.size(); i++)
+ {
+ _snapUnconnectedWays(
+ conflatedMap, QStringList("Input1"), QStringList("Input1"), linearFilterClassNames.at(i),
+ true, "conflated-snapped-immediately-connected-out-of-bounds");
+ }
// Remove any ways that weren't snapped.
@@ -256,12 +556,8 @@ void ChangesetReplacementCreator::create(
_excludeFeaturesFromChangesetDeletion(refMap, boundsStr);
}
- // CHANGESET DERIVATION
-
- // Derive a changeset between the ref and conflated maps that completely replaces ref features
- // with secondary features within the bounds and write it out.
-
- _changesetCreator->create(refMap, conflatedMap, output);
+ LOG_VARD(refMap->getElementCount());
+ LOG_VARD(conflatedMap->getElementCount());
}
void ChangesetReplacementCreator::_validateInputs(const QString& input1, const QString& input2)
@@ -271,12 +567,14 @@ void ChangesetReplacementCreator::_validateInputs(const QString& input1, const Q
std::dynamic_pointer_cast<Boundable>(OsmMapReaderFactory::createReader(input1));
if (!boundable)
{
- throw IllegalArgumentException("Reader for " + input1 + " must implement Boundable.");
+ throw IllegalArgumentException(
+ "Reader for " + input1 + " must implement Boundable for replacement changeset derivation.");
}
boundable = std::dynamic_pointer_cast<Boundable>(OsmMapReaderFactory::createReader(input2));
if (!boundable)
{
- throw IllegalArgumentException("Reader for " + input2 + " must implement Boundable.");
+ throw IllegalArgumentException(
+ "Reader for " + input2 + " must implement Boundable for replacement changeset derivation.");
}
// Fail for GeoJSON - GeoJSON coming from Overpass does not have way nodes, so their versions
@@ -285,23 +583,59 @@ void ChangesetReplacementCreator::_validateInputs(const QString& input1, const Q
OsmGeoJsonReader geoJsonReader;
if (geoJsonReader.isSupported(input1) || geoJsonReader.isSupported(input2))
{
- throw IllegalArgumentException("GeoJSON inputs are not supported.");
+ throw IllegalArgumentException(
+ "GeoJSON inputs are not supported by replacement changeset derivation.");
+ }
+
+ if (_fullReplacement && _retainmentFilter)
+ {
+ throw IllegalArgumentException(
+ "Both full reference data replacement and a reference data retainment filter may not "
+ "be specified for replacement changeset derivation.");
+ }
+
+ if (ConfigOptions().getConvertOps().size())
+ {
+ throw IllegalArgumentException(
+ "Replacement changeset derivation does not support convert operations.");
}
}
-std::shared_ptr<ConflatableElementCriterion> ChangesetReplacementCreator::_validateFilter(
- const QString& featureTypeFilterClassName)
+QMap<GeometryTypeCriterion::GeometryType, ElementCriterionPtr>
+ ChangesetReplacementCreator::_getDefaultGeometryFilters() const
{
- // Fail if a filter with an unconflatable feature type was specified.
- std::shared_ptr<ConflatableElementCriterion> featureFilter =
- std::dynamic_pointer_cast<ConflatableElementCriterion>(
- std::shared_ptr<ElementCriterion>(
- Factory::getInstance().constructObject<ElementCriterion>(featureTypeFilterClassName)));
- if (!featureFilter)
+ QMap<GeometryTypeCriterion::GeometryType, ElementCriterionPtr> featureFilters;
+ featureFilters[GeometryTypeCriterion::GeometryType::Point] =
+ std::shared_ptr<ElementCriterion>(new PointCriterion());
+ featureFilters[GeometryTypeCriterion::GeometryType::Line] =
+ std::shared_ptr<ElementCriterion>(new LinearCriterion());
+ featureFilters[GeometryTypeCriterion::GeometryType::Polygon] =
+ std::shared_ptr<ElementCriterion>(new PolygonCriterion());
+ return featureFilters;
+}
+
+QMap<GeometryTypeCriterion::GeometryType, ElementCriterionPtr>
+ ChangesetReplacementCreator::_getCombinedFilters(
+ std::shared_ptr<ChainCriterion> nonGeometryFilter)
+{
+ QMap<GeometryTypeCriterion::GeometryType, ElementCriterionPtr> combinedFilters;
+ LOG_VARD(nonGeometryFilter.get());
+ if (nonGeometryFilter)
{
- throw IllegalArgumentException("Invalid feature type filter: " + featureTypeFilterClassName);
+ for (QMap<GeometryTypeCriterion::GeometryType, ElementCriterionPtr>::const_iterator itr =
+ _geometryTypeFilters.begin(); itr != _geometryTypeFilters.end(); ++itr)
+ {
+ combinedFilters[itr.key()] =
+ std::shared_ptr<ChainCriterion>(new ChainCriterion(itr.value(), nonGeometryFilter));
+ LOG_DEBUG("New combined filter: " << combinedFilters[itr.key()]->toString());
+ }
}
- return featureFilter;
+ else
+ {
+ combinedFilters = _geometryTypeFilters;
+ }
+ LOG_VARD(combinedFilters.size());
+ return combinedFilters;
}
OsmMapPtr ChangesetReplacementCreator::_loadRefMap(const QString& input)
@@ -310,38 +644,27 @@ OsmMapPtr ChangesetReplacementCreator::_loadRefMap(const QString& input)
conf().set(
ConfigOptions::getConvertBoundingBoxKeepEntireFeaturesCrossingBoundsKey(),
- _loadRefKeepEntireCrossingBounds);
+ _boundsOpts.loadRefKeepEntireCrossingBounds);
conf().set(
ConfigOptions::getConvertBoundingBoxKeepOnlyFeaturesInsideBoundsKey(),
- _loadRefKeepOnlyInsideBounds);
+ _boundsOpts.loadRefKeepOnlyInsideBounds);
conf().set(
ConfigOptions::getConvertBoundingBoxKeepImmediatelyConnectedWaysOutsideBoundsKey(),
- _loadRefKeepImmediateConnectedWaysOutsideBounds);
+ _boundsOpts.loadRefKeepImmediateConnectedWaysOutsideBounds);
OsmMapPtr refMap(new OsmMap());
refMap->setName("ref");
IoUtils::loadMap(refMap, input, true, Status::Unknown1);
- LOG_VARD(MapProjector::toWkt(refMap->getProjection()));
+ LOG_VART(MapProjector::toWkt(refMap->getProjection()));
OsmMapWriterFactory::writeDebugMap(refMap, "ref-after-cropped-load");
return refMap;
}
-int ChangesetReplacementCreator::_versionLessThanOneCount(const OsmMapPtr& map) const
-{
- std::shared_ptr<AttributeValueCriterion> attrCrit(
- new AttributeValueCriterion(
- ElementAttributeType(ElementAttributeType::Version), 1, NumericComparisonType::LessThan));
- return
- (int)FilteredVisitor::getStat(
- attrCrit, std::shared_ptr<ElementCountVisitor>(new ElementCountVisitor()), map);
-}
-
QMap<ElementId, long> ChangesetReplacementCreator::_getIdToVersionMappings(
const OsmMapPtr& map) const
{
- LOG_DEBUG("Recording ID to version mappings for: " << map->getName() << "...");
ElementIdToVersionMapper idToVersionMapper;
LOG_DEBUG(idToVersionMapper.getInitStatusMessage());
idToVersionMapper.apply(map);
@@ -391,10 +714,10 @@ OsmMapPtr ChangesetReplacementCreator::_loadSecMap(const QString& input)
conf().set(
ConfigOptions::getConvertBoundingBoxKeepEntireFeaturesCrossingBoundsKey(),
- _loadSecKeepEntireCrossingBounds);
+ _boundsOpts.loadSecKeepEntireCrossingBounds);
conf().set(
ConfigOptions::getConvertBoundingBoxKeepOnlyFeaturesInsideBoundsKey(),
- _loadSecKeepOnlyInsideBounds);
+ _boundsOpts.loadSecKeepOnlyInsideBounds);
conf().set(
ConfigOptions::getConvertBoundingBoxKeepImmediatelyConnectedWaysOutsideBoundsKey(), false);
@@ -402,52 +725,124 @@ OsmMapPtr ChangesetReplacementCreator::_loadSecMap(const QString& input)
secMap->setName("sec");
IoUtils::loadMap(secMap, input, false, Status::Unknown2);
- LOG_VARD(MapProjector::toWkt(secMap->getProjection()));
+ LOG_VART(MapProjector::toWkt(secMap->getProjection()));
OsmMapWriterFactory::writeDebugMap(secMap, "sec-after-cropped-load");
return secMap;
}
void ChangesetReplacementCreator::_filterFeatures(
- OsmMapPtr& map, const std::shared_ptr<ConflatableElementCriterion>& featureFilter,
+ OsmMapPtr& map, const ElementCriterionPtr& featureFilter, const Settings& config,
const QString& debugFileName)
{
- LOG_DEBUG("Filtering features for: " << map->getName() << " based on input filter...");
+ LOG_DEBUG(
+ "Filtering features for: " << map->getName() << " based on input filter: " +
+ featureFilter->toString() << "...");
+
RemoveElementsVisitor elementPruner(true);
+ // The criteria must be added before the config or map is set. We may want to change
+ // MultipleCriterionConsumerVisitor and RemoveElementsVisitor to make this behavior less brittle.
elementPruner.addCriterion(featureFilter);
+ elementPruner.setConfiguration(config);
+ elementPruner.setOsmMap(map.get());
elementPruner.setRecursive(true);
LOG_DEBUG(elementPruner.getInitStatusMessage());
map->visitRw(elementPruner);
LOG_DEBUG(elementPruner.getCompletedStatusMessage());
- LOG_VARD(MapProjector::toWkt(map->getProjection()));
+
+ LOG_VART(MapProjector::toWkt(map->getProjection()));
OsmMapWriterFactory::writeDebugMap(map, debugFileName);
}
OsmMapPtr ChangesetReplacementCreator::_getCookieCutMap(OsmMapPtr doughMap, OsmMapPtr cutterMap)
{
- LOG_VARD(MapProjector::toWkt(doughMap->getProjection()));
- LOG_VARD(MapProjector::toWkt(cutterMap->getProjection()));
+ // TODO: could use some refactoring here after the addition of _fullReplacement
- // Generate a cutter shape based on the cropped secondary map.
+ LOG_VARD(doughMap->getElementCount());
+ LOG_VART(MapProjector::toWkt(doughMap->getProjection()));
+ OsmMapWriterFactory::writeDebugMap(doughMap, "dough-map");
+ LOG_VARD(cutterMap->getElementCount());
+ LOG_VART(MapProjector::toWkt(cutterMap->getProjection()));
- LOG_DEBUG("Generating cutter shape map from: " << cutterMap->getName() << "...");
- OsmMapPtr cutterShapeOutlineMap = AlphaShapeGenerator(1000.0, 0.0).generateMap(cutterMap);
- // not exactly sure yet why this needs to be done
+ OsmMapPtr cookieCutMap(new OsmMap(doughMap));
+ cookieCutMap->setName("cookie-cut");
+ LOG_VART(MapProjector::toWkt(cookieCutMap->getProjection()));
+ LOG_DEBUG("Preparing to cookie cut: " << cookieCutMap->getName() << "...");
+
+ OsmMapPtr cutterMapToUse;
+ LOG_VARD(cutterMap->getElementCount());
+ ConfigOptions opts(conf());
+ LOG_VARD(OsmUtils::mapIsPointsOnly(cutterMap));
+ double cookieCutterAlpha = opts.getCookieCutterAlpha();
+ double cookieCutterAlphaShapeBuffer = opts.getCookieCutterAlphaShapeBuffer();
+ LOG_VARD(_fullReplacement);
+ if (_fullReplacement)
+ {
+ // Generate a cutter shape based on the ref map, which will cause all the ref data to be
+ // replaced.
+ cutterMapToUse = doughMap;
+ cookieCutterAlphaShapeBuffer = 10.0;
+ }
+ else if (cutterMap->getElementCount() < 3 && OsmUtils::mapIsPointsOnly(cutterMap))
+ {
+ // Generate a cutter shape based on a transformation of the cropped secondary map.
+
+ // 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 I 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.
+
+ cutterMapToUse.reset(new OsmMap(cutterMap));
+ PointsToPolysConverter pointConverter;
+ LOG_DEBUG(pointConverter.getInitStatusMessage());
+ pointConverter.apply(cutterMapToUse);
+ LOG_DEBUG(pointConverter.getCompletedStatusMessage());
+ MapProjector::projectToWgs84(cutterMapToUse);
+ }
+ else
+ {
+ // Generate a cutter shape based on the cropped secondary map.
+ cutterMapToUse = cutterMap;
+ }
+ LOG_VARD(cutterMapToUse->getElementCount());
+ OsmMapWriterFactory::writeDebugMap(cutterMapToUse, "cutter-map");
+
+ LOG_DEBUG("Generating cutter shape map from: " << cutterMapToUse->getName() << "...");
+
+ OsmMapPtr cutterShapeOutlineMap;
+ try
+ {
+ cutterShapeOutlineMap =
+ AlphaShapeGenerator(cookieCutterAlpha, cookieCutterAlphaShapeBuffer)
+ .generateMap(cutterMapToUse);
+ }
+ catch (const HootException& e)
+ {
+ if (e.getWhat().contains("Alpha Shape area is zero"))
+ {
+ LOG_ERROR(
+ "No cut shape generated from secondary data. Is your secondary data empty or have you " <<
+ "filtered it to be empty?");
+ }
+ throw e;
+ }
+
+ // not exactly sure yet why this projection needs to be done
MapProjector::projectToWgs84(cutterShapeOutlineMap);
- LOG_VARD(MapProjector::toWkt(cutterShapeOutlineMap->getProjection()));
+ LOG_VART(MapProjector::toWkt(cutterShapeOutlineMap->getProjection()));
OsmMapWriterFactory::writeDebugMap(cutterShapeOutlineMap, "cutter-shape");
// Cookie cut the shape of the cutter shape map out of the cropped ref map.
+ LOG_DEBUG("Cookie cutting cutter shape out of: " << cookieCutMap->getName() << "...");
- LOG_DEBUG("Cookie cutting cutter shape out of: " << doughMap->getName() << "...");
- OsmMapPtr cookieCutMap(new OsmMap(doughMap));
- //OsmMapPtr cookieCutMap(new OsmMap(doughMap, MapProjector::createWgs84Projection()));
- LOG_VARD(MapProjector::toWkt(cookieCutMap->getProjection()));
- cookieCutMap->setName("cookie-cut");
- CookieCutter(false, 0.0, _cookieCutKeepEntireCrossingBounds, _cookieCutKeepOnlyInsideBounds)
+ CookieCutter(
+ false, 0.0, _boundsOpts.cookieCutKeepEntireCrossingBounds,
+ _boundsOpts.cookieCutKeepOnlyInsideBounds)
.cut(cutterShapeOutlineMap, cookieCutMap);
MapProjector::projectToWgs84(cookieCutMap); // not exactly sure yet why this needs to be done
- LOG_VARD(MapProjector::toWkt(cookieCutMap->getProjection()));
+ LOG_VARD(cookieCutMap->getElementCount());
+ MapProjector::projectToWgs84(doughMap);
+ LOG_VARD(doughMap->getElementCount());
+ LOG_VART(MapProjector::toWkt(cookieCutMap->getProjection()));
OsmMapWriterFactory::writeDebugMap(cookieCutMap, "cookie-cut");
return cookieCutMap;
@@ -465,7 +860,7 @@ void ChangesetReplacementCreator::_combineMaps(OsmMapPtr& map1, OsmMapPtr& map2,
MapProjector::projectToWgs84(map2); // not exactly sure yet why this needs to be done
map1->append(map2, throwOutDupes);
- LOG_VARD(MapProjector::toWkt(map1->getProjection()));
+ LOG_VART(MapProjector::toWkt(map1->getProjection()));
OsmMapWriterFactory::writeDebugMap(map1, debugFileName);
}
@@ -494,35 +889,36 @@ void ChangesetReplacementCreator::_conflate(OsmMapPtr& map, const bool lenientBo
NamedOp postOps(ConfigOptions().getConflatePostOps());
postOps.apply(map);
MapProjector::projectToWgs84(map); // conflation works in planar
- LOG_VARD(MapProjector::toWkt(map->getProjection()));
+ LOG_VART(MapProjector::toWkt(map->getProjection()));
OsmMapWriterFactory::writeDebugMap(map, "conflated");
}
-void ChangesetReplacementCreator::_snapUnconnectedWays(OsmMapPtr& map, const QString& snapWayStatus,
- const QString& snapToWayStatus,
- const QString& featureTypeFilterClassName,
- const bool markSnappedWays,
- const QString& debugFileName)
+void ChangesetReplacementCreator::_snapUnconnectedWays(
+ OsmMapPtr& map, const QStringList& snapWayStatuses, const QStringList& snapToWayStatuses,
+ const QString& typeCriterionClassName, const bool markSnappedWays, const QString& debugFileName)
{
- LOG_DEBUG("Snapping ways for map: " << map->getName() <<" ...");
+ LOG_DEBUG(
+ "Snapping ways for map: " << map->getName() << ", with filter type: " <<
+ typeCriterionClassName << ", snap way statuses: " << snapWayStatuses <<
+ ", snap to way statuses: " << snapToWayStatuses << " ...");
UnconnectedWaySnapper lineSnapper;
lineSnapper.setConfiguration(conf());
// override some of the default config
- lineSnapper.setSnapToWayStatus(snapToWayStatus);
- lineSnapper.setSnapWayStatus(snapWayStatus);
+ lineSnapper.setSnapToWayStatuses(snapToWayStatuses);
+ lineSnapper.setSnapWayStatuses(snapWayStatuses);
lineSnapper.setMarkSnappedWays(markSnappedWays);
- // TODO: hack - need a way to derive the way node crit from the input feature filter crit
+ // TODO: Do we need a way to derive the way node crit from the input feature filter crit?
lineSnapper.setWayNodeToSnapToCriterionClassName(
QString::fromStdString(WayNodeCriterion::className()));
- lineSnapper.setWayToSnapCriterionClassName(featureTypeFilterClassName);
- lineSnapper.setWayToSnapToCriterionClassName(featureTypeFilterClassName);
+ lineSnapper.setWayToSnapCriterionClassName(typeCriterionClassName);
+ lineSnapper.setWayToSnapToCriterionClassName(typeCriterionClassName);
LOG_DEBUG(lineSnapper.getInitStatusMessage());
lineSnapper.apply(map);
LOG_DEBUG(lineSnapper.getCompletedStatusMessage());
MapProjector::projectToWgs84(map); // snapping works in planar
- LOG_VARD(MapProjector::toWkt(map->getProjection()));
+ LOG_VART(MapProjector::toWkt(map->getProjection()));
OsmMapWriterFactory::writeDebugMap(map, debugFileName);
}
@@ -542,7 +938,7 @@ OsmMapPtr ChangesetReplacementCreator::_getImmediatelyConnectedOutOfBoundsWays(
new TagKeyCriterion(MetadataTags::HootConnectedWayOutsideBounds()))));
OsmMapPtr connectedWays = OsmUtils::getMapSubset(map, copyCrit);
connectedWays->setName(outputMapName);
- LOG_VARD(MapProjector::toWkt(connectedWays->getProjection()));
+ LOG_VART(MapProjector::toWkt(connectedWays->getProjection()));
OsmMapWriterFactory::writeDebugMap(connectedWays, "connected-ways");
return connectedWays;
}
@@ -552,11 +948,13 @@ void ChangesetReplacementCreator::_cropMapForChangesetDerivation(
const bool keepOnlyFeaturesInsideBounds, const bool isLinearMap, const QString& debugFileName)
{
LOG_DEBUG("Cropping map: " << map->getName() << " for changeset derivation...");
+ LOG_VART(MapProjector::toWkt(map->getProjection()));
+ //LOG_VART(map->getProjection()->GetName());
MapCropper cropper(bounds);
cropper.setKeepEntireFeaturesCrossingBounds(keepEntireFeaturesCrossingBounds);
cropper.setKeepOnlyFeaturesInsideBounds(keepOnlyFeaturesInsideBounds);
- LOG_DEBUG(cropper.getInitStatusMessage());
+ //LOG_DEBUG(cropper.getInitStatusMessage());
cropper.apply(map);
LOG_DEBUG(cropper.getCompletedStatusMessage());
@@ -565,7 +963,7 @@ void ChangesetReplacementCreator::_cropMapForChangesetDerivation(
// with no information.
SuperfluousNodeRemover::removeNodes(map, isLinearMap);
- LOG_VARD(MapProjector::toWkt(map->getProjection()));
+ LOG_VART(MapProjector::toWkt(map->getProjection()));
OsmMapWriterFactory::writeDebugMap(map, debugFileName);
}
@@ -589,7 +987,7 @@ void ChangesetReplacementCreator::_removeUnsnappedImmediatelyConnectedOutOfBound
LOG_DEBUG(removeVis.getInitStatusMessage());
map->visitRw(removeVis);
LOG_DEBUG(removeVis.getCompletedStatusMessage());
- LOG_VARD(MapProjector::toWkt(map->getProjection()));
+ LOG_VART(MapProjector::toWkt(map->getProjection()));
OsmMapWriterFactory::writeDebugMap(map, map->getName() + "-unsnapped-removed");
}
@@ -599,7 +997,7 @@ void ChangesetReplacementCreator::_excludeFeaturesFromChangesetDeletion(OsmMapPt
LOG_DEBUG(
"Marking reference features in: " << map->getName() << " for exclusion from deletion...");
- std::shared_ptr<InBoundsCriterion> boundsCrit(new InBoundsCriterion(_inBoundsStrict));
+ std::shared_ptr<InBoundsCriterion> boundsCrit(new InBoundsCriterion(_boundsOpts.inBoundsStrict));
boundsCrit->setBounds(GeometryUtils::envelopeFromConfigString(boundsStr));
boundsCrit->setOsmMap(map.get());
std::shared_ptr<NotCriterion> notInBoundsCrit(new NotCriterion(boundsCrit));
@@ -611,7 +1009,7 @@ void ChangesetReplacementCreator::_excludeFeaturesFromChangesetDeletion(OsmMapPt
tagSetter.apply(map);
LOG_DEBUG(tagSetter.getCompletedStatusMessage());
- LOG_VARD(MapProjector::toWkt(map->getProjection()));
+ LOG_VART(MapProjector::toWkt(map->getProjection()));
OsmMapWriterFactory::writeDebugMap(map, map->getName() + "-after-delete-exclude-tags");
}
@@ -622,12 +1020,8 @@ bool ChangesetReplacementCreator::_isNetworkConflate() const
QString::fromStdString(NetworkMatchCreator::className()));
}
-void ChangesetReplacementCreator::_parseConfigOpts(
- const bool lenientBounds, const std::shared_ptr<ConflatableElementCriterion>& featureFilter,
- const QString& boundsStr)
+void ChangesetReplacementCreator::_setGlobalOpts(const QString& boundsStr)
{
- // global opts
-
conf().set(ConfigOptions::getChangesetXmlWriterAddTimestampKey(), false);
conf().set(ConfigOptions::getReaderAddSourceDatetimeKey(), false);
conf().set(ConfigOptions::getWriterIncludeCircularErrorTagsKey(), false);
@@ -635,64 +1029,65 @@ void ChangesetReplacementCreator::_parseConfigOpts(
// For this being enabled to have any effect,
// convert.bounding.box.keep.immediately.connected.ways.outside.bounds must be enabled as well.
conf().set(ConfigOptions::getConvertBoundingBoxTagImmediatelyConnectedOutOfBoundsWaysKey(), true);
+ // turn on for testing only
//conf().set(ConfigOptions::getDebugMapsWriteKey(), true);
- // dataset specific opts
-
// These don't change between scenarios (or at least haven't needed to yet).
- _loadRefKeepOnlyInsideBounds = false;
- _cookieCutKeepOnlyInsideBounds = false;
- _changesetRefKeepOnlyInsideBounds = false;
+ _boundsOpts.loadRefKeepOnlyInsideBounds = false;
+ _boundsOpts.cookieCutKeepOnlyInsideBounds = false;
+ _boundsOpts.changesetRefKeepOnlyInsideBounds = false;
+}
+void ChangesetReplacementCreator::_parseConfigOpts(
+ const bool lenientBounds, const GeometryTypeCriterion::GeometryType& geometryType)
+{
// only one of these should ever be true
- if (featureFilter->getGeometryType() ==
- ConflatableElementCriterion::ConflatableGeometryType::Point)
+ if (geometryType == GeometryTypeCriterion::GeometryType::Point)
{
if (lenientBounds)
{
LOG_WARN("--lenient-bounds option ignored with point datasets.");
}
- _loadRefKeepEntireCrossingBounds = false;
- _loadRefKeepImmediateConnectedWaysOutsideBounds = false;
- _loadSecKeepEntireCrossingBounds = false;
- _loadSecKeepOnlyInsideBounds = false;
- _cookieCutKeepEntireCrossingBounds = false;
- _changesetRefKeepEntireCrossingBounds = false;
- _changesetSecKeepEntireCrossingBounds = false;
- _changesetSecKeepOnlyInsideBounds = true;
- _changesetAllowDeletingRefOutsideBounds = true;
- _inBoundsStrict = false;
+ _boundsOpts.loadRefKeepEntireCrossingBounds = false;
+ _boundsOpts.loadRefKeepImmediateConnectedWaysOutsideBounds = false;
+ _boundsOpts.loadSecKeepEntireCrossingBounds = false;
+ _boundsOpts.loadSecKeepOnlyInsideBounds = false;
+ _boundsOpts.cookieCutKeepEntireCrossingBounds = false;
+ _boundsOpts.changesetRefKeepEntireCrossingBounds = false;
+ _boundsOpts.changesetSecKeepEntireCrossingBounds = false;
+ _boundsOpts.changesetSecKeepOnlyInsideBounds = true;
+ _boundsOpts.changesetAllowDeletingRefOutsideBounds = true;
+ _boundsOpts.inBoundsStrict = false;
}
- else if (featureFilter->getGeometryType() ==
- ConflatableElementCriterion::ConflatableGeometryType::Line)
+ else if (geometryType == GeometryTypeCriterion::GeometryType::Line)
{
if (lenientBounds)
{
- _loadRefKeepEntireCrossingBounds = true;
- _loadRefKeepImmediateConnectedWaysOutsideBounds = true;
- _loadSecKeepEntireCrossingBounds = true;
- _loadSecKeepOnlyInsideBounds = false;
- _cookieCutKeepEntireCrossingBounds = false;
- _changesetRefKeepEntireCrossingBounds = true;
- _changesetSecKeepEntireCrossingBounds = true;
- _changesetSecKeepOnlyInsideBounds = false;
- _changesetAllowDeletingRefOutsideBounds = true;
- _inBoundsStrict = false;
+ _boundsOpts.loadRefKeepEntireCrossingBounds = true;
+ _boundsOpts.loadRefKeepImmediateConnectedWaysOutsideBounds = true;
+ _boundsOpts.loadSecKeepEntireCrossingBounds = true;
+ _boundsOpts.loadSecKeepOnlyInsideBounds = false;
+ _boundsOpts.cookieCutKeepEntireCrossingBounds = false;
+ _boundsOpts.changesetRefKeepEntireCrossingBounds = true;
+ _boundsOpts.changesetSecKeepEntireCrossingBounds = true;
+ _boundsOpts.changesetSecKeepOnlyInsideBounds = false;
+ _boundsOpts.changesetAllowDeletingRefOutsideBounds = true;
+ _boundsOpts.inBoundsStrict = false;
}
else
{
- _loadRefKeepEntireCrossingBounds = true;
- _loadRefKeepImmediateConnectedWaysOutsideBounds = false;
- _loadSecKeepEntireCrossingBounds = false;
- _loadSecKeepOnlyInsideBounds = false;
- _cookieCutKeepEntireCrossingBounds = false;
- _changesetRefKeepEntireCrossingBounds = true;
- _changesetSecKeepEntireCrossingBounds = true;
- _changesetSecKeepOnlyInsideBounds = false;
- _changesetAllowDeletingRefOutsideBounds = false;
- _inBoundsStrict = false;
+ _boundsOpts.loadRefKeepEntireCrossingBounds = true;
+ _boundsOpts.loadRefKeepImmediateConnectedWaysOutsideBounds = false;
+ _boundsOpts.loadSecKeepEntireCrossingBounds = false;
+ _boundsOpts.loadSecKeepOnlyInsideBounds = false;
+ _boundsOpts.cookieCutKeepEntireCrossingBounds = false;
+ _boundsOpts.changesetRefKeepEntireCrossingBounds = true;
+ _boundsOpts.changesetSecKeepEntireCrossingBounds = true;
+ _boundsOpts.changesetSecKeepOnlyInsideBounds = false;
+ _boundsOpts.changesetAllowDeletingRefOutsideBounds = false;
+ _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
@@ -711,34 +1106,33 @@ void ChangesetReplacementCreator::_parseConfigOpts(
LOG_VARD(conf().getList(ConfigOptions::getConflatePostOpsKey()));
}
}
- else if (featureFilter->getGeometryType() ==
- ConflatableElementCriterion::ConflatableGeometryType::Polygon)
+ else if (geometryType == GeometryTypeCriterion::GeometryType::Polygon)
{
if (lenientBounds)
{
- _loadRefKeepEntireCrossingBounds = true;
- _loadRefKeepImmediateConnectedWaysOutsideBounds = false;
- _loadSecKeepEntireCrossingBounds = true;
- _loadSecKeepOnlyInsideBounds = false;
- _cookieCutKeepEntireCrossingBounds = true;
- _changesetRefKeepEntireCrossingBounds = true;
- _changesetSecKeepEntireCrossingBounds = true;
- _changesetSecKeepOnlyInsideBounds = false;
- _changesetAllowDeletingRefOutsideBounds = true;
- _inBoundsStrict = false;
+ _boundsOpts.loadRefKeepEntireCrossingBounds = true;
+ _boundsOpts.loadRefKeepImmediateConnectedWaysOutsideBounds = false;
+ _boundsOpts.loadSecKeepEntireCrossingBounds = true;
+ _boundsOpts.loadSecKeepOnlyInsideBounds = false;
+ _boundsOpts.cookieCutKeepEntireCrossingBounds = true;
+ _boundsOpts.changesetRefKeepEntireCrossingBounds = true;
+ _boundsOpts.changesetSecKeepEntireCrossingBounds = true;
+ _boundsOpts.changesetSecKeepOnlyInsideBounds = false;
+ _boundsOpts.changesetAllowDeletingRefOutsideBounds = true;
+ _boundsOpts.inBoundsStrict = false;
}
else
{
- _loadRefKeepEntireCrossingBounds = true;
- _loadRefKeepImmediateConnectedWaysOutsideBounds = false;
- _loadSecKeepEntireCrossingBounds = false;
- _loadSecKeepOnlyInsideBounds = true;
- _cookieCutKeepEntireCrossingBounds = true;
- _changesetRefKeepEntireCrossingBounds = true;
- _changesetSecKeepEntireCrossingBounds = false;
- _changesetSecKeepOnlyInsideBounds = true;
- _changesetAllowDeletingRefOutsideBounds = false;
- _inBoundsStrict = true;
+ _boundsOpts.loadRefKeepEntireCrossingBounds = true;
+ _boundsOpts.loadRefKeepImmediateConnectedWaysOutsideBounds = false;
+ _boundsOpts.loadSecKeepEntireCrossingBounds = false;
+ _boundsOpts.loadSecKeepOnlyInsideBounds = true;
+ _boundsOpts.cookieCutKeepEntireCrossingBounds = true;
+ _boundsOpts.changesetRefKeepEntireCrossingBounds = true;
+ _boundsOpts.changesetSecKeepEntireCrossingBounds = false;
+ _boundsOpts.changesetSecKeepOnlyInsideBounds = true;
+ _boundsOpts.changesetAllowDeletingRefOutsideBounds = false;
+ _boundsOpts.inBoundsStrict = true;
}
}
else
@@ -749,21 +1143,21 @@ void ChangesetReplacementCreator::_parseConfigOpts(
conf().set(
ConfigOptions::getChangesetReplacementAllowDeletingReferenceFeaturesOutsideBoundsKey(),
- _changesetAllowDeletingRefOutsideBounds);
-
- LOG_VARD(_loadRefKeepEntireCrossingBounds);
- LOG_VARD(_loadRefKeepOnlyInsideBounds);
- LOG_VARD(_loadRefKeepImmediateConnectedWaysOutsideBounds);
- LOG_VARD(_loadSecKeepEntireCrossingBounds);
- LOG_VARD(_loadSecKeepOnlyInsideBounds);
- LOG_VARD(_cookieCutKeepEntireCrossingBounds);
- LOG_VARD(_cookieCutKeepOnlyInsideBounds);
- LOG_VARD(_changesetRefKeepEntireCrossingBounds);
- LOG_VARD(_changesetRefKeepOnlyInsideBounds);
- LOG_VARD(_changesetSecKeepEntireCrossingBounds);
- LOG_VARD(_changesetSecKeepOnlyInsideBounds);
- LOG_VARD(_changesetAllowDeletingRefOutsideBounds);
- LOG_VARD(_inBoundsStrict);
+ _boundsOpts.changesetAllowDeletingRefOutsideBounds);
+
+ LOG_VARD(_boundsOpts.loadRefKeepEntireCrossingBounds);
+ LOG_VARD(_boundsOpts.loadRefKeepOnlyInsideBounds);
+ LOG_VARD(_boundsOpts.loadRefKeepImmediateConnectedWaysOutsideBounds);
+ LOG_VARD(_boundsOpts.loadSecKeepEntireCrossingBounds);
+ LOG_VARD(_boundsOpts.loadSecKeepOnlyInsideBounds);
+ LOG_VARD(_boundsOpts.cookieCutKeepEntireCrossingBounds);
+ LOG_VARD(_boundsOpts.cookieCutKeepOnlyInsideBounds);
+ LOG_VARD(_boundsOpts.changesetRefKeepEntireCrossingBounds);
+ LOG_VARD(_boundsOpts.changesetRefKeepOnlyInsideBounds);
+ LOG_VARD(_boundsOpts.changesetSecKeepEntireCrossingBounds);
+ LOG_VARD(_boundsOpts.changesetSecKeepOnlyInsideBounds);
+ LOG_VARD(_boundsOpts.changesetAllowDeletingRefOutsideBounds);
+ LOG_VARD(_boundsOpts.inBoundsStrict);
}
}