Skip to content

v0.2.55..v0.2.56 changeset AlphaShapeGenerator.cpp

Garret Voltz edited this page Aug 14, 2020 · 3 revisions
diff --git a/hoot-core/src/main/cpp/hoot/core/algorithms/alpha-shape/AlphaShapeGenerator.cpp b/hoot-core/src/main/cpp/hoot/core/algorithms/alpha-shape/AlphaShapeGenerator.cpp
index d4d9ea8..f4b0149 100644
--- a/hoot-core/src/main/cpp/hoot/core/algorithms/alpha-shape/AlphaShapeGenerator.cpp
+++ b/hoot-core/src/main/cpp/hoot/core/algorithms/alpha-shape/AlphaShapeGenerator.cpp
@@ -47,6 +47,7 @@ namespace hoot
 AlphaShapeGenerator::AlphaShapeGenerator(const double alpha, const double buffer) :
 _alpha(alpha),
 _buffer(buffer),
+_manuallyCoverSmallPointClusters(true),
 _retryOnTooSmallInitialAlpha(true),
 _maxTries(1)
 {
@@ -65,20 +66,20 @@ OsmMapPtr AlphaShapeGenerator::generateMap(OsmMapPtr inputMap)
   OsmMapWriterFactory::writeDebugMap(inputMap, "alpha-shape-input-map");
 
   std::shared_ptr<Geometry> cutterShape = generateGeometry(inputMap);
-
   if (cutterShape->getArea() == 0.0)
   {
     // would rather this be thrown than a warning logged, as the warning may go unoticed by
     // clients who are expecting the alpha shape to be generated
     throw HootException("Alpha Shape area is zero. Try increasing the buffer size and/or alpha.");
   }
+  OsmMapWriterFactory::writeDebugMap(cutterShape, inputMap->getProjection(), "cutter-shape-map");
 
   OsmMapPtr result;
-
   result.reset(new OsmMap(inputMap->getProjection()));
   result->appendSource(inputMap->getSource());
   // add the resulting alpha shape for debugging.
   GeometryConverter(result).convertGeometryToElement(cutterShape.get(), Status::Invalid, -1);
+  OsmMapWriterFactory::writeDebugMap(result, "alpha-shape-result-map");
 
   const RelationMap& rm = result->getRelations();
   for (RelationMap::const_iterator it = rm.begin(); it != rm.end(); ++it)
@@ -95,8 +96,6 @@ OsmMapPtr AlphaShapeGenerator::generateMap(OsmMapPtr inputMap)
 
 std::shared_ptr<Geometry> AlphaShapeGenerator::generateGeometry(OsmMapPtr inputMap)
 {
-  LOG_TRACE("Generating alpha shape geometry...");
-
   MapProjector::projectToPlanar(inputMap);
   LOG_VART(MapProjector::toWkt(inputMap->getProjection()));
 
@@ -118,8 +117,12 @@ std::shared_ptr<Geometry> AlphaShapeGenerator::generateGeometry(OsmMapPtr inputM
   std::shared_ptr<Geometry> cutterShape;
 
   int numTries = 0;
-  while (numTries <= _maxTries)
+  while (numTries < _maxTries)
   {
+    LOG_DEBUG(
+      "Generating alpha shape geometry with alpha: " << _alpha << "; attempt " << (numTries + 1) <<
+      " / " << _maxTries << "...");
+
     AlphaShape alphaShape(_alpha);
     alphaShape.insert(points);
     try
@@ -150,8 +153,47 @@ std::shared_ptr<Geometry> AlphaShapeGenerator::generateGeometry(OsmMapPtr inputM
     cutterShape.reset(GeometryFactory::getDefaultInstance()->createEmptyGeometry());
   }
   cutterShape.reset(cutterShape->buffer(_buffer));
+  //OsmMapWriterFactory::writeDebugMap(cutterShape, inputMap->getProjection(), "cutter-shape-map");
+
+  // See _coverStragglers description. This is an add-on behavior that is separate from the Alpha
+  // Shape algorithm itself.
+  if (_manuallyCoverSmallPointClusters)
+  {
+    _coverStragglers(cutterShape, inputMap);
+    //OsmMapWriterFactory::writeDebugMap(geometry, spatRef, "alpha-shape-after-covering-stragglers");
+  }
 
   return cutterShape;
 }
 
+void AlphaShapeGenerator::_coverStragglers(std::shared_ptr<Geometry>& geometry,
+                                           const ConstOsmMapPtr& map)
+{
+  LOG_DEBUG("Covering stragglers...");
+
+  // Pretty simple...go through and find any point that wasn't covered by the Alpha Shape and draw
+  // a buffer around it.
+
+  int addedPointCtr = 0;
+  const NodeMap& nodes = map->getNodes();
+  for (NodeMap::const_iterator it = nodes.begin(); it != nodes.end(); ++it)
+  {
+    NodePtr node = it->second;
+    std::shared_ptr<geos::geom::Geometry> point(
+      GeometryFactory::getDefaultInstance()->createPoint(
+        geos::geom::Coordinate(node->getX(), node->getY())));
+    if (!geometry->contains(point.get()))
+    {
+      LOG_TRACE(
+        "Point " << point->toString() << " not covered by alpha shape. Buffering and adding it...");
+      point.reset(point->buffer(_buffer));
+      geometry.reset(geometry->Union(point.get()));
+      addedPointCtr++;
+      LOG_VART(geometry->getArea());
+    }
+  }
+
+  LOG_DEBUG("Added " << addedPointCtr << " point stragglers to alpha shape.");
+}
+
 }
Clone this wiki locally