[geos-commits] r2458 - in trunk/source: headers/geos/operation/overlay headers/geos/operation/overlay/snap operation/overlay operation/overlay/snap

svn_geos at osgeo.org svn_geos at osgeo.org
Sat May 2 07:01:07 EDT 2009


Author: strk
Date: 2009-05-02 07:01:07 -0400 (Sat, 02 May 2009)
New Revision: 2458

Added:
   trunk/source/headers/geos/operation/overlay/snap/
   trunk/source/headers/geos/operation/overlay/snap/LineStringSnapper.h
   trunk/source/operation/overlay/snap/
   trunk/source/operation/overlay/snap/LineStringSnapper.cpp
Modified:
   trunk/source/headers/geos/operation/overlay/Makefile.am
   trunk/source/operation/overlay/Makefile.am
Log:
Port overlay.snap.LineStringSnapper from JTS-1.10


Modified: trunk/source/headers/geos/operation/overlay/Makefile.am
===================================================================
--- trunk/source/headers/geos/operation/overlay/Makefile.am	2009-05-02 10:59:19 UTC (rev 2457)
+++ trunk/source/headers/geos/operation/overlay/Makefile.am	2009-05-02 11:01:07 UTC (rev 2458)
@@ -23,4 +23,5 @@
 	OverlayNodeFactory.h	\
 	OverlayResultValidator.h \
 	PointBuilder.h		\
-	PolygonBuilder.h
+	PolygonBuilder.h	\
+	snap/LineStringSnapper.h

Added: trunk/source/headers/geos/operation/overlay/snap/LineStringSnapper.h
===================================================================
--- trunk/source/headers/geos/operation/overlay/snap/LineStringSnapper.h	                        (rev 0)
+++ trunk/source/headers/geos/operation/overlay/snap/LineStringSnapper.h	2009-05-02 11:01:07 UTC (rev 2458)
@@ -0,0 +1,167 @@
+/**********************************************************************
+ * $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/overlay/snap/LineStringSnapper.java rev 1.5 (JTS-1.10)
+ *
+ **********************************************************************/
+
+#ifndef GEOS_OP_OVERLAY_SNAP_LINESTRINGSNAPPER_H
+#define GEOS_OP_OVERLAY_SNAP_LINESTRINGSNAPPER_H
+
+#include <geos/geom/LineSegment.h> // for composition
+#include <geos/geom/LineString.h> // for inlined ctor
+
+//#include <vector>
+#include <memory> // for auto_ptr
+
+// Forward declarations
+namespace geos {
+	namespace geom {
+		class CoordinateSequence;
+	}
+}
+
+namespace geos {
+namespace operation { // geos::operation
+namespace overlay { // geos::operation::overlay
+namespace snap { // geos::operation::overlay::snap
+
+/** \brief
+ * Snaps the vertices and segments of a LineString to a set
+ * of target snap vertices.
+ *
+ * A snapping distance tolerance is used to control where snapping is performed.
+ *
+ */
+class LineStringSnapper {
+
+public:
+
+	/**
+	 * Creates a new snapper using the points in the given LineString
+	 * as source snap points.
+	 *
+	 * @param srcLline a LineString to snap
+	 * @param nSnapTolerance the snap tolerance to use
+	 */
+	LineStringSnapper(const geom::LineString& srcLline,
+	                  double nSnapTolerance)
+		:
+		snapTolerance(nSnapTolerance),
+		srcPts(*(srcLline.getCoordinatesRO())),
+		seg(),
+		isClosed(false)
+	{
+	}
+
+	/**
+	 * Creates a new snapper using the given points
+	 * as source points to be snapped.
+	 *
+	 * @param nSrcPts the points to snap
+	 * @param nSnapTolerance the snap tolerance to use
+	 */
+	LineStringSnapper(const geom::CoordinateSequence& nSrcPts,
+	                  double nSnapTolerance)
+		:
+		snapTolerance(nSnapTolerance),
+		srcPts(nSrcPts),
+		seg(),
+		isClosed(false)
+	{
+	}
+
+	/**
+	 * Snaps the vertices and segments of the source points
+	 * to the given set of target snap points.
+	 *
+	 * @param snapPts the vertices to snap to
+	 * @return a sequence formed by the snapped points
+	 */
+	std::auto_ptr<geom::CoordinateSequence> snapTo(
+	                 const geom::CoordinateSequence& snapPts);
+
+private:
+
+	/**
+	 * Snap source vertices to vertices in the target.
+	 *
+	 * @param srcCoords the points to snap
+	 * @param snapPts the points to snap to
+	 */
+	void snapVertices(geom::CoordinateSequence& srcCoords,
+	                  const geom::CoordinateSequence& snapPts);
+
+
+	// return pointer into snapPts memory, or null
+	const geom::Coordinate*
+	findSnapForVertex(const geom::Coordinate& pt,
+	                  const geom::CoordinateSequence& snapPts);
+
+	/**
+	 * Snap segments of the source to nearby snap vertices.
+	 * Source segments are "cracked" at a snap vertex, and further
+	 * snapping takes place on the modified list of segments.
+	 * For each distinct snap vertex, at most one source segment
+	 * is snapped to.  This prevents "cracking" multiple segments
+	 * at the same point, which would almost certainly cause the result
+	 * to be invalid.
+	 *
+	 * @param srcCoords
+	 * @param snapPts
+	 */
+	void snapSegments(geom::CoordinateSequence& srcCoords,
+	                  const geom::CoordinateSequence& snapPts);
+
+	/** \brief
+	 * Finds a src segment which snaps to (is close to)
+	 * the given snap point.
+	 *
+	 * Only one segment is determined - this is to prevent                           * snapping to multiple segments, which would almost certainly
+	 * cause invalid geometry to be created.
+	 * (The heuristic approach of snapping is really only appropriate when
+	 * snap pts snap to a unique spot on the src geometry.)
+	 *
+	 * @param snapPt the point to snap to
+	 * @param srcCoords the source segment coordinates
+	 * @return the index of the snapped segment
+	 * @return -1 if no segment snaps
+	 */
+	int findSegmentIndexToSnap(const geom::Coordinate& snapPt,
+	                      const geom::CoordinateSequence& srcCoords);
+ 
+ 
+
+	double snapTolerance;
+
+	const geom::CoordinateSequence& srcPts;
+
+	geom::LineSegment seg; // for reuse during snapping
+
+	bool isClosed;
+
+};
+
+} // namespace geos::operation::overlay::snap
+} // namespace geos::operation::overlay
+} // namespace geos::operation
+} // namespace geos
+
+#endif // ndef GEOS_OP_OVERLAY_SNAP_LINESTRINGSNAPPER_H
+
+/**********************************************************************
+ * $Log$
+ **********************************************************************/
+

Modified: trunk/source/operation/overlay/Makefile.am
===================================================================
--- trunk/source/operation/overlay/Makefile.am	2009-05-02 10:59:19 UTC (rev 2457)
+++ trunk/source/operation/overlay/Makefile.am	2009-05-02 11:01:07 UTC (rev 2458)
@@ -17,7 +17,8 @@
 	OverlayOp.cpp \
 	OverlayResultValidator.cpp \
 	PointBuilder.cpp \
-	PolygonBuilder.cpp 
+	PolygonBuilder.cpp \
+	snap/LineStringSnapper.cpp
 
 libopoverlay_la_LIBADD = 
 

Added: trunk/source/operation/overlay/snap/LineStringSnapper.cpp
===================================================================
--- trunk/source/operation/overlay/snap/LineStringSnapper.cpp	                        (rev 0)
+++ trunk/source/operation/overlay/snap/LineStringSnapper.cpp	2009-05-02 11:01:07 UTC (rev 2458)
@@ -0,0 +1,143 @@
+/**********************************************************************
+ * $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/overlay/snap/LineStringSnapper.java rev 1.5 (JTS-1.10)
+ *
+ **********************************************************************/
+
+#include <geos/operation/overlay/snap/LineStringSnapper.h>
+#include <geos/geom/CoordinateSequence.h> 
+
+#include <cassert>
+#include <limits> // for numeric_limits
+#include <memory> // for auto_ptr
+
+#ifndef GEOS_DEBUG
+#define GEOS_DEBUG 0
+#endif
+
+using namespace std;
+using namespace geos::geom;
+
+namespace geos {
+namespace operation { // geos.operation
+namespace overlay { // geos.operation.overlay
+namespace snap { // geos.operation.overlay.snap
+
+/*public*/
+auto_ptr<CoordinateSequence>
+LineStringSnapper::snapTo(const CoordinateSequence& snapPts)
+{
+	auto_ptr<CoordinateSequence> coordList(snapPts.clone());
+
+	snapVertices(*coordList, snapPts);
+	snapSegments(*coordList, snapPts);
+
+	return coordList;
+} 
+
+/*private*/
+void
+LineStringSnapper::snapVertices(geom::CoordinateSequence& srcCoords,
+                                const geom::CoordinateSequence& snapPts)
+{
+    // try snapping vertices
+    // assume src list has a closing point (is a ring)
+    for (int i = 0; i < srcCoords.size() - 1; i++) {
+      const Coordinate& srcPt = srcCoords.getAt(i);
+      const Coordinate* snapVert = findSnapForVertex(srcPt, snapPts);
+      if (snapVert != NULL) {
+        // update src with snap pt
+        srcCoords.setAt(*snapVert, i);
+        // keep final closing point in synch (rings only)
+        if (i == 0 && isClosed)
+          srcCoords.setAt(*snapVert, srcCoords.size() - 1);
+      }
+    }
+}
+
+/*private*/
+const geom::Coordinate*
+LineStringSnapper::findSnapForVertex(const geom::Coordinate& pt,
+	                  const geom::CoordinateSequence& snapPts)
+{
+    for (int i = 0; i < snapPts.size(); i++) {
+      // if point is already equal to a src pt, don't snap
+      if (pt.equals2D(snapPts[i]))
+        return 0;
+      if (pt.distance(snapPts[i]) < snapTolerance)
+        return &(snapPts[i]);
+    }
+    return 0;
+}
+
+/*private*/
+void
+LineStringSnapper::snapSegments(geom::CoordinateSequence& srcCoords,
+	                  const geom::CoordinateSequence& snapPts)
+{
+    int distinctPtCount = snapPts.size();
+
+    // check for duplicate snap pts.
+    // Need to do this better - need to check all points for dups (using a Set?)
+    if (snapPts[0].equals2D(snapPts[snapPts.size() - 1]))
+        distinctPtCount = snapPts.size() - 1;
+
+    for (int i = 0; i < distinctPtCount; i++) {
+      const Coordinate& snapPt = snapPts[i];
+      int index = findSegmentIndexToSnap(snapPt, srcCoords);
+      /**
+       * If a segment to snap to was found, "crack" it at the snap pt.
+       * The new pt is inserted immediately into the src segment list,
+       * so that subsequent snapping will take place on the latest segments.
+       * Duplicate points are not added.
+       */
+      if (index >= 0) {
+        srcCoords.add(index + 1, snapPt, false);
+      }
+    }
+}
+
+/*private*/
+int
+LineStringSnapper::findSegmentIndexToSnap(const geom::Coordinate& snapPt,
+	                      const geom::CoordinateSequence& srcCoords)
+{
+    double minDist = numeric_limits<double>::max();
+    int snapIndex = -1;
+    for (int i = 0; i < srcCoords.size() - 1; i++) {
+      seg.p0 = srcCoords.getAt(i);
+      seg.p1 = srcCoords.getAt(i + 1);
+
+      /**
+       * If the snap pt is already in the src list, don't snap
+       */
+      if (seg.p0.equals2D(snapPt) || seg.p1.equals2D(snapPt))
+        return -1;
+
+      double dist = seg.distance(snapPt);
+      if (dist < snapTolerance && dist < minDist) {
+        minDist = dist;
+        snapIndex = i;
+      }
+    }
+    return snapIndex;
+}
+
+} // namespace geos.operation.snap
+} // namespace geos.operation.overlay
+} // namespace geos.operation
+} // namespace geos
+



More information about the geos-commits mailing list