[geos-commits] r3484 - in trunk: . include/geos/linearref src/linearref

svn_geos at osgeo.org svn_geos at osgeo.org
Fri Sep 23 08:14:53 EDT 2011


Author: strk
Date: 2011-09-23 05:14:53 -0700 (Fri, 23 Sep 2011)
New Revision: 3484

Added:
   trunk/include/geos/linearref/LocationIndexedLine.h
Modified:
   trunk/NEWS
   trunk/include/geos/linearref/LengthIndexedLine.h
   trunk/include/geos/linearref/LengthLocationMap.h
   trunk/include/geos/linearref/LinearIterator.h
   trunk/include/geos/linearref/LinearLocation.h
   trunk/include/geos/linearref/LocationIndexOfPoint.h
   trunk/include/geos/linearref/Makefile.am
   trunk/src/linearref/LengthIndexedLine.cpp
   trunk/src/linearref/LengthLocationMap.cpp
   trunk/src/linearref/LinearIterator.cpp
   trunk/src/linearref/LinearLocation.cpp
   trunk/src/linearref/LocationIndexOfPoint.cpp
Log:
Fixed handling of Linear Referencing over MultiLineStrings to always return lowest index, and to trim zero-length result components (#323)

Includes test. This is a port of JTS changesets 463, 464 and 465

Modified: trunk/NEWS
===================================================================
--- trunk/NEWS	2011-09-23 12:14:39 UTC (rev 3483)
+++ trunk/NEWS	2011-09-23 12:14:53 UTC (rev 3484)
@@ -9,6 +9,10 @@
     to take it by reference rather than pointer.
   - GraphComponent::label is now a Label value (from a pointer)
   - NodedSegmentString takes ownership of CoordinateSequence now
+- Bug fixes / improvements
+  - Fixed Linear Referencing API to handle MultiLineStrings consistently
+    by always using the lowest possible index value, and by trimming
+    zero-length components from results (#323)
 
 Changes in 3.3.0
 2011-05-30

Modified: trunk/include/geos/linearref/LengthIndexedLine.h
===================================================================
--- trunk/include/geos/linearref/LengthIndexedLine.h	2011-09-23 12:14:39 UTC (rev 3483)
+++ trunk/include/geos/linearref/LengthIndexedLine.h	2011-09-23 12:14:53 UTC (rev 3484)
@@ -3,6 +3,7 @@
  * GEOS - Geometry Engine Open Source
  * http://geos.refractions.net
  *
+ * Copyright (C) 2011 Sandro Santilli <strk at keybit.net>
  * Copyright (C) 2005-2006 Refractions Research Inc.
  * Copyright (C) 2001-2002 Vivid Solutions Inc.
  *
@@ -13,7 +14,7 @@
  *
  **********************************************************************
  *
- * Last port: linearref/LengthIndexedLine.java rev. 1.10
+ * Last port: linearref/LengthIndexedLine.java r463
  *
  **********************************************************************/
 
@@ -46,6 +47,8 @@
 private:
 	const geom::Geometry *linearGeom;
 	LinearLocation locationOf(double index) const;
+	LinearLocation locationOf(double index, bool resolveLower) const;
+	double positiveIndex(double index) const;
 
 public:
 
@@ -73,12 +76,14 @@
 
 
 	/**
+	 * \brief
 	 * Computes the {@link Coordinate} for the point
 	 * on the line at the given index, offset by the given distance.
+	 *
 	 * If the index is out of range the first or last point on the
 	 * line will be returned.
-	 * The computed point is offset to the left of the line if the offset distance is
-	 * positive, to the right if negative.
+	 * The computed point is offset to the left of the line if the
+	 * offset distance is positive, to the right if negative.
 	 *
 	 * The Z-ordinate of the computed point will be interpolated from
 	 * the Z-ordinates of the line segment containing it, if they exist.

Modified: trunk/include/geos/linearref/LengthLocationMap.h
===================================================================
--- trunk/include/geos/linearref/LengthLocationMap.h	2011-09-23 12:14:39 UTC (rev 3483)
+++ trunk/include/geos/linearref/LengthLocationMap.h	2011-09-23 12:14:53 UTC (rev 3484)
@@ -3,6 +3,7 @@
  * GEOS - Geometry Engine Open Source
  * http://geos.refractions.net
  *
+ * Copyright (C) 2011 Sandro Santilli <strk at keybit.net>
  * Copyright (C) 2005-2006 Refractions Research Inc.
  * Copyright (C) 2001-2002 Vivid Solutions Inc.
  *
@@ -13,7 +14,7 @@
  *
  **********************************************************************
  *
- * Last port: linearref/LengthLocationMap.java rev. 1.10
+ * Last port: linearref/LengthLocationMap.java r463
  *
  **********************************************************************/
 
@@ -24,10 +25,8 @@
 #include <geos/geom/Geometry.h>
 #include <geos/linearref/LinearLocation.h>
 
-namespace geos
-{
-namespace linearref   // geos::linearref
-{
+namespace geos {
+namespace linearref { // geos::linearref
 
 /**
  * Computes the {@link LinearLocation} for a given length
@@ -44,6 +43,8 @@
 
 	LinearLocation getLocationForward(double length) const;
 
+	LinearLocation resolveHigher(const LinearLocation& loc) const;
+
 public:
 
 	// TODO: cache computed cumulative length for each vertex
@@ -51,6 +52,7 @@
 	// TODO: support measure index for fast mapping to a location
 
 	/**
+	 * \brief
 	 * Computes the {@link LinearLocation} for a
 	 * given length along a linear {@link Geometry}.
 	 *
@@ -58,9 +60,30 @@
 	 * @param length the length index of the location
 	 * @return the {@link LinearLocation} for the length
 	 */
-	static LinearLocation getLocation(const geom::Geometry *linearGeom, double length);
+	static LinearLocation getLocation(const geom::Geometry *linearGeom, double length)
+	{
+    LengthLocationMap locater(linearGeom);
+    return locater.getLocation(length);
+	}
 
 	/**
+	 * \brief
+	 * Computes the {@link LinearLocation} for a
+	 * given length along a linear {@link Geometry}.
+	 *
+	 * @param line the linear geometry to use
+	 * @param length the length index of the location
+	 * @param resolveLower if true lengths are resolved to the
+	 *                     lowest possible index 
+	 * @return the {@link LinearLocation} for the length
+	 */
+	static LinearLocation getLocation(const geom::Geometry *linearGeom, double length, bool resolveLower)
+  {
+    LengthLocationMap locater(linearGeom);
+    return locater.getLocation(length, resolveLower);
+  }
+
+	/**
 	 * Computes the length for a given {@link LinearLocation}
 	 * on a linear {@link Geometry}.
 	 *
@@ -73,18 +96,37 @@
 	LengthLocationMap(const geom::Geometry *linearGeom);
 
 	/**
+	 * \brief
 	 * Compute the {@link LinearLocation} corresponding to a length.
+	 * 
 	 * Negative lengths are measured in reverse from end of the linear geometry.
 	 * Out-of-range values are clamped.
+	 * Ambiguous indexes are resolved to the lowest possible location value,
+	 * depending on the value of <tt>resolveLower</tt>.
 	 *
 	 * @param length the length index
 	 * @return the corresponding LinearLocation
 	 */
+	LinearLocation getLocation(double length, bool resolveLower) const;
+
+	/**
+	 * \brief
+	 * Compute the {@link LinearLocation} corresponding to a length.
+	 * 
+	 * Negative lengths are measured in reverse from end of the linear geometry.
+	 * Out-of-range values are clamped.
+	 * Ambiguous indexes are resolved to the lowest possible location value.
+	 *
+	 * @param length the length index
+	 * @return the corresponding LinearLocation
+	 */
 	LinearLocation getLocation(double length) const;
 
 	double getLength(const LinearLocation& loc) const;
 
 };
-}
-}
+
+} // geos.linearref
+} // geos
+
 #endif

Modified: trunk/include/geos/linearref/LinearIterator.h
===================================================================
--- trunk/include/geos/linearref/LinearIterator.h	2011-09-23 12:14:39 UTC (rev 3483)
+++ trunk/include/geos/linearref/LinearIterator.h	2011-09-23 12:14:53 UTC (rev 3484)
@@ -13,7 +13,7 @@
  *
  **********************************************************************
  *
- * Last port: linearref/LinearIterator.java rev. 1.10
+ * Last port: linearref/LinearIterator.java r463
  *
  **********************************************************************/
 
@@ -90,7 +90,7 @@
 
 	/**
 	 * Checks whether the iterator cursor is pointing to the
-	 * endpoint of a linestring.
+	 * endpoint of a component {@link LineString}.
 	 *
 	 * @return <code>true</true> if the iterator is at an endpoint
 	 */
@@ -143,6 +143,8 @@
 	/**
 	 * Invariant: currentLine <> null if the iterator is pointing
 	 *            at a valid coordinate
+	 *
+	 * @throws IllegalArgumentException if linearGeom is not {@link Lineal}
 	 */
 	void loadCurrentLine();
 

Modified: trunk/include/geos/linearref/LinearLocation.h
===================================================================
--- trunk/include/geos/linearref/LinearLocation.h	2011-09-23 12:14:39 UTC (rev 3483)
+++ trunk/include/geos/linearref/LinearLocation.h	2011-09-23 12:14:53 UTC (rev 3484)
@@ -3,6 +3,7 @@
  * GEOS - Geometry Engine Open Source
  * http://geos.refractions.net
  *
+ * Copyright (C) 2011 Sandro Santilli <strk at keybit.net>
  * Copyright (C) 2005-2006 Refractions Research Inc.
  * Copyright (C) 2001-2002 Vivid Solutions Inc.
  *
@@ -13,7 +14,7 @@
  *
  **********************************************************************
  *
- * Last port: linearref/LinearLocation.java rev. 1.10
+ * Last port: linearref/LinearLocation.java r463
  *
  **********************************************************************/
 
@@ -155,7 +156,7 @@
 	 * given linear {@link Geometry} which is
 	 * referenced by this location.
 	 *
-	 * @param linearGeom a linear geometry
+	 * @param linearGeom the linear geometry referenced by this location
 	 * @return the <tt>Coordinate</tt> at the location
 	 */
 	geom::Coordinate getCoordinate(const geom::Geometry* linearGeom) const;
@@ -225,6 +226,15 @@
 	 */
 	bool isOnSameSegment(const LinearLocation& loc) const;
 
+	/**
+	 * \brief
+	 * Tests whether this location is an endpoint of
+	 * the linear component it refers to.
+	 *
+	 * @param linearGeom the linear geometry referenced by this location
+	 * @return true if the location is a component endpoint
+	 */
+	bool isEndpoint(const geom::Geometry& linearGeom) const;
 
 	friend std::ostream& operator<< (std::ostream& out, const LinearLocation& obj );
 

Modified: trunk/include/geos/linearref/LocationIndexOfPoint.h
===================================================================
--- trunk/include/geos/linearref/LocationIndexOfPoint.h	2011-09-23 12:14:39 UTC (rev 3483)
+++ trunk/include/geos/linearref/LocationIndexOfPoint.h	2011-09-23 12:14:53 UTC (rev 3484)
@@ -3,6 +3,7 @@
  * GEOS - Geometry Engine Open Source
  * http://geos.refractions.net
  *
+ * Copyright (C) 2011 Sandro Santilli <strk at keybit.net>
  * Copyright (C) 2005-2006 Refractions Research Inc.
  * Copyright (C) 2001-2002 Vivid Solutions Inc.
  *
@@ -13,7 +14,7 @@
  *
  **********************************************************************
  *
- * Last port: linearref/LinearGeometryBuilder.java rev. 1.10
+ * Last port: linearref/LinearGeometryBuilder.java r466
  *
  **********************************************************************/
 
@@ -42,12 +43,12 @@
 private:
 	const geom::Geometry *linearGeom;
 
-	LinearLocation indexOfFromStart(const geom::Coordinate& inputPt, LinearLocation* minIndex) const;
+	LinearLocation indexOfFromStart(const geom::Coordinate& inputPt, const LinearLocation* minIndex) const;
 
 public:
 	static LinearLocation indexOf(const geom::Geometry *linearGeom, const geom::Coordinate& inputPt);
 
-	static LinearLocation indexOfAfter(const geom::Geometry *linearGeom, const geom::Coordinate& inputPt, LinearLocation* minIndex);
+	static LinearLocation indexOfAfter(const geom::Geometry *linearGeom, const geom::Coordinate& inputPt, const LinearLocation* minIndex);
 
 	LocationIndexOfPoint(const geom::Geometry *linearGeom);
 
@@ -73,7 +74,7 @@
 	 * @param minLocation the minimum location for the point location
 	 * @return the location of the nearest point
 	 */
-	LinearLocation indexOfAfter(const geom::Coordinate& inputPt, LinearLocation* minIndex) const;
+	LinearLocation indexOfAfter(const geom::Coordinate& inputPt, const LinearLocation* minIndex) const;
 };
 }
 }

Added: trunk/include/geos/linearref/LocationIndexedLine.h
===================================================================
--- trunk/include/geos/linearref/LocationIndexedLine.h	                        (rev 0)
+++ trunk/include/geos/linearref/LocationIndexedLine.h	2011-09-23 12:14:53 UTC (rev 3484)
@@ -0,0 +1,267 @@
+/**********************************************************************
+ *
+ * GEOS - Geometry Engine Open Source
+ * http://geos.refractions.net
+ *
+ * Copyright (C) 2011 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: linearref/LocationIndexedLine.java r466
+ *
+ **********************************************************************/
+
+#ifndef GEOS_LINEARREF_LOCATIONINDEXEDLINE_H
+#define GEOS_LINEARREF_LOCATIONINDEXEDLINE_H
+
+#include <geos/export.h>
+#include <geos/geom/Coordinate.h>
+#include <geos/geom/Geometry.h>
+#include <geos/geom/Lineal.h>
+#include <geos/linearref/LinearLocation.h>
+#include <geos/linearref/LocationIndexOfPoint.h>
+#include <geos/linearref/LocationIndexOfLine.h>
+#include <geos/util/IllegalArgumentException.h>
+
+namespace geos {
+namespace linearref { // geos::linearref
+
+/**
+ * \brief
+ * Supports linear referencing
+ * along a linear {@link Geometry}
+ * using {@link LinearLocation}s as the index.
+ */
+class GEOS_DLL LocationIndexedLine
+{
+private:
+  const geom::Geometry *linearGeom;
+
+  void checkGeometryType()
+  {
+    if ( ! dynamic_cast<const geom::Lineal*>(linearGeom) )
+      throw util::IllegalArgumentException("Input geometry must be linear");
+  }
+
+public:
+
+  /**
+   * \brief
+   * Constructs an object which allows linear referencing along
+   * a given linear {@link Geometry}.
+   *
+   * @param linearGeom the linear geometry to reference along
+   */
+  LocationIndexedLine(const geom::Geometry *linearGeom)
+    : linearGeom(linearGeom)
+  {
+    checkGeometryType();
+  }
+
+  /**
+   * \brief
+   * Computes the {@link Coordinate} for the point
+   * on the line at the given index.
+   *
+   * If the index is out of range the first or last point on the
+   * line will be returned.
+   * The Z-ordinate of the computed point will be interpolated from
+   * the Z-ordinates of the line segment containing it, if they exist.
+   *
+   * @param index the index of the desired point
+   * @return the Coordinate at the given index
+   */
+  geom::Coordinate extractPoint(const LinearLocation& index) const
+  {
+    return index.getCoordinate(linearGeom);
+  }
+
+
+  /**
+   * \brief
+   * Computes the {@link Coordinate} for the point
+   * on the line at the given index, offset by the given distance.
+   *
+   * If the index is out of range the first or last point on the
+   * line will be returned.
+   * The computed point is offset to the left of the line if the offset
+   * distance is positive, to the right if negative.
+   *
+   * The Z-ordinate of the computed point will be interpolated from
+   * the Z-ordinates of the line segment containing it, if they exist.
+   *
+   * @param index the index of the desired point
+   * @param offsetDistance the distance the point is offset from the segment
+   *    (positive is to the left, negative is to the right)
+   * @return the Coordinate at the given index
+   */
+  geom::Coordinate extractPoint(const LinearLocation& index,
+                                               double offsetDistance) const
+  {
+    geom::Coordinate ret;
+    index.getSegment(linearGeom)->pointAlongOffset(
+                index.getSegmentFraction(), offsetDistance, ret
+           );
+    return ret;
+  }
+
+  /**
+   * \brief
+   * Computes the {@link LineString} for the interval
+   * on the line between the given indices.
+   *
+   * If the endIndex lies before the startIndex,
+   * the computed geometry is reversed.
+   *
+   * @param startIndex the index of the start of the interval
+   * @param endIndex the index of the end of the interval
+   * @return the linear interval between the indices
+   */
+  geom::Geometry *extractLine(const LinearLocation& startIndex,
+                              const LinearLocation& endIndex) const
+  {
+    return ExtractLineByLocation::extract(linearGeom, startIndex, endIndex);
+  }
+
+
+  /**
+   * \brief
+   * Computes the index for a given point on the line.
+   *
+   * The supplied point does not <i>necessarily</i> have to lie precisely
+   * on the line, but if it is far from the line the accuracy and
+   * performance of this function is not guaranteed.
+   * Use {@link #project} to compute a guaranteed result for points
+   * which may be far from the line.
+   *
+   * @param pt a point on the line
+   * @return the index of the point
+   *
+   * @see project
+   */
+  LinearLocation indexOf(const geom::Coordinate& pt) const
+  {
+    return LocationIndexOfPoint::indexOf(linearGeom, pt);
+  }
+
+  /**
+   * \brief
+   * Finds the index for a point on the line
+   * which is greater than the given index.
+   *
+   * If no such index exists, returns <tt>minIndex</tt>.
+   * This method can be used to determine all indexes for
+   * a point which occurs more than once on a non-simple line.
+   * It can also be used to disambiguate cases where the given point lies
+   * slightly off the line and is equidistant from two different
+   * points on the line.
+   *
+   * The supplied point does not <i>necessarily</i> have to lie precisely
+   * on the line, but if it is far from the line the accuracy and
+   * performance of this function is not guaranteed.
+   * Use {@link #project} to compute a guaranteed result for points
+   * which may be far from the line.
+   *
+   * @param pt a point on the line
+   * @param minIndex the value the returned index must be greater than
+   * @return the index of the point greater than the given minimum index
+   *
+   * @see project
+   */
+  LinearLocation indexOfAfter(const geom::Coordinate& pt,
+                                const LinearLocation& minIndex) const
+  {
+    return LocationIndexOfPoint::indexOfAfter(linearGeom, pt, &minIndex);
+  }
+
+  /**
+   * \brief
+   * Computes the indices for a subline of the line.
+   *
+   * (The subline must <b>conform</b> to the line; that is,
+   * all vertices in the subline (except possibly the first and last)
+   * must be vertices of the line and occur in the same order).
+   *
+   * @param subLine a subLine of the line
+   * @return a pair of indices for the start and end of the subline.
+   */
+  LinearLocation* indicesOf(const geom::Geometry *subLine) const
+  {
+    return LocationIndexOfLine::indicesOf(linearGeom, subLine);
+  }
+
+
+  /**
+   * \brief
+   * Computes the index for the closest point on the line to the given point.
+   *
+   * If more than one point has the closest distance the first one along
+   * the line is returned.
+   * (The point does not necessarily have to lie precisely on the line.)
+   *
+   * @param pt a point on the line
+   * @return the index of the point
+   */
+  LinearLocation project(const geom::Coordinate& pt) const
+  {
+    return LocationIndexOfPoint::indexOf(linearGeom, pt);
+  }
+
+  /**
+   * \brief
+   * Returns the index of the start of the line
+   *
+   * @return the start index
+   */
+  LinearLocation getStartIndex() const
+  {
+    return LinearLocation();
+  }
+
+  /**
+   * \brief
+   * Returns the index of the end of the line
+   *
+   * @return the end index
+   */
+  LinearLocation getEndIndex() const
+  {
+    return LinearLocation::getEndLocation(linearGeom);
+  }
+
+  /**
+   * \brief
+   * Tests whether an index is in the valid index range for the line.
+   *
+   * @param length the index to test
+   * @return <code>true</code> if the index is in the valid range
+   */
+  bool isValidIndex(const LinearLocation& index) const
+  {
+    return index.isValid(linearGeom);
+  }
+
+
+  /**
+   * \brief
+   * Computes a valid index for this line
+   * by clamping the given index to the valid range of index values
+   *
+   * @return a valid index value
+   */
+  LinearLocation clampIndex(const LinearLocation& index) const
+  {
+    LinearLocation loc = index;
+    loc.clamp(linearGeom);
+    return loc;
+  }
+};
+
+} // geos::linearref
+} // geos
+#endif

Modified: trunk/include/geos/linearref/Makefile.am
===================================================================
--- trunk/include/geos/linearref/Makefile.am	2011-09-23 12:14:39 UTC (rev 3483)
+++ trunk/include/geos/linearref/Makefile.am	2011-09-23 12:14:53 UTC (rev 3484)
@@ -13,5 +13,6 @@
     LinearIterator.h \
     LinearGeometryBuilder.h \
     LinearLocation.h \
+    LocationIndexedLine.h \
     LocationIndexOfLine.h \
     LocationIndexOfPoint.h

Modified: trunk/src/linearref/LengthIndexedLine.cpp
===================================================================
--- trunk/src/linearref/LengthIndexedLine.cpp	2011-09-23 12:14:39 UTC (rev 3483)
+++ trunk/src/linearref/LengthIndexedLine.cpp	2011-09-23 12:14:53 UTC (rev 3484)
@@ -3,6 +3,7 @@
  * GEOS - Geometry Engine Open Source
  * http://geos.refractions.net
  *
+ * Copyright (C) 2011 Sandro Santilli <strk at keybit.net>
  * Copyright (C) 2005-2006 Refractions Research Inc.
  * Copyright (C) 2001-2002 Vivid Solutions Inc.
  *
@@ -13,12 +14,13 @@
  *
  **********************************************************************
  *
- * Last port: linearref/LengthIndexedLine.java rev. 1.35
+ * Last port: linearref/LengthIndexedLine.java r463
  *
  **********************************************************************/
 
 #include <geos/linearref/ExtractLineByLocation.h>
 #include <geos/linearref/LengthIndexedLine.h>
+#include <geos/linearref/LocationIndexedLine.h>
 #include <geos/linearref/LinearLocation.h>
 #include <geos/linearref/LengthLocationMap.h>
 #include <geos/linearref/LengthIndexOfPoint.h>
@@ -52,13 +54,20 @@
 }
 
 
-Geometry *LengthIndexedLine::extractLine(double startIndex, double endIndex) const
+Geometry *
+LengthIndexedLine::extractLine(double startIndex, double endIndex) const
 {
-
-	const LinearLocation startLoc = locationOf(startIndex);
-	const LinearLocation endLoc = locationOf(endIndex);
-	Geometry* g = ExtractLineByLocation::extract(linearGeom, startLoc, endLoc);
-	return g;
+  const LocationIndexedLine lil(linearGeom);
+  const double startIndex2 = clampIndex(startIndex);
+  const double endIndex2 = clampIndex(endIndex);
+  // if extracted line is zero-length, resolve start lower as well to
+  // ensure they are equal
+  const bool resolveStartLower = ( startIndex2 == endIndex2 );
+  const LinearLocation startLoc = locationOf(startIndex2, resolveStartLower);
+  const LinearLocation endLoc = locationOf(endIndex2);
+//    LinearLocation endLoc = locationOf(endIndex2, true);
+//    LinearLocation startLoc = locationOf(startIndex2);
+  return ExtractLineByLocation::extract(linearGeom, startLoc, endLoc);
 }
 
 LinearLocation LengthIndexedLine::locationOf(double index) const
@@ -66,7 +75,13 @@
 	return LengthLocationMap::getLocation(linearGeom, index);
 }
 
+LinearLocation
+LengthIndexedLine::locationOf(double index, bool resolveLower) const
+{
+	return LengthLocationMap::getLocation(linearGeom, index, resolveLower);
+}
 
+
 double LengthIndexedLine::indexOf(const Coordinate& pt) const
 {
 	return LengthIndexOfPoint::indexOf(linearGeom, pt);
@@ -111,15 +126,27 @@
 		&& index <= getEndIndex());
 }
 
-double LengthIndexedLine::clampIndex(double index) const
+/* public */
+double
+LengthIndexedLine::clampIndex(double index) const
 {
+  double posIndex = positiveIndex(index);
 	double startIndex = getStartIndex();
-	if (index < startIndex) return startIndex;
+  if (posIndex < startIndex) return startIndex;
 
 	double endIndex = getEndIndex();
-	if (index > endIndex) return endIndex;
+	if (posIndex > endIndex) return endIndex;
 
-	return index;
+	return posIndex;
 }
+
+/* private */
+double
+LengthIndexedLine::positiveIndex(double index) const
+{
+  if (index >= 0.0) return index;
+  return linearGeom->getLength() + index;
 }
-}
+
+} // geos.linearref
+} // geos

Modified: trunk/src/linearref/LengthLocationMap.cpp
===================================================================
--- trunk/src/linearref/LengthLocationMap.cpp	2011-09-23 12:14:39 UTC (rev 3483)
+++ trunk/src/linearref/LengthLocationMap.cpp	2011-09-23 12:14:53 UTC (rev 3484)
@@ -3,6 +3,7 @@
  * GEOS - Geometry Engine Open Source
  * http://geos.refractions.net
  *
+ * Copyright (C) 2011 Sandro Santilli <strk at keybit.net>
  * Copyright (C) 2005-2006 Refractions Research Inc.
  * Copyright (C) 2001-2002 Vivid Solutions Inc.
  *
@@ -13,7 +14,7 @@
  *
  **********************************************************************
  *
- * Last port: algorithm/LengthLocationMap.java rev. 1.35
+ * Last port: algorithm/LengthLocationMap.java r463
  *
  **********************************************************************/
 
@@ -33,12 +34,6 @@
 {
 
 
-LinearLocation LengthLocationMap::getLocation(const Geometry* linearGeom, double length)
-{
-	LengthLocationMap locater(linearGeom);
-	return locater.getLocation(length);
-}
-
 double LengthLocationMap::getLength(const Geometry* linearGeom, const LinearLocation& loc)
 {
 	LengthLocationMap locater(linearGeom);
@@ -49,7 +44,8 @@
 LengthLocationMap::LengthLocationMap(const Geometry* linearGeom) :
 		linearGeom(linearGeom) {}
 
-LinearLocation LengthLocationMap::getLocation(double length) const
+LinearLocation
+LengthLocationMap::getLocation(double length) const
 {
 	double forwardLength = length;
 	if (length < 0.0)
@@ -60,8 +56,29 @@
 	return getLocationForward(forwardLength);
 }
 
-LinearLocation LengthLocationMap::getLocationForward(double length) const
+LinearLocation
+LengthLocationMap::getLocation(double length, bool resolveLower) const
 {
+	double forwardLength = length;
+
+	// negative values are measured from end of geometry
+	if (length < 0.0)
+	{
+		double lineLen = linearGeom->getLength();
+		forwardLength = lineLen + length;
+	}
+
+	LinearLocation loc = getLocationForward(forwardLength);
+	if (resolveLower) {
+		return loc;
+	}
+	return resolveHigher(loc);
+}
+
+/* private */
+LinearLocation
+LengthLocationMap::getLocationForward(double length) const
+{
 	if (length <= 0.0)
 		return LinearLocation();
 
@@ -70,8 +87,22 @@
 	LinearIterator it (linearGeom);
 	while (it.hasNext())
 	{
-		if (! it.isEndOfLine())
-		{
+		/**
+		 * Special handling is required for the situation when the
+		 * length references exactly to a component endpoint.
+		 * In this case, the endpoint location of the current component
+		 * is returned,
+		 * rather than the startpoint location of the next component.
+		 * This produces consistent behaviour with the project method.
+		 */
+		if (it.isEndOfLine()) {
+			if (totalLength == length) {
+				unsigned int compIndex = it.getComponentIndex();
+				unsigned int segIndex = it.getVertexIndex();
+				return LinearLocation(compIndex, segIndex, 0.0);
+			}
+		}
+		else {
 			Coordinate p0 = it.getSegmentStart();
 			Coordinate p1 = it.getSegmentEnd();
 			double segLen = p1.distance(p0);
@@ -85,13 +116,33 @@
 			}
 			totalLength += segLen;
 		}
+
 		it.next();
 	}
 	// length is longer than line - return end location
 	return LinearLocation::getEndLocation(linearGeom);
 }
 
+/* private */
+LinearLocation
+LengthLocationMap::resolveHigher(const LinearLocation& loc) const
+{
+  if (! loc.isEndpoint(*linearGeom)) return loc;
 
+  unsigned int compIndex = loc.getComponentIndex();
+  // if last component can't resolve any higher
+  if (compIndex >= linearGeom->getNumGeometries() - 1) return loc;
+  
+  do {
+    compIndex++;
+  } while (compIndex < linearGeom->getNumGeometries() - 1
+           && linearGeom->getGeometryN(compIndex)->getLength() == 0);
+
+  // resolve to next higher location
+  return LinearLocation(compIndex, 0, 0.0);
+}
+
+
 double LengthLocationMap::getLength(const LinearLocation& loc) const
 {
 	double totalLength = 0.0;

Modified: trunk/src/linearref/LinearIterator.cpp
===================================================================
--- trunk/src/linearref/LinearIterator.cpp	2011-09-23 12:14:39 UTC (rev 3483)
+++ trunk/src/linearref/LinearIterator.cpp	2011-09-23 12:14:53 UTC (rev 3484)
@@ -13,7 +13,7 @@
  *
  **********************************************************************
  *
- * Last port: linearref/LinearIterator.java rev. 1.35
+ * Last port: linearref/LinearIterator.java r463
  *
  **********************************************************************/
 

Modified: trunk/src/linearref/LinearLocation.cpp
===================================================================
--- trunk/src/linearref/LinearLocation.cpp	2011-09-23 12:14:39 UTC (rev 3483)
+++ trunk/src/linearref/LinearLocation.cpp	2011-09-23 12:14:53 UTC (rev 3484)
@@ -3,6 +3,7 @@
  * GEOS - Geometry Engine Open Source
  * http://geos.refractions.net
  *
+ * Copyright (C) 2011 Sandro Santilli <strk at keybit.net>
  * Copyright (C) 2005-2006 Refractions Research Inc.
  * Copyright (C) 2001-2002 Vivid Solutions Inc.
  *
@@ -13,7 +14,7 @@
  *
  **********************************************************************
  *
- * Last port: linearref/LinearLocation.java rev. 1.10
+ * Last port: linearref/LinearLocation.java r463
  *
  **********************************************************************/
 
@@ -318,11 +319,24 @@
 	return false;
 }
 
+/* public */
+bool
+LinearLocation::isEndpoint(const Geometry& linearGeom) const
+{
+  const LineString& lineComp = dynamic_cast<const LineString&>(
+      *(linearGeom.getGeometryN(componentIndex)) );
+  // check for endpoint
+  unsigned int nseg = lineComp.getNumPoints() - 1;
+  return segmentIndex >= nseg
+        || (segmentIndex == nseg && segmentFraction >= 1.0);
 
+}
+
+
 ostream& operator<<(ostream &out, const LinearLocation &obj)
 {
-	return out << "LinearLocation(" << obj.componentIndex << ", " <<
-	       obj.segmentIndex << ", " << obj.segmentFraction << ")";
+	return out << "LinearLoc[" << obj.componentIndex << ", " <<
+	       obj.segmentIndex << ", " << obj.segmentFraction << "]";
 }
 
 } // namespace geos.linearref

Modified: trunk/src/linearref/LocationIndexOfPoint.cpp
===================================================================
--- trunk/src/linearref/LocationIndexOfPoint.cpp	2011-09-23 12:14:39 UTC (rev 3483)
+++ trunk/src/linearref/LocationIndexOfPoint.cpp	2011-09-23 12:14:53 UTC (rev 3484)
@@ -3,6 +3,7 @@
  * GEOS - Geometry Engine Open Source
  * http://geos.refractions.net
  *
+ * Copyright (C) 2011 Sandro Santilli <strk at keybit.net>
  * Copyright (C) 2005-2006 Refractions Research Inc.
  * Copyright (C) 2001-2002 Vivid Solutions Inc.
  *
@@ -13,7 +14,7 @@
  *
  **********************************************************************
  *
- * Last port: linearref/LocationIndexOfPoint.java rev. 1.35
+ * Last port: linearref/LocationIndexOfPoint.java r466
  *
  **********************************************************************/
 
@@ -36,7 +37,9 @@
 namespace linearref   // geos.linearref
 {
 
-LinearLocation LocationIndexOfPoint::indexOfFromStart(const Coordinate& inputPt, LinearLocation* minIndex) const
+LinearLocation
+LocationIndexOfPoint::indexOfFromStart(const Coordinate& inputPt,
+  const LinearLocation* minIndex) const
 {
 	double minDistance = numeric_limits<double>::max();
 	int minComponentIndex = 0;
@@ -82,7 +85,7 @@
 	return locater.indexOf(inputPt);
 }
 
-LinearLocation LocationIndexOfPoint::indexOfAfter(const Geometry *linearGeom, const Coordinate& inputPt, LinearLocation* minIndex)
+LinearLocation LocationIndexOfPoint::indexOfAfter(const Geometry *linearGeom, const Coordinate& inputPt, const LinearLocation* minIndex)
 {
 	LocationIndexOfPoint locater(linearGeom);
 	return locater.indexOfAfter(inputPt, minIndex);
@@ -97,7 +100,9 @@
 	return indexOfFromStart(inputPt, 0);
 }
 
-LinearLocation LocationIndexOfPoint::indexOfAfter(const Coordinate& inputPt, LinearLocation* minIndex) const
+LinearLocation
+LocationIndexOfPoint::indexOfAfter(const Coordinate& inputPt,
+                                   const LinearLocation* minIndex) const
 {
 	if (!minIndex) return indexOf(inputPt);
 



More information about the geos-commits mailing list