[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