Skip to content

v0.2.53..v0.2.54 changeset ChangesetReplacementCreator.cpp

Garret Voltz edited this page Mar 31, 2020 · 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 d7929c1..32ca201 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
@@ -60,7 +60,9 @@
 #include <hoot/core/ops/NamedOp.h>
 #include <hoot/core/ops/PointsToPolysConverter.h>
 #include <hoot/core/ops/SuperfluousNodeRemover.h>
+#include <hoot/core/ops/SuperfluousWayRemover.h>
 #include <hoot/core/ops/RecursiveSetTagValueOp.h>
+#include <hoot/core/ops/RemoveEmptyRelationsOp.h>
 #include <hoot/core/ops/WayJoinerOp.h>
 
 #include <hoot/core/util/Boundable.h>
@@ -73,6 +75,7 @@
 #include <hoot/core/visitors/ApiTagTruncateVisitor.h>
 #include <hoot/core/visitors/FilteredVisitor.h>
 #include <hoot/core/visitors/RemoveElementsVisitor.h>
+#include <hoot/core/visitors/RemoveMissingElementsVisitor.h>
 #include <hoot/core/visitors/SetTagValueVisitor.h>
 
 namespace hoot
@@ -86,7 +89,8 @@ _geometryFiltersSpecified(false),
 _chainReplacementFilters(false),
 _chainRetainmentFilters(false),
 _waySnappingEnabled(true),
-_conflationEnabled(true)
+_conflationEnabled(true),
+_tagOobConnectedWays(false)
 {
   _changesetCreator.reset(new ChangesetCreator(printStats, osmApiDbUrl));
   setGeometryFilters(QStringList());
@@ -94,7 +98,7 @@ _conflationEnabled(true)
 
 void ChangesetReplacementCreator::setGeometryFilters(const QStringList& filterClassNames)
 {
-  LOG_VARD(filterClassNames);
+  LOG_VART(filterClassNames);
   if (!filterClassNames.isEmpty())
   {
     _geometryFiltersSpecified = true;
@@ -104,7 +108,7 @@ void ChangesetReplacementCreator::setGeometryFilters(const QStringList& filterCl
     for (int i = 0; i < filterClassNames.size(); i++)
     {
       const QString filterClassName = filterClassNames.at(i);
-      LOG_VARD(filterClassName);
+      LOG_VART(filterClassName);
 
       // Fail if the filter doesn't map to a geometry type.
       std::shared_ptr<GeometryTypeCriterion> filter =
@@ -138,18 +142,18 @@ void ChangesetReplacementCreator::setGeometryFilters(const QStringList& filterCl
 
   // TODO: have to call this method to keep filtering from erroring...shouldn't have to...should
   // init itself internally when no geometry filters are specified
-  LOG_VARD(_geometryTypeFilters.size());
+  LOG_VART(_geometryTypeFilters.size());
   if (_geometryTypeFilters.isEmpty())
   {
     _geometryFiltersSpecified = false;
     _geometryTypeFilters = _getDefaultGeometryFilters();
     _linearFilterClassNames =
-      ConflatableElementCriterion::getCriterionClassNamesByType(
+      ConflatableElementCriterion::getCriterionClassNamesByGeometryType(
         GeometryTypeCriterion::GeometryType::Line);
   }
 
   LOG_VARD(_geometryTypeFilters.size());
-  LOG_VARD(_linearFilterClassNames);
+  LOG_VART(_linearFilterClassNames);
 }
 
 void ChangesetReplacementCreator::_setInputFilter(
@@ -214,10 +218,10 @@ void ChangesetReplacementCreator::_setInputFilter(
 
 void ChangesetReplacementCreator::setReplacementFilters(const QStringList& filterClassNames)
 {
-  LOG_VARD(filterClassNames.size());
+  LOG_VART(filterClassNames.size());
   if (filterClassNames.size() > 0)
   {
-    LOG_DEBUG("Creating replacement filter...");
+    LOG_TRACE("Creating replacement filter...");
     _setInputFilter(_replacementFilter, filterClassNames, _chainReplacementFilters);
   }
 }
@@ -235,9 +239,9 @@ void ChangesetReplacementCreator::setRetainmentFilters(const QStringList& filter
 void ChangesetReplacementCreator::_setInputFilterOptions(Settings& opts,
                                                          const QStringList& optionKvps)
 {
-  LOG_VARD(optionKvps.size());
+  LOG_VART(optionKvps.size());
   opts = conf();
-  LOG_DEBUG("Opts size before adding custom opts: " << opts.size());
+  const int optsSizeBefore = opts.size();
   for (int i = 0; i < optionKvps.size(); i++)
   {
     const QString kvp = optionKvps.at(i);
@@ -248,12 +252,13 @@ void ChangesetReplacementCreator::_setInputFilterOptions(Settings& opts,
       throw IllegalArgumentException("Invalid filter configuration option: " + kvp);
     }
     const QString key = kvp.mid(0, firstEqualOccurrence).trimmed().remove("\"").remove("'");
-    LOG_VARD(key);
+    LOG_VART(key);
     const QString val = kvp.mid(firstEqualOccurrence + 2).trimmed().remove("\"").remove("'");
-    LOG_VARD(val);
+    LOG_VART(val);
     opts.set(key, val);
   }
-  LOG_DEBUG("Opts size after adding custom opts: " << opts.size());
+  const int optsSizeAfter = opts.size() - optsSizeBefore;
+  LOG_DEBUG("Opts size after adding custom opts: " << optsSizeAfter);
 }
 
 void ChangesetReplacementCreator::setReplacementFilterOptions(const QStringList& optionKvps)
@@ -313,6 +318,7 @@ void ChangesetReplacementCreator::create(
   for (QMap<GeometryTypeCriterion::GeometryType, ElementCriterionPtr>::const_iterator itr =
          refFilters.begin(); itr != refFilters.end(); ++itr)
   {
+    LOG_VARD("******************************************");
     LOG_INFO(
       "Preparing maps for changeset derivation given geometry type: "<<
       GeometryTypeCriterion::typeToString(itr.key()) << ". Pass: " << passCtr << " / " <<
@@ -321,7 +327,7 @@ void ChangesetReplacementCreator::create(
     OsmMapPtr refMap;
     OsmMapPtr conflatedMap;
     QStringList linearFilterClassNames;
-    LOG_VARD(itr.value().get());
+    //LOG_VARD(itr.value().get());
     if (itr.key() == GeometryTypeCriterion::GeometryType::Line)
     {
       linearFilterClassNames = _linearFilterClassNames;
@@ -330,24 +336,43 @@ void ChangesetReplacementCreator::create(
       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)
+    if (!refMap)
+    {
+      LOG_DEBUG("ref map null");
+    }
+    else
     {
       LOG_VARD(refMap->size());
-      LOG_VARD(conflatedMap.get());
+    }
+    if (!conflatedMap)
+    {
+      LOG_DEBUG("conflated map null");
+    }
+    else
+    {
+      LOG_VARD(conflatedMap->size());
+    }
+    if (refMap && conflatedMap)
+    {
+      LOG_DEBUG(
+        "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()) << "...");
+      refMap->setName(refMap->getName() + "-" + GeometryTypeCriterion::typeToString(itr.key()));
       refMaps.append(refMap);
+      conflatedMap->setName(
+        conflatedMap->getName() + "-" + GeometryTypeCriterion::typeToString(itr.key()));
       conflatedMaps.append(conflatedMap);
     }
 
     passCtr++;
   }
 
-  LOG_VARD(refMaps.size());
-  LOG_VARD(conflatedMaps.size());
-  if (refMaps.size() == 0 || conflatedMaps.size() == 0)
+  LOG_VART(refMaps.size());
+  LOG_VART(conflatedMaps.size());
+  if (refMaps.size() == 0 && conflatedMaps.size() == 0)
   {
-    LOG_INFO("No features remain after filtering. Skipping changeset generation...");
+    LOG_WARN("No features remain after filtering so no changeset will be generated.");
     return;
   }
   assert(refMaps.size() == conflatedMaps.size());
@@ -359,7 +384,7 @@ void ChangesetReplacementCreator::create(
 
   _changesetCreator->create(refMaps, conflatedMaps, output);
 
-  LOG_INFO("Derived replacement changeset: " << output.right(maxFilePrintLength));
+  LOG_INFO("Derived replacement changeset: ..." << output.right(maxFilePrintLength));
 }
 
 void ChangesetReplacementCreator::_getMapsForGeometryType(
@@ -369,8 +394,8 @@ void ChangesetReplacementCreator::_getMapsForGeometryType(
   const GeometryTypeCriterion::GeometryType& geometryType,
   const QStringList& linearFilterClassNames)
 {
-  LOG_VARD(linearFilterClassNames);
-  LOG_VARD(secFeatureFilter);
+  LOG_VART(linearFilterClassNames);
+  LOG_VART(secFeatureFilter);
 
   // INPUT VALIDATION AND SETUP
 
@@ -387,8 +412,8 @@ void ChangesetReplacementCreator::_getMapsForGeometryType(
 
   const QMap<ElementId, long> refIdToVersionMappings = _getIdToVersionMappings(refMap);
   const bool isLinearCrit = !linearFilterClassNames.isEmpty();
-  LOG_VARD(isLinearCrit);
-  if (_lenientBounds && isLinearCrit)
+  LOG_VART(isLinearCrit);
+  if (_tagOobConnectedWays && _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.
@@ -398,7 +423,9 @@ void ChangesetReplacementCreator::_getMapsForGeometryType(
   // 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, refFeatureFilter, conf(), "ref-after-type-pruning");
+  _filterFeatures(
+    refMap, refFeatureFilter, conf(),
+    "ref-after-" + GeometryTypeCriterion::typeToString(geometryType) + "-pruning");
 
   // Load the sec dataset and crop to the specified aoi.
 
@@ -407,25 +434,22 @@ 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.
 
-  _filterFeatures(secMap, secFeatureFilter, _replacementFilterOptions, "sec-after-type-pruning");
+  _filterFeatures(
+    secMap, secFeatureFilter, _replacementFilterOptions,
+    "sec-after-" + GeometryTypeCriterion::typeToString(geometryType) + "-pruning");
 
-  LOG_VARD(refMap->getElementCount());
-  LOG_VARD(secMap->getElementCount());
-  // If the secondary dataset is empty here, then the filtering must have removed everything from
-  // it...no changeset to calculate. Note, the ref map could be empty by this point, and that will
-  // just result in an all add changeset with secondary features in it for the current geometry
-  // type being replaced
-  if (secMap->getElementCount() == 0)
-  {
-    LOG_INFO("Secondary input map empty after filtering. Skipping changeset generation...");
-    return;
-  }
+  const int refMapSize = refMap->size();
+  // If the secondary dataset is empty here and the ref dataset isn't, then we'll end up with a
+  // changeset with delete statements if the option to allow deleting reference features is enabled.
+  const int secMapSize = secMap->size();
+  LOG_VARD(refMapSize);
+  LOG_VARD(secMapSize);
 
   // COOKIE CUT
 
   // Cut the secondary data out of the reference data.
 
-  OsmMapPtr cookieCutRefMap = _getCookieCutMap(refMap, secMap);
+  OsmMapPtr cookieCutRefMap = _getCookieCutMap(refMap, secMap, geometryType);
 
   // 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
@@ -445,11 +469,12 @@ void ChangesetReplacementCreator::_getMapsForGeometryType(
   // Conflate the cookie cut ref map with the sec map.
 
   conflatedMap = cookieCutRefMap;
-  if (_conflationEnabled)
+  if (_conflationEnabled && secMapSize > 0)
   {
     // TODO: do something with reviews - #3361
     _conflate(conflatedMap, _lenientBounds);
   }
+  conflatedMap->setName("conflated");
 
   if (isLinearCrit && _waySnappingEnabled)
   {
@@ -475,7 +500,7 @@ void ChangesetReplacementCreator::_getMapsForGeometryType(
     // data in the resulting changeset and generate modify statements instead.
 
     ReplacementSnappedWayJoiner(refIdToVersionMappings).join(conflatedMap);
-    LOG_VARD(MapProjector::toWkt(conflatedMap->getProjection()));
+    LOG_VART(MapProjector::toWkt(conflatedMap->getProjection()));
   }
 
   // PRE-CHANGESET DERIVATION DATA PREP
@@ -500,8 +525,8 @@ void ChangesetReplacementCreator::_getMapsForGeometryType(
   _cropMapForChangesetDerivation(
     conflatedMap, bounds, _boundsOpts.changesetSecKeepEntireCrossingBounds,
     _boundsOpts.changesetSecKeepOnlyInsideBounds, isLinearCrit, "sec-cropped-for-changeset");
-  LOG_VARD(_lenientBounds);
-  LOG_VARD(isLinearCrit);
+  LOG_VART(_lenientBounds);
+  LOG_VART(isLinearCrit);
   if (_lenientBounds && isLinearCrit)
   {
     if (_waySnappingEnabled)
@@ -538,7 +563,7 @@ void ChangesetReplacementCreator::_getMapsForGeometryType(
 
     if (_waySnappingEnabled)
     {
-      LOG_VARD(linearFilterClassNames);
+      LOG_VART(linearFilterClassNames);
       for (int i = 0; i < linearFilterClassNames.size(); i++)
       {
         _snapUnconnectedWays(
@@ -567,8 +592,29 @@ void ChangesetReplacementCreator::_getMapsForGeometryType(
     _excludeFeaturesFromChangesetDeletion(refMap, boundsStr);
   }
 
-  LOG_VARD(refMap->getElementCount());
-  LOG_VARD(conflatedMap->getElementCount());
+  _cleanupMissingElements(refMap);
+  _cleanupMissingElements(conflatedMap);
+
+  LOG_VART(refMap->getElementCount());
+  LOG_VART(conflatedMap->getElementCount());
+}
+
+void ChangesetReplacementCreator::_cleanupMissingElements(OsmMapPtr& map)
+{
+  //SuperfluousWayRemover::removeWays(map);
+  //SuperfluousNodeRemover::removeNodes(map);
+
+  // 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());
+
+  // This will remove any relations that were already empty or became empty after the previous step.
+  RemoveEmptyRelationsOp emptyRelationRemover;
+  LOG_STATUS("\t" << emptyRelationRemover.getInitStatusMessage());
+  emptyRelationRemover.apply(map);
+  LOG_STATUS("\t" << emptyRelationRemover.getCompletedStatusMessage());
 }
 
 void ChangesetReplacementCreator::_validateInputs(const QString& input1, const QString& input2)
@@ -630,7 +676,7 @@ QMap<GeometryTypeCriterion::GeometryType, ElementCriterionPtr>
     std::shared_ptr<ChainCriterion> nonGeometryFilter)
 {
   QMap<GeometryTypeCriterion::GeometryType, ElementCriterionPtr> combinedFilters;
-  LOG_VARD(nonGeometryFilter.get());
+  LOG_VART(nonGeometryFilter.get());
   if (nonGeometryFilter)
   {
     for (QMap<GeometryTypeCriterion::GeometryType, ElementCriterionPtr>::const_iterator itr =
@@ -638,7 +684,7 @@ QMap<GeometryTypeCriterion::GeometryType, ElementCriterionPtr>
     {
       combinedFilters[itr.key()] =
         std::shared_ptr<ChainCriterion>(new ChainCriterion(itr.value(), nonGeometryFilter));
-      LOG_DEBUG("New combined filter: " << combinedFilters[itr.key()]->toString());
+      LOG_TRACE("New combined filter: " << combinedFilters[itr.key()]->toString());
     }
   }
   else
@@ -647,12 +693,12 @@ QMap<GeometryTypeCriterion::GeometryType, ElementCriterionPtr>
     {
       _geometryTypeFilters = _getDefaultGeometryFilters();
       _linearFilterClassNames =
-        ConflatableElementCriterion::getCriterionClassNamesByType(
+        ConflatableElementCriterion::getCriterionClassNamesByGeometryType(
           GeometryTypeCriterion::GeometryType::Line);
     }
     combinedFilters = _geometryTypeFilters;
   }
-  LOG_VARD(combinedFilters.size());
+  LOG_VART(combinedFilters.size());
   return combinedFilters;
 }
 
@@ -691,12 +737,12 @@ OsmMapPtr ChangesetReplacementCreator::_loadRefMap(const QString& input)
 QMap<ElementId, long> ChangesetReplacementCreator::_getIdToVersionMappings(
   const OsmMapPtr& map) const
 {
-  LOG_INFO("Mapping element IDs to element versions for: " << map->getName() << "...");
+  LOG_DEBUG("Mapping element IDs to element versions for: " << map->getName() << "...");
 
   ElementIdToVersionMapper idToVersionMapper;
-  LOG_DEBUG(idToVersionMapper.getInitStatusMessage());
+  LOG_STATUS("\t" << idToVersionMapper.getInitStatusMessage());
   idToVersionMapper.apply(map);
-  LOG_DEBUG(idToVersionMapper.getCompletedStatusMessage());
+  LOG_STATUS("\t" << idToVersionMapper.getCompletedStatusMessage());
   const QMap<ElementId, long> idToVersionMappings = idToVersionMapper.getMappings();
   LOG_VART(idToVersionMappings.size());
   return idToVersionMappings;
@@ -711,14 +757,14 @@ void ChangesetReplacementCreator::_addChangesetDeleteExclusionTags(OsmMapPtr& ma
   // Add the changeset deletion exclusion tag to all connected ways previously tagged upon load.
 
   SetTagValueVisitor addTagVis(MetadataTags::HootChangeExcludeDelete(), "yes");
-  LOG_DEBUG(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_DEBUG(addTagVis.getCompletedStatusMessage());
+  LOG_STATUS("\t" << addTagVis.getCompletedStatusMessage());
 
   // Add the changeset deletion exclusion tag to all children of those connected ways.
 
@@ -729,9 +775,9 @@ void ChangesetReplacementCreator::_addChangesetDeleteExclusionTags(OsmMapPtr& ma
         new TagKeyCriterion(MetadataTags::HootChangeExcludeDelete()))));
   RecursiveSetTagValueOp childDeletionExcludeTagOp(
     MetadataTags::HootChangeExcludeDelete(), "yes", childAddTagCrit);
-  LOG_DEBUG(childDeletionExcludeTagOp.getInitStatusMessage());
+  LOG_STATUS("\t" << childDeletionExcludeTagOp.getInitStatusMessage());
   childDeletionExcludeTagOp.apply(map);
-  LOG_DEBUG(childDeletionExcludeTagOp.getCompletedStatusMessage());
+  LOG_STATUS("\t" << childDeletionExcludeTagOp.getCompletedStatusMessage());
 
   OsmMapWriterFactory::writeDebugMap(map, map->getName() + "-after-delete-exclusion-tagging");
 }
@@ -774,28 +820,51 @@ void ChangesetReplacementCreator::_filterFeatures(
   elementPruner.setConfiguration(config);
   elementPruner.setOsmMap(map.get());
   elementPruner.setRecursive(true);
-  LOG_DEBUG(elementPruner.getInitStatusMessage());
+  LOG_STATUS("\t" << elementPruner.getInitStatusMessage());
   map->visitRw(elementPruner);
-  LOG_DEBUG(elementPruner.getCompletedStatusMessage());
+  LOG_STATUS("\t" << elementPruner.getCompletedStatusMessage());
 
   LOG_VART(MapProjector::toWkt(map->getProjection()));
   OsmMapWriterFactory::writeDebugMap(map, debugFileName);
 }
 
-OsmMapPtr ChangesetReplacementCreator::_getCookieCutMap(OsmMapPtr doughMap, OsmMapPtr cutterMap)
+OsmMapPtr ChangesetReplacementCreator::_getCookieCutMap(
+  OsmMapPtr doughMap, OsmMapPtr cutterMap, const GeometryTypeCriterion::GeometryType& geometryType)
 {
-  // TODO: could use some refactoring here after the addition of _fullReplacement
+  // 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)
   {
+    LOG_DEBUG("Nothing to cut from dough map, so returning the dough map as the cut map...");
     return doughMap;
   }
+  else if (cutterMap->size() == 0)
+  {
+    if (_fullReplacement)
+    {
+      // 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());
+    }
+    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;
+    }
+  }
 
-  LOG_VARD(doughMap->getElementCount());
+  LOG_VART(doughMap->getElementCount());
   LOG_VART(MapProjector::toWkt(doughMap->getProjection()));
   OsmMapWriterFactory::writeDebugMap(doughMap, "dough-map");
-  LOG_VARD(cutterMap->getElementCount());
+  LOG_VART(cutterMap->getElementCount());
   LOG_VART(MapProjector::toWkt(cutterMap->getProjection()));
 
   OsmMapPtr cookieCutMap(new OsmMap(doughMap));
@@ -804,16 +873,17 @@ OsmMapPtr ChangesetReplacementCreator::_getCookieCutMap(OsmMapPtr doughMap, OsmM
   LOG_DEBUG("Preparing to cookie cut: " << cookieCutMap->getName() << "...");
 
   OsmMapPtr cutterMapToUse;
-  LOG_VARD(cutterMap->getElementCount());
+  LOG_VART(cutterMap->getElementCount());
   ConfigOptions opts(conf());
-  LOG_VARD(OsmUtils::mapIsPointsOnly(cutterMap));
+  LOG_VART(OsmUtils::mapIsPointsOnly(cutterMap));
   const double cookieCutterAlpha = opts.getCookieCutterAlpha();
   double cookieCutterAlphaShapeBuffer = opts.getCookieCutterAlphaShapeBuffer();
-  LOG_VARD(_fullReplacement);
+  LOG_VART(_fullReplacement);
   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 as cutter shape map...");
     cutterMapToUse = doughMap;
     cookieCutterAlphaShapeBuffer = 10.0;
   }
@@ -825,23 +895,27 @@ OsmMapPtr ChangesetReplacementCreator::_getCookieCutMap(OsmMapPtr doughMap, OsmM
     // 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.
 
+    LOG_DEBUG("Generating cutter shape map from sec map transformation...");
     cutterMapToUse.reset(new OsmMap(cutterMap));
     PointsToPolysConverter pointConverter;
-    LOG_INFO(pointConverter.getInitStatusMessage());
+    LOG_STATUS("\t" << pointConverter.getInitStatusMessage());
     pointConverter.apply(cutterMapToUse);
-    LOG_INFO(pointConverter.getCompletedStatusMessage());
+    LOG_STATUS("\t" << pointConverter.getCompletedStatusMessage());
     MapProjector::projectToWgs84(cutterMapToUse);
   }
   else
   {
     // Generate a cutter shape based on the cropped secondary map.
+    LOG_DEBUG("Using cutter map as cutter shape map...");
     cutterMapToUse = cutterMap;
   }
-  LOG_VARD(cutterMapToUse->getElementCount());
+  LOG_VART(cutterMapToUse->getElementCount());
   OsmMapWriterFactory::writeDebugMap(cutterMapToUse, "cutter-map");
 
   LOG_INFO("Generating cutter shape map from: " << cutterMapToUse->getName() << "...");
 
+  LOG_VART(cookieCutterAlpha);
+  LOG_VART(cookieCutterAlphaShapeBuffer);
   OsmMapPtr cutterShapeOutlineMap;
   try
   {
@@ -854,10 +928,11 @@ OsmMapPtr ChangesetReplacementCreator::_getCookieCutMap(OsmMapPtr doughMap, OsmM
     if (e.getWhat().contains("Alpha Shape area is zero"))
     {
       LOG_ERROR(
-        "No cut shape generated from secondary data. " << e.getWhat() <<
-        " Is your secondary data empty or have you filtered it to be empty?");
+        "No cut shape generated from secondary data when processing geometry type: " <<
+        GeometryTypeCriterion::typeToString(geometryType) << ". Is your secondary data empty " <<
+        "or have you filtered it to be empty? error: " << e.getWhat());
     }
-    //  Rethrow the original exception
+    // rethrow the original exception
     throw;
   }
 
@@ -876,7 +951,7 @@ OsmMapPtr ChangesetReplacementCreator::_getCookieCutMap(OsmMapPtr doughMap, OsmM
   MapProjector::projectToWgs84(cookieCutMap); // not exactly sure yet why this needs to be done
   LOG_VARD(cookieCutMap->getElementCount());
   MapProjector::projectToWgs84(doughMap);
-  LOG_VARD(doughMap->getElementCount());
+  LOG_VART(doughMap->getElementCount());
   LOG_VART(MapProjector::toWkt(cookieCutMap->getProjection()));
   OsmMapWriterFactory::writeDebugMap(cookieCutMap, "cookie-cut");
 
@@ -889,13 +964,21 @@ void ChangesetReplacementCreator::_combineMaps(OsmMapPtr& map1, OsmMapPtr& map2,
 {
   LOG_VART(map1.get());
   LOG_VART(map2.get());
-  LOG_INFO("Combining maps: " << map1->getName() << " and " << map2->getName() << "...");
 
   MapProjector::projectToWgs84(map1);
   MapProjector::projectToWgs84(map2);   // not exactly sure yet why this needs to be done
 
+  if (map2->size() == 0)
+  {
+    LOG_DEBUG("Combined map size: " << map1->size());
+    return;
+  }
+
+  LOG_INFO("Combining maps: " << map1->getName() << " and " << map2->getName() << "...");
+
   map1->append(map2, throwOutDupes);
   LOG_VART(MapProjector::toWkt(map1->getProjection()));
+  LOG_DEBUG("Combined map size: " << map1->size());
 
   OsmMapWriterFactory::writeDebugMap(map1, debugFileName);
 }
@@ -929,6 +1012,7 @@ void ChangesetReplacementCreator::_conflate(OsmMapPtr& map, const bool lenientBo
   MapProjector::projectToWgs84(map);  // conflation works in planar
   LOG_VART(MapProjector::toWkt(map->getProjection()));
   OsmMapWriterFactory::writeDebugMap(map, "conflated");
+  LOG_DEBUG("Conflated map size: " << map->size());
 }
 
 void ChangesetReplacementCreator::_snapUnconnectedWays(
@@ -951,9 +1035,9 @@ void ChangesetReplacementCreator::_snapUnconnectedWays(
     QString::fromStdString(WayNodeCriterion::className()));
   lineSnapper.setWayToSnapCriterionClassName(typeCriterionClassName);
   lineSnapper.setWayToSnapToCriterionClassName(typeCriterionClassName);
-  LOG_DEBUG(lineSnapper.getInitStatusMessage());
+  LOG_STATUS("\t" << lineSnapper.getInitStatusMessage());
   lineSnapper.apply(map);
-  LOG_DEBUG(lineSnapper.getCompletedStatusMessage());
+  LOG_STATUS("\t" << lineSnapper.getCompletedStatusMessage());
 
   MapProjector::projectToWgs84(map);   // snapping works in planar
   LOG_VART(MapProjector::toWkt(map->getProjection()));
@@ -985,15 +1069,21 @@ void ChangesetReplacementCreator::_cropMapForChangesetDerivation(
   OsmMapPtr& map, const geos::geom::Envelope& bounds, const bool keepEntireFeaturesCrossingBounds,
   const bool keepOnlyFeaturesInsideBounds, const bool isLinearMap, const QString& debugFileName)
 {
+  if (map->size() == 0)
+  {
+    LOG_DEBUG("Skipping cropping empty map: " << map->getName() << "...");
+    return;
+  }
+
   LOG_INFO("Cropping map: " << map->getName() << " for changeset derivation...");
   LOG_VART(MapProjector::toWkt(map->getProjection()));
 
   MapCropper cropper(bounds);
   cropper.setKeepEntireFeaturesCrossingBounds(keepEntireFeaturesCrossingBounds);
   cropper.setKeepOnlyFeaturesInsideBounds(keepOnlyFeaturesInsideBounds);
-  LOG_DEBUG(cropper.getInitStatusMessage());
+  LOG_STATUS("\t" << cropper.getInitStatusMessage());
   cropper.apply(map);
-  LOG_DEBUG(cropper.getCompletedStatusMessage());
+  LOG_STATUS("\t" << cropper.getCompletedStatusMessage());
 
   // Clean up straggling nodes in that are the result of cropping. Its ok to ignore info tags when
   // dealing with only linear features, as all nodes in the data being conflated should be way nodes
@@ -1003,6 +1093,7 @@ void ChangesetReplacementCreator::_cropMapForChangesetDerivation(
 
   LOG_VART(MapProjector::toWkt(map->getProjection()));
   OsmMapWriterFactory::writeDebugMap(map, debugFileName);
+  LOG_DEBUG("Cropped map: " << map->getName() << " size: " << map->size());
 }
 
 void ChangesetReplacementCreator::_removeUnsnappedImmediatelyConnectedOutOfBoundsWays(
@@ -1011,6 +1102,7 @@ void ChangesetReplacementCreator::_removeUnsnappedImmediatelyConnectedOutOfBound
   LOG_INFO(
     "Removing any immediately connected ways that were not previously snapped in: " <<
     map->getName() << "...");
+
   RemoveElementsVisitor removeVis;
   removeVis.addCriterion(ElementCriterionPtr(new WayCriterion()));
   removeVis.addCriterion(
@@ -1022,9 +1114,10 @@ void ChangesetReplacementCreator::_removeUnsnappedImmediatelyConnectedOutOfBound
           new TagCriterion(MetadataTags::HootSnapped(), "snapped_way")))));
   removeVis.setChainCriteria(true);
   removeVis.setRecursive(true);
-  LOG_DEBUG(removeVis.getInitStatusMessage());
+  LOG_STATUS("\t" << removeVis.getInitStatusMessage());
   map->visitRw(removeVis);
-  LOG_DEBUG(removeVis.getCompletedStatusMessage());
+  LOG_STATUS("\t" << removeVis.getCompletedStatusMessage());
+
   LOG_VART(MapProjector::toWkt(map->getProjection()));
   OsmMapWriterFactory::writeDebugMap(map, map->getName() + "-unsnapped-removed");
 }
@@ -1032,6 +1125,11 @@ void ChangesetReplacementCreator::_removeUnsnappedImmediatelyConnectedOutOfBound
 void ChangesetReplacementCreator::_excludeFeaturesFromChangesetDeletion(OsmMapPtr& map,
                                                                         const QString& boundsStr)
 {
+  if (map->size() == 0)
+  {
+    return;
+  }
+
   LOG_INFO(
     "Marking reference features in: " << map->getName() << " for exclusion from deletion...");
 
@@ -1043,9 +1141,9 @@ void ChangesetReplacementCreator::_excludeFeaturesFromChangesetDeletion(OsmMapPt
     new ChainCriterion(std::shared_ptr<WayCriterion>(new WayCriterion()), notInBoundsCrit));
 
   RecursiveSetTagValueOp tagSetter(MetadataTags::HootChangeExcludeDelete(), "yes", elementCrit);
-  LOG_DEBUG(tagSetter.getInitStatusMessage());
+  LOG_STATUS("\t" << tagSetter.getInitStatusMessage());
   tagSetter.apply(map);
-  LOG_DEBUG(tagSetter.getCompletedStatusMessage());
+  LOG_STATUS("\t" << tagSetter.getCompletedStatusMessage());
 
   LOG_VART(MapProjector::toWkt(map->getProjection()));
   OsmMapWriterFactory::writeDebugMap(map, map->getName() + "-after-delete-exclude-tags");
@@ -1066,7 +1164,11 @@ void ChangesetReplacementCreator::_setGlobalOpts(const QString& boundsStr)
   conf().set(ConfigOptions::getConvertBoundingBoxKey(), boundsStr);
   // 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);
+  conf().set(
+    ConfigOptions::getConvertBoundingBoxTagImmediatelyConnectedOutOfBoundsWaysKey(),
+    _tagOobConnectedWays);
+  // will have to see if setting this to false causes problems in the future...
+  conf().set(ConfigOptions::getConvertRequireAreaForPolygonKey(), false);
   // turn on for testing only
   //conf().set(ConfigOptions::getDebugMapsWriteKey(), true);
 
@@ -1143,7 +1245,7 @@ void ChangesetReplacementCreator::_parseConfigOpts(
       // 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.
 
-      LOG_VARD(conf().getList(ConfigOptions::getConflatePostOpsKey()));
+      LOG_VART(conf().getList(ConfigOptions::getConflatePostOpsKey()));
       QStringList conflatePostOps = conf().getList(ConfigOptions::getConflatePostOpsKey());
       conflatePostOps.removeAll(QString::fromStdString(WayJoinerOp::className()));
       const int indexOfTagTruncater =
@@ -1193,19 +1295,19 @@ void ChangesetReplacementCreator::_parseConfigOpts(
     ConfigOptions::getChangesetReplacementAllowDeletingReferenceFeaturesOutsideBoundsKey(),
     _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);
+  LOG_VART(_boundsOpts.loadRefKeepEntireCrossingBounds);
+  LOG_VART(_boundsOpts.loadRefKeepOnlyInsideBounds);
+  LOG_VART(_boundsOpts.loadRefKeepImmediateConnectedWaysOutsideBounds);
+  LOG_VART(_boundsOpts.loadSecKeepEntireCrossingBounds);
+  LOG_VART(_boundsOpts.loadSecKeepOnlyInsideBounds);
+  LOG_VART(_boundsOpts.cookieCutKeepEntireCrossingBounds);
+  LOG_VART(_boundsOpts.cookieCutKeepOnlyInsideBounds);
+  LOG_VART(_boundsOpts.changesetRefKeepEntireCrossingBounds);
+  LOG_VART(_boundsOpts.changesetRefKeepOnlyInsideBounds);
+  LOG_VART(_boundsOpts.changesetSecKeepEntireCrossingBounds);
+  LOG_VART(_boundsOpts.changesetSecKeepOnlyInsideBounds);
+  LOG_VART(_boundsOpts.changesetAllowDeletingRefOutsideBounds);
+  LOG_VART(_boundsOpts.inBoundsStrict);
 }
 
 }
Clone this wiki locally