[geos-commits] r2347 - trunk/source/operation/buffer
svn_geos at osgeo.org
svn_geos at osgeo.org
Fri Apr 10 16:22:27 EDT 2009
Author: strk
Date: 2009-04-10 16:22:27 -0400 (Fri, 10 Apr 2009)
New Revision: 2347
Added:
trunk/source/operation/buffer/BufferInputLineSimplifier.cpp
trunk/source/operation/buffer/BufferInputLineSimplifier.h
Modified:
trunk/source/operation/buffer/Makefile.am
Log:
Port BufferInputLineSimplifier from JTS 1.9
Added: trunk/source/operation/buffer/BufferInputLineSimplifier.cpp
===================================================================
--- trunk/source/operation/buffer/BufferInputLineSimplifier.cpp (rev 0)
+++ trunk/source/operation/buffer/BufferInputLineSimplifier.cpp 2009-04-10 20:22:27 UTC (rev 2347)
@@ -0,0 +1,224 @@
+/**********************************************************************
+ * $Id$
+ *
+ * GEOS - Geometry Engine Open Source
+ * http://geos.refractions.net
+ *
+ * Copyright (C) 2009 Sandro Santilli <strk at keybit.net>
+ *
+ * This is free software; you can redistribute and/or modify it under
+ * the terms of the GNU Lesser General Public Licence as published
+ * by the Free Software Foundation.
+ * See the COPYING file for more information.
+ *
+ **********************************************************************
+ *
+ * Last port: operation/buffer/BufferInputLineSimplifier.java rev 1.6 (JTS-1.9)
+ *
+ **********************************************************************/
+
+#include "BufferInputLineSimplifier.h"
+#include <geos/geom/CoordinateSequence.h> // for inlines
+#include <geos/geom/CoordinateArraySequence.h> // for constructing the return
+#include <geos/algorithm/CGAlgorithms.h> // for use
+
+//#include <geos/operation/buffer/RightmostEdgeFinder.h>
+//#include <geos/geomgraph/DirectedEdge.h>
+//#include <geos/geomgraph/DirectedEdgeStar.h>
+//#include <geos/geomgraph/Position.h>
+//#include <geos/geomgraph/Node.h>
+//#include <geos/geomgraph/Edge.h>
+
+#include <memory>
+#include <cmath>
+#include <vector>
+
+//#include <cassert>
+
+using namespace geos::algorithm; // CGAlgorithms
+using namespace geos::geom;
+//using namespace geos::geomgraph; // DirectedEdge, Position
+
+namespace geos {
+namespace operation { // geos.operation
+namespace buffer { // geos.operation.buffer
+
+BufferInputLineSimplifier::BufferInputLineSimplifier(
+ const geom::CoordinateSequence& input)
+ :
+ inputLine(input),
+ angleOrientation(CGAlgorithms::COUNTERCLOCKWISE)
+{}
+
+/*public static*/
+std::auto_ptr<geom::CoordinateSequence>
+BufferInputLineSimplifier::simplify(const geom::CoordinateSequence& inputLine,
+ double distanceTol)
+{
+ BufferInputLineSimplifier simp(inputLine);
+ return simp.simplify(distanceTol);
+}
+
+/* public */
+std::auto_ptr<geom::CoordinateSequence>
+BufferInputLineSimplifier::simplify(double nDistanceTol)
+{
+ distanceTol = fabs(nDistanceTol);
+ if (distanceTol < 0)
+ angleOrientation = CGAlgorithms::CLOCKWISE;
+
+ // rely on fact that boolean array is filled with false value
+ static const int startValue = INIT;
+ isDeleted.assign(inputLine.size(), startValue);
+
+ bool isChanged = false;
+ do {
+ isChanged = deleteShallowConcavities();
+ } while (isChanged);
+
+ return collapseLine();
+}
+
+/* private */
+bool
+BufferInputLineSimplifier::deleteShallowConcavities()
+{
+ /**
+ * Do not simplify end line segments of the line string.
+ * This ensures that end caps are generated consistently.
+ */
+ unsigned int index = 1;
+ //int maxIndex = inputLine.size() - 1;
+
+ unsigned int midIndex = findNextNonDeletedIndex(index);
+ unsigned int lastIndex = findNextNonDeletedIndex(midIndex);
+
+ bool isChanged = false;
+ while (lastIndex < inputLine.size())
+ {
+ // test triple for shallow concavity
+ bool isMiddleVertexDeleted = false;
+ if (isDeletable(index, midIndex, lastIndex,
+ distanceTol))
+ {
+ isDeleted[midIndex] = DELETE;
+ isMiddleVertexDeleted = true;
+ isChanged = true;
+ }
+ // move simplification window forward
+ if (isMiddleVertexDeleted)
+ index = lastIndex;
+ else
+ index = midIndex;
+
+ midIndex = findNextNonDeletedIndex(index);
+ lastIndex = findNextNonDeletedIndex(midIndex);
+ }
+ return isChanged;
+}
+
+/* private */
+unsigned int
+BufferInputLineSimplifier::findNextNonDeletedIndex(unsigned int index) const
+{
+ unsigned int next = index + 1;
+ const unsigned int len = inputLine.size();
+ while (next < len && isDeleted[next] == DELETE)
+ next++;
+ return next;
+}
+
+/* private */
+std::auto_ptr<geom::CoordinateSequence>
+BufferInputLineSimplifier::collapseLine() const
+{
+ std::auto_ptr<geom::CoordinateSequence> coordList(
+ new CoordinateArraySequence());
+
+ for (size_t i=0, n=inputLine.size(); i<n; ++i)
+ {
+ if (isDeleted[i] != DELETE)
+ coordList->add(inputLine[i]);
+ }
+
+ return coordList;
+}
+
+/* private */
+bool
+BufferInputLineSimplifier::isDeletable(int i0, int i1, int i2,
+ double distanceTol) const
+{
+ const Coordinate& p0 = inputLine[i0];
+ const Coordinate& p1 = inputLine[i1];
+ const Coordinate& p2 = inputLine[i2];
+
+ if (! isConcave(p0, p1, p2)) return false;
+ if (! isShallow(p0, p1, p2, distanceTol)) return false;
+
+ // MD - don't use this heuristic - it's too restricting
+ // if (p0.distance(p2) > distanceTol) return false;
+
+ return isShallowSampled(p0, p1, i0, i2, distanceTol);
+}
+
+/* private */
+bool
+BufferInputLineSimplifier::isShallowConcavity(const geom::Coordinate& p0,
+ const geom::Coordinate& p1,
+ const geom::Coordinate& p2,
+ double distanceTol) const
+{
+ int orientation = CGAlgorithms::computeOrientation(p0, p1, p2);
+ bool isAngleToSimplify = (orientation == angleOrientation);
+ if (! isAngleToSimplify)
+ return false;
+
+ double dist = CGAlgorithms::distancePointLine(p1, p0, p2);
+ return dist < distanceTol;
+}
+
+/* private */
+bool
+BufferInputLineSimplifier::isShallowSampled(const geom::Coordinate& p0,
+ const geom::Coordinate& p2,
+ int i0, int i2,
+ double distanceTol) const
+{
+ // check every n'th point to see if it is within tolerance
+ int inc = (i2 - i0) / NUM_PTS_TO_CHECK;
+ if (inc <= 0) inc = 1;
+
+ for (int i = i0; i < i2; i += inc) {
+ if (! isShallow(p0, p2, inputLine[i], distanceTol))
+ return false;
+ }
+ return true;
+}
+
+/* private */
+bool
+BufferInputLineSimplifier::isShallow(const geom::Coordinate& p0,
+ const geom::Coordinate& p1,
+ const geom::Coordinate& p2,
+ double distanceTol) const
+{
+ double dist = CGAlgorithms::distancePointLine(p1, p0, p2);
+ return dist < distanceTol;
+}
+
+/* private */
+bool
+BufferInputLineSimplifier::isConcave(const geom::Coordinate& p0,
+ const geom::Coordinate& p1,
+ const geom::Coordinate& p2) const
+{
+ int orientation = CGAlgorithms::computeOrientation(p0, p1, p2);
+ bool isConcave = (orientation == angleOrientation);
+ return isConcave;
+}
+
+} // namespace geos.operation.buffer
+} // namespace geos.operation
+} // namespace geos
+
Added: trunk/source/operation/buffer/BufferInputLineSimplifier.h
===================================================================
--- trunk/source/operation/buffer/BufferInputLineSimplifier.h (rev 0)
+++ trunk/source/operation/buffer/BufferInputLineSimplifier.h 2009-04-10 20:22:27 UTC (rev 2347)
@@ -0,0 +1,185 @@
+/**********************************************************************
+ * $Id$
+ *
+ * GEOS - Geometry Engine Open Source
+ * http://geos.refractions.net
+ *
+ * Copyright (C) 2009 Sandro Santilli <strk at keybit.net>
+ *
+ * This is free software; you can redistribute and/or modify it under
+ * the terms of the GNU Lesser General Public Licence as published
+ * by the Free Software Foundation.
+ * See the COPYING file for more information.
+ *
+ **********************************************************************
+ *
+ * Last port: operation/buffer/BufferInputLineSimplifier.java rev 1.6 (JTS-1.9)
+ *
+ **********************************************************************/
+
+#ifndef GEOS_OP_BUFFER_BUFFERINPUTLINESIMPLIFIER_H
+#define GEOS_OP_BUFFER_BUFFERINPUTLINESIMPLIFIER_H
+
+
+#include <geos/algorithm/CGAlgorithms.h> // for enum
+
+#include <memory>
+#include <vector> // for composition
+
+
+// Forward declarations
+namespace geos {
+ namespace geom {
+ class CoordinateSequence;
+ //class PrecisionModel;
+ }
+}
+
+namespace geos {
+namespace operation { // geos.operation
+namespace buffer { // geos.operation.buffer
+
+/** \brief
+ * Simplifies a buffer input line to
+ * remove concavities with shallow depth.
+ *
+ * The most important benefit of doing this
+ * is to reduce the number of points and the complexity of
+ * shape which will be buffered.
+ * It also reduces the risk of gores created by
+ * the quantized fillet arcs (although this issue
+ * should be eliminated in any case by the
+ * offset curve generation logic).
+ *
+ * A key aspect of the simplification is that it
+ * affects inside (concave or inward) corners only.
+ * Convex (outward) corners are preserved, since they
+ * are required to ensure that the eventual buffer curve
+ * lies at the correct distance from the input geometry.
+ *
+ * Another important heuristic used is that the end segments
+ * of the input are never simplified. This ensures that
+ * the client buffer code is able to generate end caps consistently.
+ *
+ * No attempt is made to avoid self-intersections in the output.
+ * This is acceptable for use for generating a buffer offset curve,
+ * but means that this cannot be used as a general-purpose polygon
+ * simplification algorithm.
+ *
+ * @author Martin Davis
+ *
+ */
+class BufferInputLineSimplifier
+{
+
+public:
+
+ /**
+ * Simplify the input coordinate list.
+ *
+ * If the distance tolerance is positive,
+ * concavities on the LEFT side of the line are simplified.
+ * If the supplied distance tolerance is negative,
+ * concavities on the RIGHT side of the line are simplified.
+ *
+ * @param inputLine the coordinate sequence to simplify
+ * @param distanceTol simplification distance tolerance to use
+ * @return a simplified version of the coordinate sequence
+ */
+ static std::auto_ptr<geom::CoordinateSequence> simplify(
+ const geom::CoordinateSequence& inputLine, double distanceTol);
+
+ BufferInputLineSimplifier(const geom::CoordinateSequence& input);
+
+ /**
+ * Simplify the input coordinate list.
+ * If the distance tolerance is positive,
+ * concavities on the LEFT side of the line are simplified.
+ * If the supplied distance tolerance is negative,
+ * concavities on the RIGHT side of the line are simplified.
+ *
+ * @param distanceTol simplification distance tolerance to use
+ * @return the simplified coordinate list
+ */
+ std::auto_ptr<geom::CoordinateSequence> simplify(double distanceTol);
+
+private:
+
+ /**
+ * Uses a sliding window containing 3 vertices to detect shallow angles
+ * in which the middle vertex can be deleted, since it does not
+ * affect the shape of the resulting buffer in a significant way.
+ * @return
+ */
+ bool deleteShallowConcavities();
+
+ /**
+ * Finds the next non-deleted index,
+ * or the end of the point array if none
+ *
+ * @param index
+ * @return the next non-deleted index, if any
+ * @return inputLine.size() if there are no more non-deleted indices
+ */
+ unsigned int findNextNonDeletedIndex(unsigned int index) const;
+
+ std::auto_ptr<geom::CoordinateSequence> collapseLine() const;
+
+ bool isDeletable(int i0, int i1, int i2, double distanceTol) const;
+
+ bool isShallowConcavity(const geom::Coordinate& p0,
+ const geom::Coordinate& p1,
+ const geom::Coordinate& p2,
+ double distanceTol) const;
+
+ /**
+ * Checks for shallowness over a sample of points in the given section.
+ *
+ * This helps prevents the siplification from incrementally
+ * "skipping" over points which are in fact non-shallow.
+ *
+ * @param p0 start coordinate of section
+ * @param p2 end coordinate of section
+ * @param i0 start index of section
+ * @param i2 end index of section
+ * @param distanceTol distance tolerance
+ * @return
+ */
+ bool isShallowSampled(const geom::Coordinate& p0,
+ const geom::Coordinate& p2,
+ int i0, int i2, double distanceTol) const;
+
+ bool isShallow(const geom::Coordinate& p0,
+ const geom::Coordinate& p1,
+ const geom::Coordinate& p2,
+ double distanceTol) const;
+
+ bool isConcave(const geom::Coordinate& p0,
+ const geom::Coordinate& p1,
+ const geom::Coordinate& p2) const;
+
+ static const int NUM_PTS_TO_CHECK = 10;
+
+ static const int INIT = 0;
+ static const int DELETE = 1;
+ static const int KEEP = 1;
+
+ const geom::CoordinateSequence& inputLine;
+ double distanceTol;
+ std::vector<int> isDeleted;
+
+ int angleOrientation;
+};
+
+
+} // namespace geos.operation.buffer
+} // namespace geos.operation
+} // namespace geos
+
+
+#endif // ndef GEOS_OP_BUFFER_BUFFERINPUTLINESIMPLIFIER_H
+
+/**********************************************************************
+ * $Log$
+ **********************************************************************/
+
Modified: trunk/source/operation/buffer/Makefile.am
===================================================================
--- trunk/source/operation/buffer/Makefile.am 2009-04-10 15:15:35 UTC (rev 2346)
+++ trunk/source/operation/buffer/Makefile.am 2009-04-10 20:22:27 UTC (rev 2347)
@@ -6,6 +6,8 @@
libopbuffer_la_SOURCES = \
BufferBuilder.cpp \
+ BufferInputLineSimplifier.cpp \
+ BufferInputLineSimplifier.h \
BufferOp.cpp \
BufferParameters.cpp \
BufferSubgraph.cpp \
More information about the geos-commits
mailing list