|
|
|
David Turner-3
|
JTS has a class called LengthIndexedLine with a method "project", which
lets you figure out the nearest point on a line to a given point. This is useful, for instance, if you are trying to figure out what street a person is on from (possibly slightly inaccurate) GPS observations. http://tsusiatsoftware.net/jts/javadoc/com/vividsolutions/jts/linearref/LengthIndexedLine.html#project(com.vividsolutions.jts.geom.Coordinate) PostGIS calls this function st_line_locate_point. GEOS doesn't seem to have it, even though I was under the impression that GEOS was merely a port of JTS. If I port JTS's project function and related functions such as extractPoint to GEOS, would that patch be likely to be accepted? Or am I missing something about the relationship between JTS and GEOS? _______________________________________________ geos-devel mailing list [hidden email] http://lists.osgeo.org/mailman/listinfo/geos-devel |
||||||||||||||||
|
strk
|
On Thu, Jul 23, 2009 at 11:13:34AM -0400, David Turner wrote:
> JTS has a class called LengthIndexedLine with a method "project", which > lets you figure out the nearest point on a line to a given point. This > is useful, for instance, if you are trying to figure out what street a > person is on from (possibly slightly inaccurate) GPS observations. > > http://tsusiatsoftware.net/jts/javadoc/com/vividsolutions/jts/linearref/LengthIndexedLine.html#project(com.vividsolutions.jts.geom.Coordinate) > > PostGIS calls this function st_line_locate_point. > > GEOS doesn't seem to have it, even though I was under the impression > that GEOS was merely a port of JTS. If I port JTS's project function > and related functions such as extractPoint to GEOS, would that patch be > likely to be accepted? Or am I missing something about the relationship > between JTS and GEOS? Your patch would be welcome. Make sure to include unit testing please. --strk; Free GIS & Flash consultant/developer () ASCII Ribbon Campaign http://foo.keybit.net/~strk/services.html /\ Keep it simple! _______________________________________________ geos-devel mailing list [hidden email] http://lists.osgeo.org/mailman/listinfo/geos-devel |
||||||||||||||||
|
David Turner-3
|
On Thu, 2009-07-23 at 21:53 +0200, strk wrote:
> On Thu, Jul 23, 2009 at 11:13:34AM -0400, David Turner wrote: > > JTS has a class called LengthIndexedLine with a method "project", which > > lets you figure out the nearest point on a line to a given point. This > > is useful, for instance, if you are trying to figure out what street a > > person is on from (possibly slightly inaccurate) GPS observations. > > > > http://tsusiatsoftware.net/jts/javadoc/com/vividsolutions/jts/linearref/LengthIndexedLine.html#project(com.vividsolutions.jts.geom.Coordinate) > > > > PostGIS calls this function st_line_locate_point. > > > > GEOS doesn't seem to have it, even though I was under the impression > > that GEOS was merely a port of JTS. If I port JTS's project function > > and related functions such as extractPoint to GEOS, would that patch be > > likely to be accepted? Or am I missing something about the relationship > > between JTS and GEOS? > > Your patch would be welcome. Make sure to include unit testing please. I have a patch. Unfortunately, I do not yet have unit tests, because I cannot find the relevant Java unit tests to port. I could write my own, but it seems like some of the other code uses ported Java unit tests, and I want to follow the common practice. Can you point me to the Java unit tests? _______________________________________________ geos-devel mailing list [hidden email] http://lists.osgeo.org/mailman/listinfo/geos-devel |
||||||||||||||||
|
David Turner-3
|
On Mon, 2009-07-27 at 17:42 -0400, David Turner wrote:
> On Thu, 2009-07-23 at 21:53 +0200, strk wrote: > > On Thu, Jul 23, 2009 at 11:13:34AM -0400, David Turner wrote: > > > JTS has a class called LengthIndexedLine with a method "project", which > > > lets you figure out the nearest point on a line to a given point. This > > > is useful, for instance, if you are trying to figure out what street a > > > person is on from (possibly slightly inaccurate) GPS observations. > > > > > > http://tsusiatsoftware.net/jts/javadoc/com/vividsolutions/jts/linearref/LengthIndexedLine.html#project(com.vividsolutions.jts.geom.Coordinate) > > > > > > PostGIS calls this function st_line_locate_point. > > > > > > GEOS doesn't seem to have it, even though I was under the impression > > > that GEOS was merely a port of JTS. If I port JTS's project function > > > and related functions such as extractPoint to GEOS, would that patch be > > > likely to be accepted? Or am I missing something about the relationship > > > between JTS and GEOS? > > > > Your patch would be welcome. Make sure to include unit testing please. > > I have a patch. Unfortunately, I do not yet have unit tests, because I > cannot find the relevant Java unit tests to port. I could write my own, > but it seems like some of the other code uses ported Java unit tests, > and I want to follow the common practice. > > Can you point me to the Java unit tests? Just wanted to follow up to be sure this wasn't lost. The example I'm looking at, in case I'm missing something, is: tests/unit/algorithm/RobustLineIntersectionTest.cpp which claims to be: Ported from JTS junit/algorithm/RobustLineIntersectionTest.java I assume there are probably similar tests for the linearref stuff, but the JTS CVS appears to be empty or down or something, and Googling turns up nothing. _______________________________________________ geos-devel mailing list [hidden email] http://lists.osgeo.org/mailman/listinfo/geos-devel |
||||||||||||||||
|
strk
|
Let's ask Martin...
Are unit tests for LengthIndexedLine available or to be made ? --strk; On Sat, Aug 01, 2009 at 12:02:07AM -0400, David Turner wrote: > On Mon, 2009-07-27 at 17:42 -0400, David Turner wrote: > > On Thu, 2009-07-23 at 21:53 +0200, strk wrote: > > > On Thu, Jul 23, 2009 at 11:13:34AM -0400, David Turner wrote: > > > > JTS has a class called LengthIndexedLine with a method "project", which > > > > lets you figure out the nearest point on a line to a given point. This > > > > is useful, for instance, if you are trying to figure out what street a > > > > person is on from (possibly slightly inaccurate) GPS observations. > > > > > > > > http://tsusiatsoftware.net/jts/javadoc/com/vividsolutions/jts/linearref/LengthIndexedLine.html#project(com.vividsolutions.jts.geom.Coordinate) > > > > > > > > PostGIS calls this function st_line_locate_point. > > > > > > > > GEOS doesn't seem to have it, even though I was under the impression > > > > that GEOS was merely a port of JTS. If I port JTS's project function > > > > and related functions such as extractPoint to GEOS, would that patch be > > > > likely to be accepted? Or am I missing something about the relationship > > > > between JTS and GEOS? > > > > > > Your patch would be welcome. Make sure to include unit testing please. > > > > I have a patch. Unfortunately, I do not yet have unit tests, because I > > cannot find the relevant Java unit tests to port. I could write my own, > > but it seems like some of the other code uses ported Java unit tests, > > and I want to follow the common practice. > > > > Can you point me to the Java unit tests? > > Just wanted to follow up to be sure this wasn't lost. The example I'm > looking at, in case I'm missing something, is: > > tests/unit/algorithm/RobustLineIntersectionTest.cpp > > which claims to be: > > Ported from JTS junit/algorithm/RobustLineIntersectionTest.java > > I assume there are probably similar tests for the linearref stuff, but > the JTS CVS appears to be empty or down or something, and Googling turns > up nothing. > > _______________________________________________ > geos-devel mailing list > [hidden email] > http://lists.osgeo.org/mailman/listinfo/geos-devel -- Free GIS & Flash consultant/developer () ASCII Ribbon Campaign http://foo.keybit.net/~strk/services.html /\ Keep it simple! _______________________________________________ geos-devel mailing list [hidden email] http://lists.osgeo.org/mailman/listinfo/geos-devel |
||||||||||||||||
|
strk
|
Martin forgot to answer publically, anyway, he mentioned
tests are here: test.jts.junit.linearref NOTE: they are only in CVS: :pserver:[hidden email]:/home/cvs/jts --strk; Free GIS & Flash consultant/developer () ASCII Ribbon Campaign http://foo.keybit.net/~strk/services.html /\ Keep it simple! On Sun, Aug 02, 2009 at 03:23:18PM +0200, strk wrote: > Let's ask Martin... > Are unit tests for LengthIndexedLine available or to be made ? > > --strk; > > On Sat, Aug 01, 2009 at 12:02:07AM -0400, David Turner wrote: > > On Mon, 2009-07-27 at 17:42 -0400, David Turner wrote: > > > On Thu, 2009-07-23 at 21:53 +0200, strk wrote: > > > > On Thu, Jul 23, 2009 at 11:13:34AM -0400, David Turner wrote: > > > > > JTS has a class called LengthIndexedLine with a method "project", which > > > > > lets you figure out the nearest point on a line to a given point. This > > > > > is useful, for instance, if you are trying to figure out what street a > > > > > person is on from (possibly slightly inaccurate) GPS observations. > > > > > > > > > > http://tsusiatsoftware.net/jts/javadoc/com/vividsolutions/jts/linearref/LengthIndexedLine.html#project(com.vividsolutions.jts.geom.Coordinate) > > > > > > > > > > PostGIS calls this function st_line_locate_point. > > > > > > > > > > GEOS doesn't seem to have it, even though I was under the impression > > > > > that GEOS was merely a port of JTS. If I port JTS's project function > > > > > and related functions such as extractPoint to GEOS, would that patch be > > > > > likely to be accepted? Or am I missing something about the relationship > > > > > between JTS and GEOS? > > > > > > > > Your patch would be welcome. Make sure to include unit testing please. > > > > > > I have a patch. Unfortunately, I do not yet have unit tests, because I > > > cannot find the relevant Java unit tests to port. I could write my own, > > > but it seems like some of the other code uses ported Java unit tests, > > > and I want to follow the common practice. > > > > > > Can you point me to the Java unit tests? > > > > Just wanted to follow up to be sure this wasn't lost. The example I'm > > looking at, in case I'm missing something, is: > > > > tests/unit/algorithm/RobustLineIntersectionTest.cpp > > > > which claims to be: > > > > Ported from JTS junit/algorithm/RobustLineIntersectionTest.java > > > > I assume there are probably similar tests for the linearref stuff, but > > the JTS CVS appears to be empty or down or something, and Googling turns > > up nothing. > > > > _______________________________________________ > > geos-devel mailing list > > [hidden email] > > http://lists.osgeo.org/mailman/listinfo/geos-devel > > -- > > Free GIS & Flash consultant/developer () ASCII Ribbon Campaign > http://foo.keybit.net/~strk/services.html /\ Keep it simple! > _______________________________________________ > geos-devel mailing list > [hidden email] > http://lists.osgeo.org/mailman/listinfo/geos-devel geos-devel mailing list [hidden email] http://lists.osgeo.org/mailman/listinfo/geos-devel |
||||||||||||||||
|
David Turner-3
|
In reply to this post
by David Turner-3
OK, I've done the port. A patch, with ported tests, is attached.
On Thu, 2009-07-23 at 11:13 -0400, David Turner wrote: > JTS has a class called LengthIndexedLine with a method "project", which > lets you figure out the nearest point on a line to a given point. This > is useful, for instance, if you are trying to figure out what street a > person is on from (possibly slightly inaccurate) GPS observations. > > http://tsusiatsoftware.net/jts/javadoc/com/vividsolutions/jts/linearref/LengthIndexedLine.html#project(com.vividsolutions.jts.geom.Coordinate) > > PostGIS calls this function st_line_locate_point. > > GEOS doesn't seem to have it, even though I was under the impression > that GEOS was merely a port of JTS. If I port JTS's project function > and related functions such as extractPoint to GEOS, would that patch be > likely to be accepted? Or am I missing something about the relationship > between JTS and GEOS? > > > _______________________________________________ > geos-devel mailing list > [hidden email] > http://lists.osgeo.org/mailman/listinfo/geos-devel [linearref.patch] Index: configure.in =================================================================== --- configure.in (revision 2616) +++ configure.in (working copy) @@ -361,6 +361,7 @@ source/headers/geos/index/strtree/Makefile source/headers/geos/index/sweepline/Makefile source/headers/geos/io/Makefile + source/headers/geos/linearref/Makefile source/headers/geos/noding/Makefile source/headers/geos/noding/snapround/Makefile source/headers/geos/operation/Makefile @@ -388,6 +389,7 @@ source/index/strtree/Makefile source/index/sweepline/Makefile source/io/Makefile + source/linearref/Makefile source/noding/Makefile source/noding/snapround/Makefile source/operation/Makefile Index: source/linearref/LocationIndexOfPoint.cpp =================================================================== --- source/linearref/LocationIndexOfPoint.cpp (revision 0) +++ source/linearref/LocationIndexOfPoint.cpp (revision 0) @@ -0,0 +1,122 @@ +/********************************************************************** + * $Id: LocationIndexOfPoint.cpp 1938 2006-12-07 10:45:16Z strk $ + * + * GEOS - Geometry Engine Open Source + * http://geos.refractions.net + * + * Copyright (C) 2005-2006 Refractions Research Inc. + * Copyright (C) 2001-2002 Vivid Solutions Inc. + * + * 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/LocationIndexOfPoint.java rev. 1.35 + * + **********************************************************************/ + + +#include <geos/geom/LineSegment.h> +#include <geos/linearref/LinearIterator.h> +#include <geos/linearref/LinearLocation.h> +#include <geos/linearref/LocationIndexOfPoint.h> +#include <geos/util/IllegalArgumentException.h> + +#include <cassert> +#include <limits> + +using namespace std; + +using namespace geos::geom; + +namespace geos +{ +namespace linearref // geos.linearref +{ + +LinearLocation LocationIndexOfPoint::indexOfFromStart(const Coordinate& inputPt, LinearLocation* minIndex) const +{ + double minDistance = numeric_limits<double>::max(); + int minComponentIndex = 0; + int minSegmentIndex = 0; + double minFrac = -1.0; + + LineSegment seg; + for (LinearIterator it(linearGeom); + it.hasNext(); it.next()) + { + if (! it.isEndOfLine()) + { + seg.p0 = it.getSegmentStart(); + seg.p1 = it.getSegmentEnd(); + double segDistance = seg.distance(inputPt); + double segFrac = seg.segmentFraction(inputPt); + + int candidateComponentIndex = it.getComponentIndex(); + int candidateSegmentIndex = it.getVertexIndex(); + if (segDistance < minDistance) + { + // ensure after minLocation, if any + if (!minIndex || + minIndex->compareLocationValues(candidateComponentIndex, candidateSegmentIndex, segFrac) < 0) + { + // otherwise, save this as new minimum + minComponentIndex = candidateComponentIndex; + minSegmentIndex = candidateSegmentIndex; + minFrac = segFrac; + minDistance = segDistance; + } + } + } + } + LinearLocation loc(minComponentIndex, minSegmentIndex, minFrac); + return loc; +} + + +LinearLocation LocationIndexOfPoint::indexOf(Geometry *linearGeom, const Coordinate& inputPt) +{ + LocationIndexOfPoint locater(linearGeom); + return locater.indexOf(inputPt); +} + +LinearLocation LocationIndexOfPoint::indexOfAfter(Geometry *linearGeom, const Coordinate& inputPt, LinearLocation* minIndex) +{ + LocationIndexOfPoint locater(linearGeom); + return locater.indexOfAfter(inputPt, minIndex); +} + +LocationIndexOfPoint::LocationIndexOfPoint(Geometry *linearGeom) : + linearGeom(linearGeom) +{} + +LinearLocation LocationIndexOfPoint::indexOf(const Coordinate& inputPt) const +{ + return indexOfFromStart(inputPt, 0); +} + +LinearLocation LocationIndexOfPoint::indexOfAfter(const Coordinate& inputPt, LinearLocation* minIndex) const +{ + if (!minIndex) return indexOf(inputPt); + + // sanity check for minLocation at or past end of line + LinearLocation endLoc = LinearLocation::getEndLocation(linearGeom); + if (endLoc.compareTo(*minIndex) <= 0) + return endLoc; + + LinearLocation closestAfter = indexOfFromStart(inputPt, minIndex); + /** + * Return the minDistanceLocation found. + * This will not be null, since it was initialized to minLocation + */ + if (closestAfter.compareTo(*minIndex) < 0) + { + throw util::IllegalArgumentException("computed location is before specified minimum location"); + } + return closestAfter; +} +} +} Index: source/linearref/LinearLocation.cpp =================================================================== --- source/linearref/LinearLocation.cpp (revision 0) +++ source/linearref/LinearLocation.cpp (revision 0) @@ -0,0 +1,284 @@ +/********************************************************************** + * $Id: LinearLocation.cpp 1938 2006-12-07 10:45:16Z strk $ + * + * GEOS - Geometry Engine Open Source + * http://geos.refractions.net + * + * Copyright (C) 2005-2006 Refractions Research Inc. + * Copyright (C) 2001-2002 Vivid Solutions Inc. + * + * 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/LinearLocation.java rev. 1.35 + * + **********************************************************************/ + +#include <geos/geom/LineString.h> +#include <geos/linearref/LengthIndexedLine.h> +#include <geos/linearref/LinearLocation.h> +#include <geos/linearref/LengthLocationMap.h> + +using namespace std; + +using namespace geos::geom; + +namespace geos +{ +namespace linearref // geos.linearref +{ + +LinearLocation LinearLocation::getEndLocation(Geometry* linear) +{ + // assert: linear is LineString or MultiLineString + LinearLocation loc; + loc.setToEnd(linear); + return loc; +} + +Coordinate LinearLocation::pointAlongSegmentByFraction(Coordinate& p0, Coordinate& p1, double frac) +{ + if (frac <= 0.0) return p0; + if (frac >= 1.0) return p1; + + double x = (p1.x - p0.x) * frac + p0.x; + double y = (p1.y - p0.y) * frac + p0.y; + // interpolate Z value. If either input Z is NaN, result z will be NaN as well. + double z = (p1.z - p0.z) * frac + p0.z; + return Coordinate(x, y, z); +} + +LinearLocation::LinearLocation(unsigned int segmentIndex, double segmentFraction) : + componentIndex(0), segmentIndex(segmentIndex), segmentFraction(segmentFraction) {} + + +LinearLocation::LinearLocation(unsigned int componentIndex, unsigned int segmentIndex, double segmentFraction): + componentIndex(componentIndex), segmentIndex(segmentIndex), segmentFraction(segmentFraction) +{ + normalize(); +} + +void LinearLocation::normalize() +{ + if (segmentFraction < 0.0) + { + segmentFraction = 0.0; + } + if (segmentFraction > 1.0) + { + segmentFraction = 1.0; + } + + if (componentIndex < 0) + { + componentIndex = 0; + segmentIndex = 0; + segmentFraction = 0.0; + } + if (segmentIndex < 0) + { + segmentIndex = 0; + segmentFraction = 0.0; + } + if (segmentFraction == 1.0) + { + segmentFraction = 0.0; + segmentIndex += 1; + } +} + + + +void LinearLocation::clamp(Geometry* linear) +{ + if (componentIndex >= linear->getNumGeometries()) + { + setToEnd(linear); + return; + } + if (segmentIndex >= linear->getNumPoints()) + { + const LineString* line = dynamic_cast<const LineString*> (linear->getGeometryN(componentIndex)); + segmentIndex = line->getNumPoints() - 1; + segmentFraction = 1.0; + } +} + +void LinearLocation::snapToVertex(Geometry* linearGeom, double minDistance) +{ + if (segmentFraction <= 0.0 || segmentFraction >= 1.0) + return; + double segLen = getSegmentLength(linearGeom); + double lenToStart = segmentFraction * segLen; + double lenToEnd = segLen - lenToStart; + if (lenToStart <= lenToEnd && lenToStart < minDistance) + { + segmentFraction = 0.0; + } + else if (lenToEnd <= lenToStart && lenToEnd < minDistance) + { + segmentFraction = 1.0; + } +} + +double LinearLocation::getSegmentLength(Geometry* linearGeom) const +{ + const LineString* lineComp = dynamic_cast<const LineString*> (linearGeom->getGeometryN(componentIndex)); + + // ensure segment index is valid + unsigned int segIndex = segmentIndex; + if (segmentIndex >= lineComp->getNumPoints() - 1) + segIndex = lineComp->getNumPoints() - 2; + + Coordinate p0 = lineComp->getCoordinateN(segIndex); + Coordinate p1 = lineComp->getCoordinateN(segIndex + 1); + return p0.distance(p1); +} + +void LinearLocation::setToEnd(Geometry* linear) +{ + componentIndex = linear->getNumGeometries() - 1; + const LineString* lastLine = dynamic_cast<const LineString*>(linear->getGeometryN(componentIndex)); + segmentIndex = lastLine->getNumPoints() - 1; + segmentFraction = 1.0; +} + +unsigned int LinearLocation::getComponentIndex() const +{ + return componentIndex; +} + +unsigned int LinearLocation::getSegmentIndex() const +{ + return segmentIndex; +} + +double LinearLocation::getSegmentFraction() const +{ + return segmentFraction; +} + +bool LinearLocation::isVertex() const +{ + return segmentFraction <= 0.0 || segmentFraction >= 1.0; +} + +Coordinate LinearLocation::getCoordinate(Geometry* linearGeom) const +{ + const LineString* lineComp = dynamic_cast<const LineString *> (linearGeom->getGeometryN(componentIndex)); + Coordinate p0 = lineComp->getCoordinateN(segmentIndex); + if (segmentIndex >= lineComp->getNumPoints() - 1) + return p0; + Coordinate p1 = lineComp->getCoordinateN(segmentIndex + 1); + return pointAlongSegmentByFraction(p0, p1, segmentFraction); +} + +LineSegment* LinearLocation::getSegment(Geometry* linearGeom) const +{ + const LineString* lineComp = dynamic_cast<const LineString *> (linearGeom->getGeometryN(componentIndex)); + Coordinate p0 = lineComp->getCoordinateN(segmentIndex); + // check for endpoint - return last segment of the line if so + if (segmentIndex >= lineComp->getNumPoints() - 1) + { + Coordinate prev = lineComp->getCoordinateN(lineComp->getNumPoints() - 2); + return new LineSegment(prev, p0); + } + Coordinate p1 = lineComp->getCoordinateN(segmentIndex + 1); + return new LineSegment(p0, p1); +} + + +bool LinearLocation::isValid(Geometry* linearGeom) const +{ + if (componentIndex < 0 || componentIndex >= linearGeom->getNumGeometries()) + return false; + + const LineString* lineComp = dynamic_cast<const LineString*> (linearGeom->getGeometryN(componentIndex)); + if (segmentIndex < 0 || segmentIndex > lineComp->getNumPoints()) + return false; + if (segmentIndex == lineComp->getNumPoints() && segmentFraction != 0.0) + return false; + + if (segmentFraction < 0.0 || segmentFraction > 1.0) + return false; + return true; +} + + +int LinearLocation::compareTo(const LinearLocation& other) const +{ + // compare component indices + if (componentIndex < other.componentIndex) return -1; + if (componentIndex > other.componentIndex) return 1; + // compare segments + if (segmentIndex < other.segmentIndex) return -1; + if (segmentIndex > other.segmentIndex) return 1; + // same segment, so compare segment fraction + if (segmentFraction < other.segmentFraction) return -1; + if (segmentFraction > other.segmentFraction) return 1; + // same location + return 0; +} + + +int LinearLocation::compareLocationValues(unsigned int componentIndex1, unsigned int segmentIndex1, double segmentFraction1) const +{ + // compare component indices + if (componentIndex < componentIndex1) return -1; + if (componentIndex > componentIndex1) return 1; + // compare segments + if (segmentIndex < segmentIndex1) return -1; + if (segmentIndex > segmentIndex1) return 1; + // same segment, so compare segment fraction + if (segmentFraction < segmentFraction1) return -1; + if (segmentFraction > segmentFraction1) return 1; + // same location + return 0; +} + + +int LinearLocation::compareLocationValues( + unsigned int componentIndex0, unsigned int segmentIndex0, double segmentFraction0, + unsigned int componentIndex1, unsigned int segmentIndex1, double segmentFraction1) +{ + // compare component indices + if (componentIndex0 < componentIndex1) return -1; + if (componentIndex0 > componentIndex1) return 1; + // compare segments + if (segmentIndex0 < segmentIndex1) return -1; + if (segmentIndex0 > segmentIndex1) return 1; + // same segment, so compare segment fraction + if (segmentFraction0 < segmentFraction1) return -1; + if (segmentFraction0 > segmentFraction1) return 1; + // same location + return 0; +} + + +bool LinearLocation::isOnSameSegment(const LinearLocation& loc) const +{ + if (componentIndex != loc.componentIndex) return false; + if (segmentIndex == loc.segmentIndex) return true; + if (loc.segmentIndex - segmentIndex == 1 + && loc.segmentFraction == 0.0) + return true; + if (segmentIndex - loc.segmentIndex == 1 + && segmentFraction == 0.0) + return true; + return false; +} + + +ostream& operator<<(ostream &out, const LinearLocation &obj) +{ + return out << "LinearLocation(" << obj.componentIndex << ", " << + obj.segmentIndex << ", " << obj.segmentFraction << ")"; +} + +} +} + Index: source/linearref/LinearIterator.cpp =================================================================== --- source/linearref/LinearIterator.cpp (revision 0) +++ source/linearref/LinearIterator.cpp (revision 0) @@ -0,0 +1,141 @@ +/********************************************************************** + * $Id: LinearIterator.cpp 1938 2006-12-07 10:45:16Z strk $ + * + * GEOS - Geometry Engine Open Source + * http://geos.refractions.net + * + * Copyright (C) 2005-2006 Refractions Research Inc. + * Copyright (C) 2001-2002 Vivid Solutions Inc. + * + * 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/LinearIterator.java rev. 1.35 + * + **********************************************************************/ + + +#include <geos/geom/LineString.h> +#include <geos/linearref/LinearIterator.h> +#include <geos/linearref/LinearLocation.h> +#include <geos/linearref/LengthLocationMap.h> + +using namespace geos::geom; + +namespace geos +{ +namespace linearref // geos.linearref +{ + +unsigned int LinearIterator::segmentEndVertexIndex(const LinearLocation& loc) +{ + if (loc.getSegmentFraction() > 0.0) + return loc.getSegmentIndex() + 1; + return loc.getSegmentIndex(); +} + +LinearIterator::LinearIterator(Geometry* linear) : + vertexIndex(0), + componentIndex(0), + linear(linear), + numLines(linear->getNumGeometries()) +{ + loadCurrentLine(); +} + + +LinearIterator::LinearIterator(Geometry* linear, const LinearLocation& start): + vertexIndex(segmentEndVertexIndex(start)), + componentIndex(start.getComponentIndex()), + linear(linear), + numLines(linear->getNumGeometries()) +{ + loadCurrentLine(); +} + +LinearIterator::LinearIterator(Geometry* linear, unsigned int componentIndex, unsigned int vertexIndex) : + vertexIndex(vertexIndex), + componentIndex(componentIndex), + linear(linear), + numLines(linear->getNumGeometries()) +{ + loadCurrentLine(); +} + +void LinearIterator::loadCurrentLine() +{ + if (componentIndex >= numLines) + { + currentLine = 0; + return; + } + currentLine = dynamic_cast<const LineString *> (linear->getGeometryN(componentIndex)); +} + +bool LinearIterator::hasNext() const +{ + if (componentIndex >= numLines) return false; + if (componentIndex == numLines - 1 + && vertexIndex >= currentLine->getNumPoints()) + return false; + return true; +} + +void LinearIterator::next() +{ + if (! hasNext()) return; + + vertexIndex++; + if (vertexIndex >= currentLine->getNumPoints()) + { + componentIndex++; + loadCurrentLine(); + vertexIndex = 0; + } +} + +bool LinearIterator::isEndOfLine() const +{ + if (componentIndex >= numLines) return false; + //LineString currentLine = (LineString) linear.getGeometryN(componentIndex); + if (!currentLine) + return false; + if (vertexIndex < currentLine->getNumPoints() - 1) + return false; + return true; +} + +unsigned int LinearIterator::getComponentIndex() const +{ + return componentIndex; +} + +unsigned int LinearIterator::getVertexIndex() const +{ + return vertexIndex; +} + +const LineString* LinearIterator::getLine() const +{ + return currentLine; +} + +Coordinate LinearIterator::getSegmentStart() const +{ + return currentLine->getCoordinateN(vertexIndex); +} + +Coordinate LinearIterator::getSegmentEnd() const +{ + if (vertexIndex < getLine()->getNumPoints() - 1) + return currentLine->getCoordinateN(vertexIndex + 1); + Coordinate c; + c.setNull(); + return c; +} +} +} Index: source/linearref/ExtractLineByLocation.cpp =================================================================== --- source/linearref/ExtractLineByLocation.cpp (revision 0) +++ source/linearref/ExtractLineByLocation.cpp (revision 0) @@ -0,0 +1,160 @@ +/********************************************************************** + * $Id: ExtractLineByLocation.cpp 1938 2006-12-07 10:45:16Z strk $ + * + * GEOS - Geometry Engine Open Source + * http://geos.refractions.net + * + * Copyright (C) 2005-2006 Refractions Research Inc. + * Copyright (C) 2001-2002 Vivid Solutions Inc. + * + * 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/ExtractLineByLocation.java rev. 1.35 + * + **********************************************************************/ + +#include <geos/geom/Coordinate.h> +#include <geos/geom/CoordinateArraySequence.h> +#include <geos/geom/MultiLineString.h> +#include <geos/geom/LineString.h> +#include <geos/linearref/ExtractLineByLocation.h> +#include <geos/linearref/LinearIterator.h> +#include <geos/linearref/LinearLocation.h> +#include <geos/linearref/LengthLocationMap.h> +#include <geos/linearref/LengthIndexOfPoint.h> +#include <geos/linearref/LinearGeometryBuilder.h> + +#include <cassert> +#include <typeinfo> + +using namespace std; + +using namespace geos::geom; + +namespace geos +{ +namespace linearref // geos.linearref +{ + + +Geometry *ExtractLineByLocation::extract(Geometry *line, const LinearLocation& start, const LinearLocation& end) +{ + ExtractLineByLocation ls(line); + return ls.extract(start, end); +} + +ExtractLineByLocation::ExtractLineByLocation(Geometry *line) : + line(line) {} + + +Geometry *ExtractLineByLocation::extract(const LinearLocation& start, const LinearLocation& end) +{ + if (end.compareTo(start) < 0) + { + Geometry* backwards = computeLinear(end, start); + Geometry* forwards = reverse(backwards); + delete backwards; + return forwards; + } + return computeLinear(start, end); +} + +Geometry *ExtractLineByLocation::reverse(Geometry *linear) +{ + LineString* ls = dynamic_cast<LineString *>(linear); + if (ls) + { + return ls->reverse(); + } + else + { + MultiLineString* mls = dynamic_cast<MultiLineString *>(linear); + if (mls) + { + return mls->reverse(); + } + else + { + assert(!"non-linear geometry encountered"); + } + } +} + +LineString* ExtractLineByLocation::computeLine(const LinearLocation& start, const LinearLocation& end) +{ + CoordinateSequence* coordinates = line->getCoordinates(); + CoordinateArraySequence newCoordinateArray; + + unsigned int startSegmentIndex = start.getSegmentIndex(); + if (start.getSegmentFraction() > 0.0) + startSegmentIndex += 1; + unsigned int lastSegmentIndex = end.getSegmentIndex(); + if (end.getSegmentFraction() == 1.0) + lastSegmentIndex += 1; + if (lastSegmentIndex >= coordinates->size()) + lastSegmentIndex = coordinates->size() - 1; + // not needed - LinearLocation values should always be correct + //Assert.isTrue(end.getSegmentFraction() <= 1.0, "invalid segment fraction value"); + + if (! start.isVertex()) + newCoordinateArray.add(start.getCoordinate(line)); + for (unsigned int i = startSegmentIndex; i <= lastSegmentIndex; i++) + { + newCoordinateArray.add((*coordinates)[i]); + } + if (! end.isVertex()) + newCoordinateArray.add(end.getCoordinate(line)); + + // ensure there is at least one coordinate in the result + if (newCoordinateArray.size() == 0) + newCoordinateArray.add(start.getCoordinate(line)); + + /** + * Ensure there is enough coordinates to build a valid line. + * Make a 2-point line with duplicate coordinates, if necessary. + * There will always be at least one coordinate in the coordList. + */ + if (newCoordinateArray.size() <= 1) + { + newCoordinateArray.add(newCoordinateArray[0]); + } + + return line->getFactory()->createLineString(newCoordinateArray); +} + +Geometry *ExtractLineByLocation::computeLinear(const LinearLocation& start, const LinearLocation& end) +{ + LinearGeometryBuilder builder(line->getFactory()); + builder.setFixInvalidLines(true); + + if (! start.isVertex()) + { + builder.add(start.getCoordinate(line)); + } + + for (LinearIterator it(line, start); it.hasNext(); it.next()) + { + if (end.compareLocationValues(it.getComponentIndex(), it.getVertexIndex(), 0.0) < 0) + { + break; + } + Coordinate pt = it.getSegmentStart(); + builder.add(pt); + if (it.isEndOfLine()) + { + builder.endLine(); + } + } + if (! end.isVertex()) + { + builder.add(end.getCoordinate(line)); + } + return builder.getGeometry(); +} +} +} Index: source/linearref/Makefile.am =================================================================== --- source/linearref/Makefile.am (revision 0) +++ source/linearref/Makefile.am (revision 0) @@ -0,0 +1,20 @@ + +noinst_LTLIBRARIES = liblinearref.la + +INCLUDES = -I$(top_srcdir)/source/headers + +liblinearref_la_SOURCES = \ + ExtractLineByLocation.cpp \ + LengthIndexedLine.cpp \ + LengthIndexOfPoint.cpp \ + LengthLocationMap.cpp \ + LinearIterator.cpp \ + LinearGeometryBuilder.cpp \ + LinearLocation.cpp \ + LocationIndexOfLine.cpp \ + LocationIndexOfPoint.cpp + +# Deprecated files +# (http://geos.refractions.net/pipermail/geos-devel/2006-March/001828.html): +#NonRobustLineIntersector.cpp +#RobustLineIntersector.cpp Index: source/linearref/LengthIndexOfPoint.cpp =================================================================== --- source/linearref/LengthIndexOfPoint.cpp (revision 0) +++ source/linearref/LengthIndexOfPoint.cpp (revision 0) @@ -0,0 +1,124 @@ +/********************************************************************** + * $Id: LineIntersector.cpp 1938 2006-12-07 10:45:16Z strk $ + * + * GEOS - Geometry Engine Open Source + * http://geos.refractions.net + * + * Copyright (C) 2005-2006 Refractions Research Inc. + * Copyright (C) 2001-2002 Vivid Solutions Inc. + * + * 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: algorithm/RobustLineIntersector.java rev. 1.35 + * + **********************************************************************/ + +#include <geos/linearref/ExtractLineByLocation.h> +#include <geos/linearref/LengthIndexedLine.h> +#include <geos/linearref/LinearIterator.h> +#include <geos/linearref/LengthLocationMap.h> +#include <geos/linearref/LengthIndexOfPoint.h> +#include <geos/util/IllegalArgumentException.h> + +#include <limits> + +using namespace std; + +using namespace geos::geom; + +namespace geos +{ +namespace linearref // geos.linearref +{ + +double LengthIndexOfPoint::indexOf(Geometry *linearGeom, Coordinate& inputPt) +{ + LengthIndexOfPoint locater(linearGeom); + return locater.indexOf(inputPt); +} + +double LengthIndexOfPoint::indexOfAfter(Geometry *linearGeom, Coordinate& inputPt, double minIndex) +{ + LengthIndexOfPoint locater(linearGeom); + return locater.indexOfAfter(inputPt, minIndex); +} + +LengthIndexOfPoint::LengthIndexOfPoint(Geometry *linearGeom): + linearGeom(linearGeom) {} + +double LengthIndexOfPoint::indexOf(Coordinate& inputPt) +{ + return indexOfFromStart(inputPt, -1.0); +} + + +double LengthIndexOfPoint::indexOfAfter(Coordinate& inputPt, double minIndex) +{ + if (minIndex < 0.0) return indexOf(inputPt); + + // sanity check for minIndex at or past end of line + double endIndex = linearGeom->getLength(); + if (endIndex < minIndex) + return endIndex; + + double closestAfter = indexOfFromStart(inputPt, minIndex); + /** + * Return the minDistanceLocation found. + * This will not be null, since it was initialized to minLocation + */ + if (closestAfter <= minIndex) + { + throw util::IllegalArgumentException("computed index is before specified minimum index"); + } + return closestAfter; +} + +double LengthIndexOfPoint::indexOfFromStart(Coordinate& inputPt, double minIndex) +{ + double minDistance = numeric_limits<double>::max(); + + double ptMeasure = minIndex; + double segmentStartMeasure = 0.0; + LineSegment seg; + LinearIterator it(linearGeom); + while (it.hasNext()) + { + if (! it.isEndOfLine()) + { + seg.p0 = it.getSegmentStart(); + seg.p1 = it.getSegmentEnd(); + double segDistance = seg.distance(inputPt); + double segMeasureToPt = segmentNearestMeasure(&seg, inputPt, segmentStartMeasure); + if (segDistance < minDistance + && segMeasureToPt > minIndex) + { + ptMeasure = segMeasureToPt; + minDistance = segDistance; + } + segmentStartMeasure += seg.getLength(); + } + it.next(); + } + return ptMeasure; +} + +double LengthIndexOfPoint::segmentNearestMeasure(LineSegment* seg, Coordinate& inputPt, + double segmentStartMeasure) +{ + // found new minimum, so compute location distance of point + double projFactor = seg->projectionFactor(inputPt); + if (projFactor <= 0.0) + return segmentStartMeasure; + if (projFactor <= 1.0) + return segmentStartMeasure + projFactor * seg->getLength(); + // projFactor > 1.0 + return segmentStartMeasure + seg->getLength(); +} +} +} + Index: source/linearref/LengthLocationMap.cpp =================================================================== --- source/linearref/LengthLocationMap.cpp (revision 0) +++ source/linearref/LengthLocationMap.cpp (revision 0) @@ -0,0 +1,122 @@ +/********************************************************************** + * $Id: LengthLocationMap.cpp 1938 2006-12-07 10:45:16Z strk $ + * + * GEOS - Geometry Engine Open Source + * http://geos.refractions.net + * + * Copyright (C) 2005-2006 Refractions Research Inc. + * Copyright (C) 2001-2002 Vivid Solutions Inc. + * + * 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: algorithm/LengthLocationMap.java rev. 1.35 + * + **********************************************************************/ + + +#include <geos/linearref/LengthIndexedLine.h> +#include <geos/linearref/LinearIterator.h> +#include <geos/linearref/LinearLocation.h> +#include <geos/linearref/LengthLocationMap.h> + +using namespace std; + +using namespace geos::geom; + +namespace geos +{ +namespace linearref // geos.linearref +{ + + +LinearLocation LengthLocationMap::getLocation(Geometry* linearGeom, double length) +{ + LengthLocationMap locater(linearGeom); + return locater.getLocation(length); +} + +double LengthLocationMap::getLength(Geometry* linearGeom, const LinearLocation& loc) +{ + LengthLocationMap locater(linearGeom); + return locater.getLength(loc); +} + + +LengthLocationMap::LengthLocationMap(Geometry* linearGeom) : + linearGeom(linearGeom) {} + +LinearLocation LengthLocationMap::getLocation(double length) const +{ + double forwardLength = length; + if (length < 0.0) + { + double lineLen = linearGeom->getLength(); + forwardLength = lineLen + length; + } + return getLocationForward(forwardLength); +} + +LinearLocation LengthLocationMap::getLocationForward(double length) const +{ + if (length <= 0.0) + return LinearLocation(); + + double totalLength = 0.0; + + LinearIterator it (linearGeom); + while (it.hasNext()) + { + if (! it.isEndOfLine()) + { + Coordinate p0 = it.getSegmentStart(); + Coordinate p1 = it.getSegmentEnd(); + double segLen = p1.distance(p0); + // length falls in this segment + if (totalLength + segLen > length) + { + double frac = (length - totalLength) / segLen; + unsigned int compIndex = it.getComponentIndex(); + unsigned int segIndex = it.getVertexIndex(); + return LinearLocation(compIndex, segIndex, frac); + } + totalLength += segLen; + } + it.next(); + } + // length is longer than line - return end location + return LinearLocation::getEndLocation(linearGeom); +} + + +double LengthLocationMap::getLength(const LinearLocation& loc) const +{ + double totalLength = 0.0; + + LinearIterator it(linearGeom); + while (it.hasNext()) + { + if (! it.isEndOfLine()) + { + Coordinate p0 = it.getSegmentStart(); + Coordinate p1 = it.getSegmentEnd(); + double segLen = p1.distance(p0); + // length falls in this segment + if (loc.getComponentIndex() == it.getComponentIndex() + && loc.getSegmentIndex() == it.getVertexIndex()) + { + return totalLength + segLen * loc.getSegmentFraction(); + } + totalLength += segLen; + } + it.next(); + } + return totalLength; +} + +} +} Index: source/linearref/LengthIndexedLine.cpp =================================================================== --- source/linearref/LengthIndexedLine.cpp (revision 0) +++ source/linearref/LengthIndexedLine.cpp (revision 0) @@ -0,0 +1,126 @@ +/********************************************************************** + * $Id: LengthIndexedLine.cpp 1938 2006-12-07 10:45:16Z strk $ + * + * GEOS - Geometry Engine Open Source + * http://geos.refractions.net + * + * Copyright (C) 2005-2006 Refractions Research Inc. + * Copyright (C) 2001-2002 Vivid Solutions Inc. + * + * 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/LengthIndexedLine.java rev. 1.35 + * + **********************************************************************/ + +#include <geos/linearref/ExtractLineByLocation.h> +#include <geos/linearref/LengthIndexedLine.h> +#include <geos/linearref/LinearLocation.h> +#include <geos/linearref/LengthLocationMap.h> +#include <geos/linearref/LengthIndexOfPoint.h> +#include <geos/linearref/LocationIndexOfLine.h> + +using namespace std; + +using namespace geos::geom; + +namespace geos +{ +namespace linearref // geos.linearref +{ + +LengthIndexedLine::LengthIndexedLine(Geometry* linearGeom) : + linearGeom(linearGeom) {} + +Coordinate LengthIndexedLine::extractPoint(double index) +{ + LinearLocation loc = LengthLocationMap::getLocation(linearGeom, index); + Coordinate coord = loc.getCoordinate(linearGeom); + return coord; +} + +Coordinate LengthIndexedLine::extractPoint(double index, double offsetDistance) +{ + LinearLocation loc = LengthLocationMap::getLocation(linearGeom, index); + Coordinate ret; + loc.getSegment(linearGeom)->pointAlongOffset(loc.getSegmentFraction(), offsetDistance, ret); + return ret; +} + + +Geometry *LengthIndexedLine::extractLine(double startIndex, double endIndex) +{ + + LinearLocation startLoc = locationOf(startIndex); + LinearLocation endLoc = locationOf(endIndex); + Geometry* g = ExtractLineByLocation::extract(linearGeom, startLoc, endLoc); + return g; +} + +LinearLocation LengthIndexedLine::locationOf(double index) +{ + return LengthLocationMap::getLocation(linearGeom, index); +} + + +double LengthIndexedLine::indexOf(Coordinate& pt) +{ + return LengthIndexOfPoint::indexOf(linearGeom, pt); +} + + +double LengthIndexedLine::indexOfAfter(Coordinate& pt, double minIndex) +{ + return LengthIndexOfPoint::indexOfAfter(linearGeom, pt, minIndex); +} + + +double* LengthIndexedLine::indicesOf(Geometry* subLine) +{ + LinearLocation* locIndex = LocationIndexOfLine::indicesOf(linearGeom, subLine); + double* index = new double[2]; + index[0] = LengthLocationMap::getLength(linearGeom, locIndex[0]); + index[1] = LengthLocationMap::getLength(linearGeom, locIndex[1]); + delete locIndex; + return index; +} + + +double LengthIndexedLine::project(Coordinate pt) +{ + return LengthIndexOfPoint::indexOf(linearGeom, pt); +} + +double LengthIndexedLine::getStartIndex() +{ + return 0.0; +} + +double LengthIndexedLine::getEndIndex() +{ + return linearGeom->getLength(); +} + +bool LengthIndexedLine::isValidIndex(double index) +{ + return (index >= getStartIndex() + && index <= getEndIndex()); +} + +double LengthIndexedLine::clampIndex(double index) +{ + double startIndex = getStartIndex(); + if (index < startIndex) return startIndex; + + double endIndex = getEndIndex(); + if (index > endIndex) return endIndex; + + return index; +} +} +} Index: source/linearref/LinearGeometryBuilder.cpp =================================================================== --- source/linearref/LinearGeometryBuilder.cpp (revision 0) +++ source/linearref/LinearGeometryBuilder.cpp (revision 0) @@ -0,0 +1,141 @@ +/********************************************************************** + * $Id: ExtractLineByLocation.cpp 1938 2006-12-07 10:45:16Z strk $ + * + * GEOS - Geometry Engine Open Source + * http://geos.refractions.net + * + * Copyright (C) 2005-2006 Refractions Research Inc. + * Copyright (C) 2001-2002 Vivid Solutions Inc. + * + * 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/ExtractLineByLocation.java rev. 1.35 + * + **********************************************************************/ + +#include <geos/geom/CoordinateSequence.h> +#include <geos/geom/CoordinateArraySequence.h> +#include <geos/geom/LineString.h> +#include <geos/linearref/ExtractLineByLocation.h> +#include <geos/linearref/LengthIndexedLine.h> +#include <geos/linearref/LinearLocation.h> +#include <geos/linearref/LengthLocationMap.h> +#include <geos/linearref/LengthIndexOfPoint.h> +#include <geos/linearref/LinearGeometryBuilder.h> +#include <geos/util/IllegalArgumentException.h> + +using namespace std; + +using namespace geos::geom; + +namespace geos +{ +namespace linearref // geos.linearref +{ + +LinearGeometryBuilder::LinearGeometryBuilder(const GeometryFactory* geomFact) : + geomFact(geomFact), + ignoreInvalidLines(false), + fixInvalidLines(false), + coordList(0) {} + +void LinearGeometryBuilder::setIgnoreInvalidLines(bool ignoreInvalidLines) +{ + this->ignoreInvalidLines = ignoreInvalidLines; +} + +/** + * Allows invalid lines to be ignored rather than causing Exceptions. + * An invalid line is one which has only one unique point. + * + * @param ignoreShortLines <code>true</code> if short lines are to be ignored + */ +void LinearGeometryBuilder::setFixInvalidLines(bool fixInvalidLines) +{ + this->fixInvalidLines = fixInvalidLines; +} + +/** + * Adds a point to the current line. + * + * @param pt the Coordinate to add + */ +void LinearGeometryBuilder::add(const Coordinate& pt) +{ + add(pt, true); +} + +/** + * Adds a point to the current line. + * + * @param pt the Coordinate to add + */ +void LinearGeometryBuilder::add(const Coordinate& pt, bool allowRepeatedPoints) +{ + if (!coordList) + coordList = new CoordinateArraySequence(); + coordList->add(pt, allowRepeatedPoints); + lastPt = pt; +} + +Coordinate LinearGeometryBuilder::getLastCoordinate() const +{ + return lastPt; +} + +/** + * Terminate the current LineString. + */ +void LinearGeometryBuilder::endLine() +{ + if (!coordList) + { + return; + } + if (coordList->size() < 2) + { + if (ignoreInvalidLines) + { + if (coordList) + { + delete coordList; + coordList = 0; + } + return; + } + else if (fixInvalidLines) + { + add((*coordList)[0]); + } + } + + LineString* line = 0; + try + { + line = geomFact->createLineString(coordList); + } + catch (util::IllegalArgumentException ex) + { + // exception is due to too few points in line. + // only propagate if not ignoring short lines + if (! ignoreInvalidLines) + throw ex; + } + + if (line) lines.push_back(line); + coordList = 0; +} + +Geometry* LinearGeometryBuilder::getGeometry() +{ + // end last line in case it was not done by user + endLine(); + return geomFact->buildGeometry(lines); +} +} +} Index: source/linearref/LocationIndexOfLine.cpp =================================================================== --- source/linearref/LocationIndexOfLine.cpp (revision 0) +++ source/linearref/LocationIndexOfLine.cpp (revision 0) @@ -0,0 +1,77 @@ +/********************************************************************** + * $Id: LengthIndexedLine.cpp 1938 2006-12-07 10:45:16Z strk $ + * + * GEOS - Geometry Engine Open Source + * http://geos.refractions.net + * + * Copyright (C) 2005-2006 Refractions Research Inc. + * Copyright (C) 2001-2002 Vivid Solutions Inc. + * + * 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/LengthIndexedLine.java rev. 1.35 + * + **********************************************************************/ + +#include <geos/geom/Geometry.h> +#include <geos/geom/LineString.h> +#include <geos/linearref/LinearLocation.h> +#include <geos/linearref/LocationIndexOfLine.h> +#include <geos/linearref/LocationIndexOfPoint.h> + +using namespace std; + +using namespace geos::geom; + +namespace geos +{ +namespace linearref // geos.linearref +{ + +/** + * Determines the location of a subline along a linear {@link Geometry}. + * The location is reported as a pair of {@link LinearLocation}s. + * <p> + * <b>Note:</b> Currently this algorithm is not guaranteed to + * return the correct substring in some situations where + * an endpoint of the test line occurs more than once in the input line. + * (However, the common case of a ring is always handled correctly). + */ + +LinearLocation* LocationIndexOfLine::indicesOf(Geometry* linearGeom, Geometry* subLine) +{ + LocationIndexOfLine locater(linearGeom); + return locater.indicesOf(subLine); +} + +LocationIndexOfLine::LocationIndexOfLine(Geometry* linearGeom) : + linearGeom(linearGeom) {} + +LinearLocation* LocationIndexOfLine::indicesOf(Geometry* subLine) const +{ + Coordinate startPt = dynamic_cast<const LineString*> (subLine->getGeometryN(0))->getCoordinateN(0); + const LineString* lastLine = dynamic_cast<const LineString*> (subLine->getGeometryN(subLine->getNumGeometries() - 1)); + Coordinate endPt = lastLine->getCoordinateN(lastLine->getNumPoints() - 1); + + LocationIndexOfPoint locPt(linearGeom); + LinearLocation *subLineLoc = new LinearLocation[2]; + subLineLoc[0] = locPt.indexOf(startPt); + + // check for case where subline is zero length + if (subLine->getLength() == 0.0) + { + subLineLoc[1] = subLineLoc[0]; + } + else + { + subLineLoc[1] = locPt.indexOfAfter(endPt, &subLineLoc[0]); + } + return subLineLoc; +} +} +} Index: source/Makefile.am =================================================================== --- source/Makefile.am (revision 2616) +++ source/Makefile.am (working copy) @@ -4,6 +4,7 @@ headers \ index \ io \ + linearref \ noding \ operation \ planargraph \ @@ -31,6 +32,7 @@ geomgraph/libgeomgraph.la \ index/libindex.la \ io/libio.la \ + linearref/liblinearref.la \ noding/libnoding.la \ operation/liboperation.la \ planargraph/libplanargraph.la \ Index: source/headers/geos/linearref/LengthIndexedLine.h =================================================================== --- source/headers/geos/linearref/LengthIndexedLine.h (revision 0) +++ source/headers/geos/linearref/LengthIndexedLine.h (revision 0) @@ -0,0 +1,203 @@ +/********************************************************************** + * $Id: LengthIndexedLine.h 1938 2009-07-23 10:45:16Z novalis $ + * + * GEOS - Geometry Engine Open Source + * http://geos.refractions.net + * + * Copyright (C) 2005-2006 Refractions Research Inc. + * Copyright (C) 2001-2002 Vivid Solutions Inc. + * + * 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/LengthIndexedLine.java rev. 1.10 + * + **********************************************************************/ + +#ifndef GEOS_LINEARREF_LENGTHINDEXEDLINE_H +#define GEOS_LINEARREF_LENGTHINDEXEDLINE_H + +#include <geos/geom/Coordinate.h> +#include <geos/geom/Geometry.h> +#include <geos/linearref/LinearLocation.h> + +namespace geos +{ +namespace linearref // geos::linearref +{ + +/** \brief + * Supports linear referencing along a linear {@link Geometry} + * using the length along the line as the index. + * Negative length values are taken as measured in the reverse direction + * from the end of the geometry. + * Out-of-range index values are handled by clamping + * them to the valid range of values. + * Non-simple lines (i.e. which loop back to cross or touch + * themselves) are supported. + */ + +class LengthIndexedLine +{ +private: + geom::Geometry *linearGeom; + LinearLocation locationOf(double index); + +public: + + /** \brief + * Constructs an object which allows a linear {@link Geometry} + * to be linearly referenced using length as an index. + * + * @param linearGeom the linear geometry to reference along + */ + + LengthIndexedLine(geom::Geometry *linearGeom); + + /** \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(double index); + + + /** + * 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(double index, double offsetDistance); + + /** + * 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(double startIndex, double endIndex); + + + /** + * Computes the minimum index for a point on the line. + * If the line is not simple (i.e. loops back on itself) + * a single point may have more than one possible index. + * In this case, the smallest index is returned. + * + * 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 minimum index of the point + * + * @see project + */ + double indexOf(geom::Coordinate& pt); + + /** + * 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 + */ + double indexOfAfter(geom::Coordinate& pt, double minIndex); + + /** + * 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 occcur in the same order). + * + * @param subLine a subLine of the line + * @return a pair of indices for the start and end of the subline. + */ + double* indicesOf(geom::Geometry *subLine); + + + /** + * 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 + */ + double project(geom::Coordinate pt); + + /** + * Returns the index of the start of the line + * @return the start index + */ + double getStartIndex(); + + /** + * Returns the index of the end of the line + * @return the end index + */ + double getEndIndex(); + + /** + * 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(double index); + + + /** + * Computes a valid index for this line + * by clamping the given index to the valid range of index values + * + * @return a valid index value + */ + double clampIndex(double index); +}; +} +} +#endif Index: source/headers/geos/linearref/LinearGeometryBuilder.h =================================================================== --- source/headers/geos/linearref/LinearGeometryBuilder.h (revision 0) +++ source/headers/geos/linearref/LinearGeometryBuilder.h (revision 0) @@ -0,0 +1,98 @@ +/********************************************************************** + * $Id: LinearGeometryBuilder.h 1938 2009-07-23 10:45:16Z novalis $ + * + * GEOS - Geometry Engine Open Source + * http://geos.refractions.net + * + * Copyright (C) 2005-2006 Refractions Research Inc. + * Copyright (C) 2001-2002 Vivid Solutions Inc. + * + * 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/LinearGeometryBuilder.java rev. 1.10 + * + **********************************************************************/ + +#ifndef GEOS_LINEARREF_LINEARGEOMETRYBUILDER_H +#define GEOS_LINEARREF_LINEARGEOMETRYBUILDER_H + +#include <geos/geom/Coordinate.h> +#include <geos/geom/CoordinateList.h> +#include <geos/geom/Geometry.h> +#include <geos/geom/GeometryFactory.h> +#include <geos/linearref/LinearLocation.h> + +#include <vector> + +namespace geos +{ +namespace linearref // geos::linearref +{ + +/** + * Builds a linear geometry ({@link LineString} or {@link MultiLineString}) + * incrementally (point-by-point). + * + * @version 1.7 + */ +class LinearGeometryBuilder +{ +private: + const geom::GeometryFactory* geomFact; + std::vector<geom::Geometry *> lines; + + bool ignoreInvalidLines; + bool fixInvalidLines; + geom::CoordinateSequence* coordList; + + geom::Coordinate lastPt; + +public: + LinearGeometryBuilder(const geom::GeometryFactory* geomFact); + + /** + * Allows invalid lines to be ignored rather than causing Exceptions. + * An invalid line is one which has only one unique point. + * + * @param ignoreShortLines <code>true</code> if short lines are to be ignored + */ + void setIgnoreInvalidLines(bool ignoreInvalidLines); + + /** + * Allows invalid lines to be ignored rather than causing Exceptions. + * An invalid line is one which has only one unique point. + * + * @param ignoreShortLines <code>true</code> if short lines are to be ignored + */ + void setFixInvalidLines(bool fixInvalidLines); + /** + * Adds a point to the current line. + * + * @param pt the Coordinate to add + */ + void add(const geom::Coordinate& pt); + + /** + * Adds a point to the current line. + * + * @param pt the Coordinate to add + */ + void add(const geom::Coordinate& pt, bool allowRepeatedPoints); + + geom::Coordinate getLastCoordinate() const; + + /** + * Terminate the current LineString. + */ + void endLine(); + + geom::Geometry *getGeometry(); +}; +} +} +#endif Index: source/headers/geos/linearref/LocationIndexOfLine.h =================================================================== --- source/headers/geos/linearref/LocationIndexOfLine.h (revision 0) +++ source/headers/geos/linearref/LocationIndexOfLine.h (revision 0) @@ -0,0 +1,62 @@ +/********************************************************************** + * $Id: LinearGeometryBuilder.h 1938 2009-07-23 10:45:16Z novalis $ + * + * GEOS - Geometry Engine Open Source + * http://geos.refractions.net + * + * Copyright (C) 2005-2006 Refractions Research Inc. + * Copyright (C) 2001-2002 Vivid Solutions Inc. + * + * 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/LinearGeometryBuilder.java rev. 1.10 + * + **********************************************************************/ + +#ifndef GEOS_LINEARREF_LINEARGEOMETRYBUILDER_H +#define GEOS_LINEARREF_LINEARGEOMETRYBUILDER_H + +#include <geos/geom/Coordinate.h> +#include <geos/geom/Geometry.h> +#include <geos/linearref/LinearLocation.h> + +namespace geos +{ +namespace linearref // geos::linearref +{ + +/** + * Determines the location of a subline along a linear {@link Geometry}. + * The location is reported as a pair of {@link LinearLocation}s. + * <p> + * <b>Note:</b> Currently this algorithm is not guaranteed to + * return the correct substring in some situations where + * an endpoint of the test line occurs more than once in the input line. + * (However, the common case of a ring is always handled correctly). + */ +class LocationIndexOfLine +{ + /** + * MD - this algorithm has been extracted into a class + * because it is intended to validate that the subline truly is a subline, + * and also to use the internal vertex information to unambiguously locate the subline. + */ +private: + geom::Geometry* linearGeom; + +public: + static LinearLocation* indicesOf(geom::Geometry* linearGeom, geom::Geometry* subLine); + + LocationIndexOfLine(geom::Geometry* linearGeom); + + LinearLocation* indicesOf(geom::Geometry* subLine) const; +}; +} +} + +#endif Index: source/headers/geos/linearref/LocationIndexOfPoint.h =================================================================== --- source/headers/geos/linearref/LocationIndexOfPoint.h (revision 0) +++ source/headers/geos/linearref/LocationIndexOfPoint.h (revision 0) @@ -0,0 +1,81 @@ +/********************************************************************** + * $Id: LinearGeometryBuilder.h 1938 2009-07-23 10:45:16Z novalis $ + * + * GEOS - Geometry Engine Open Source + * http://geos.refractions.net + * + * Copyright (C) 2005-2006 Refractions Research Inc. + * Copyright (C) 2001-2002 Vivid Solutions Inc. + * + * 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/LinearGeometryBuilder.java rev. 1.10 + * + **********************************************************************/ + +#ifndef GEOS_LINEARREF_LOCATIONINDEXOFPOINT_H +#define GEOS_LINEARREF_LOCATIONINDEXOFPOINT_H + +#include <geos/geom/Coordinate.h> +#include <geos/geom/Geometry.h> +#include <geos/linearref/LinearLocation.h> + +namespace geos +{ +namespace linearref // geos::linearref +{ + +/** + * Computes the {@link LinearLocation} of the point + * on a linear {@link Geometry} nearest a given {@link Coordinate}. + * The nearest point is not necessarily unique; this class + * always computes the nearest point closest to + * the start of the geometry. + */ +class LocationIndexOfPoint +{ + +private: + geom::Geometry *linearGeom; + + LinearLocation indexOfFromStart(const geom::Coordinate& inputPt, LinearLocation* minIndex) const; + +public: + static LinearLocation indexOf(geom::Geometry *linearGeom, const geom::Coordinate& inputPt); + + static LinearLocation indexOfAfter(geom::Geometry *linearGeom, const geom::Coordinate& inputPt, LinearLocation* minIndex); + + LocationIndexOfPoint(geom::Geometry *linearGeom); + + /** + * Find the nearest location along a linear {@link Geometry} to a given point. + * + * @param inputPt the coordinate to locate + * @return the location of the nearest point + */ + LinearLocation indexOf(const geom::Coordinate& inputPt) const; + /** + * Find the nearest {@link LinearLocation} along the linear {@link Geometry} + * to a given {@link Coordinate} + * after the specified minimum {@link LinearLocation}. + * If possible the location returned will be strictly greater than the + * <code>minLocation</code>. + * If this is not possible, the + * value returned will equal <code>minLocation</code>. + * (An example where this is not possible is when + * minLocation = [end of line] ). + * + * @param inputPt the coordinate to locate + * @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; +}; +} +} +#endif Index: source/headers/geos/linearref/LinearLocation.h =================================================================== --- source/headers/geos/linearref/LinearLocation.h (revision 0) +++ source/headers/geos/linearref/LinearLocation.h (revision 0) @@ -0,0 +1,238 @@ +/********************************************************************** + * $Id: LinearLocation.h 1938 2009-07-23 10:45:16Z novalis $ + * + * GEOS - Geometry Engine Open Source + * http://geos.refractions.net + * + * Copyright (C) 2005-2006 Refractions Research Inc. + * Copyright (C) 2001-2002 Vivid Solutions Inc. + * + * 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/LinearLocation.java rev. 1.10 + * + **********************************************************************/ + +#ifndef GEOS_LINEARREF_LINEARLOCATION_H +#define GEOS_LINEARREF_LINEARLOCATION_H + +#include <string> + +#include <geos/geom/Coordinate.h> +#include <geos/geom/Geometry.h> +#include <geos/geom/LineSegment.h> + +namespace geos +{ +namespace linearref // geos::linearref +{ + + +/** + * Represents a location along a {@link LineString} or {@link MultiLineString}. + * The referenced geometry is not maintained within + * this location, but must be provided for operations which require it. + * Various methods are provided to manipulate the location value + * and query the geometry it references. + */ +class LinearLocation +{ +private: + unsigned int componentIndex; + unsigned int segmentIndex; + double segmentFraction; + + /** + * Ensures the individual values are locally valid. + * Does <b>not</b> ensure that the indexes are valid for + * a particular linear geometry. + * + * @see clamp + */ + void normalize(); + +public: + /** + * Gets a location which refers to the end of a linear {@link Geometry}. + * @param linear the linear geometry + * @return a new <tt>LinearLocation</tt> + */ + static LinearLocation getEndLocation(geom::Geometry* linear); + + /** + * Computes the {@link Coordinate} of a point a given fraction + * along the line segment <tt>(p0, p1)</tt>. + * If the fraction is greater than 1.0 the last + * point of the segment is returned. + * If the fraction is less than or equal to 0.0 the first point + * of the segment is returned. + * The Z ordinate is interpolated from the Z-ordinates of the given points, + * if they are specified. + * + * @param p0 the first point of the line segment + * @param p1 the last point of the line segment + * @param frac the length to the desired point + * @return the <tt>Coordinate</tt> of the desired point + */ + static geom::Coordinate pointAlongSegmentByFraction(geom::Coordinate& p0, geom::Coordinate& p1, double frac); + + + /** + * Creates a location referring to the start of a linear geometry + */ + + LinearLocation(unsigned int segmentIndex = 0, double segmentFraction = 0.0); + + LinearLocation(unsigned int componentIndex, unsigned int segmentIndex, double segmentFraction); + + /** + * Ensures the indexes are valid for a given linear {@link Geometry}. + * + * @param linear a linear geometry + */ + void clamp(geom::Geometry* linear); + + /** + * Snaps the value of this location to + * the nearest vertex on the given linear {@link Geometry}, + * if the vertex is closer than <tt>minDistance</tt>. + * + * @param linearGeom a linear geometry + * @param minDistance the minimum allowable distance to a vertex + */ + void snapToVertex(geom::Geometry* linearGeom, double minDistance); + + /** + * Gets the length of the segment in the given + * Geometry containing this location. + * + * @param linearGeom a linear geometry + * @return the length of the segment + */ + double getSegmentLength(geom::Geometry* linearGeom) const; + /** + * Sets the value of this location to + * refer the end of a linear geometry + * + * @param linear the linear geometry to set + */ + void setToEnd(geom::Geometry* linear); + + /** + * Gets the component index for this location. + * + * @return the component index + */ + unsigned int getComponentIndex() const; + + /** + * Gets the segment index for this location + * + * @return the segment index + */ + unsigned int getSegmentIndex() const; + + /** + * Gets the segment fraction for this location + * + * @return the segment fraction + */ + double getSegmentFraction() const; + + /** + * Tests whether this location refers to a vertex + * + * @return true if the location is a vertex + */ + bool isVertex() const; + + /** + * Gets the {@link Coordinate} along the + * given linear {@link Geometry} which is + * referenced by this location. + * + * @param linearGeom a linear geometry + * @return the <tt>Coordinate</tt> at the location + */ + geom::Coordinate getCoordinate(geom::Geometry* linearGeom) const; + + /** + * Gets a {@link LineSegment} representing the segment of the + * given linear {@link Geometry} which contains this location. + * + * @param linearGeom a linear geometry + * @return the <tt>LineSegment</tt> containing the location + */ + geom::LineSegment *getSegment(geom::Geometry* linearGeom) const; + + /** + * Tests whether this location refers to a valid + * location on the given linear {@link Geometry}. + * + * @param linearGeom a linear geometry + * @return true if this location is valid + */ + bool isValid(geom::Geometry* linearGeom) const; + + /** + * Compares this object with the specified object for order. + * + *@param o the <code>LineStringLocation</code> with which this <code>Coordinate</code> + * is being compared + *@return a negative integer, zero, or a positive integer as this <code>LineStringLocation</code> + * is less than, equal to, or greater than the specified <code>LineStringLocation</code> + */ + int compareTo(const LinearLocation& other) const; + + /** + * Compares this object with the specified index values for order. + * + * @param componentIndex1 a component index + * @param segmentIndex1 a segment index + * @param segmentFraction1 a segment fraction + * @return a negative integer, zero, or a positive integer as this <code>LineStringLocation</code> + * is less than, equal to, or greater than the specified locationValues + */ + int compareLocationValues(unsigned int componentIndex1, unsigned int segmentIndex1, double segmentFraction1) const; + + /** + * Compares two sets of location values for order. + * + * @param componentIndex0 a component index + * @param segmentIndex0 a segment index + * @param segmentFraction0 a segment fraction + * @param componentIndex1 another component index + * @param segmentIndex1 another segment index + * @param segmentFraction1 another segment fraction + *@return a negative integer, zero, or a positive integer + * as the first set of location values + * is less than, equal to, or greater than the second set of locationValues + */ + static int compareLocationValues( + unsigned int componentIndex0, unsigned int segmentIndex0, double segmentFraction0, + unsigned int componentIndex1, unsigned int segmentIndex1, double segmentFraction1); + + /** + * Tests whether two locations + * are on the same segment in the parent {@link Geometry}. + * + * @param loc a location on the same geometry + * @return true if the locations are on the same segment of the parent geometry + */ + bool isOnSameSegment(const LinearLocation& loc) const; + + + friend std::ostream& operator<< (std::ostream& out, const LinearLocation& obj ); + +}; + + +} +} + +#endif Index: source/headers/geos/linearref/Makefile.am =================================================================== --- source/headers/geos/linearref/Makefile.am (revision 0) +++ source/headers/geos/linearref/Makefile.am (revision 0) @@ -0,0 +1,15 @@ + +EXTRA_DIST = + +geosdir = $(includedir)/geos/algorithm + +geos_HEADERS = \ + ExtractLineByLocation.h \ + LengthIndexedLine.h \ + LengthIndexOfPoint.h \ + LengthLocationMap.h \ + LinearIterator.h \ + LinearGeometryBuilder.h \ + LinearLocation.h \ + LocationIndexOfLine.h \ + LocationIndexOfPoint.h Index: source/headers/geos/linearref/LinearIterator.h =================================================================== --- source/headers/geos/linearref/LinearIterator.h (revision 0) +++ source/headers/geos/linearref/LinearIterator.h (revision 0) @@ -0,0 +1,154 @@ +/********************************************************************** + * $Id: LinearIterator.h 1938 2009-07-23 10:45:16Z novalis $ + * + * GEOS - Geometry Engine Open Source + * http://geos.refractions.net + * + * Copyright (C) 2005-2006 Refractions Research Inc. + * Copyright (C) 2001-2002 Vivid Solutions Inc. + * + * 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/LinearIterator.java rev. 1.10 + * + **********************************************************************/ + +#ifndef GEOS_LINEARREF_LINEARITERATOR_H +#define GEOS_LINEARREF_LINEARITERATOR_H + +#include <string> + +#include <geos/geom/Coordinate.h> +#include <geos/geom/Geometry.h> +#include <geos/geom/LineSegment.h> +#include <geos/linearref/LinearLocation.h> + +namespace geos +{ +namespace linearref // geos::linearref +{ + +/** + * An iterator over the components and coordinates of a linear geometry + * ({@link LineString}s and {@link MultiLineString}s. + * + * The standard usage pattern for a {@link LinearIterator} is: + * + * <pre> + * for (LinearIterator it = new LinearIterator(...); it.hasNext(); it.next()) { + * ... + * int ci = it.getComponentIndex(); // for example + * int vi = it.getVertexIndex(); // for example + * ... + * } + * </pre> + * + * @version 1.7 + */ +class LinearIterator +{ +private: + static unsigned int segmentEndVertexIndex(const LinearLocation& loc); + + const geom::LineString *currentLine; + unsigned int vertexIndex; + unsigned int componentIndex; + geom::Geometry *linear; + const unsigned int numLines; + + /** + * Invariant: currentLine <> null if the iterator is pointing at a valid coordinate + */ + + void loadCurrentLine(); + + +public: + /** + * Creates an iterator initialized to the start of a linear {@link Geometry} + * + * @param linear the linear geometry to iterate over + */ + LinearIterator(geom::Geometry *linear); + + /** + * Creates an iterator starting at + * a {@link LinearLocation} on a linear {@link Geometry} + * + * @param linear the linear geometry to iterate over + * @param start the location to start at + */ + LinearIterator(geom::Geometry *linear, const LinearLocation& start); + + /** + * Creates an iterator starting at + * a component and vertex in a linear {@link Geometry} + * + * @param linear the linear geometry to iterate over + * @param componentIndex the component to start at + * @param vertexIndex the vertex to start at + */ + LinearIterator(geom::Geometry *linear, unsigned int componentIndex, unsigned int vertexIndex); + + /** + * Tests whether there are any vertices left to iterator over. + * @return <code>true</code> if there are more vertices to scan + */ + bool hasNext() const; + + + /** + * Moves the iterator ahead to the next vertex and (possibly) linear component. + */ + void next(); + + /** + * Checks whether the iterator cursor is pointing to the + * endpoint of a linestring. + * + * @return <code>true</true> if the iterator is at an endpoint + */ + bool isEndOfLine() const; + + /** + * The component index of the vertex the iterator is currently at. + * @return the current component index + */ + unsigned int getComponentIndex() const; + + /** + * The vertex index of the vertex the iterator is currently at. + * @return the current vertex index + */ + unsigned int getVertexIndex() const; + + /** + * Gets the {@link LineString} component the iterator is current at. + * @return a linestring + */ + const geom::LineString* getLine() const; + + /** + * Gets the first {@link Coordinate} of the current segment. + * (the coordinate of the current vertex). + * @return a {@link Coordinate} + */ + geom::Coordinate getSegmentStart() const; + + /** + * Gets the second {@link Coordinate} of the current segment. + * (the coordinate of the next vertex). + * If the iterator is at the end of a line, <code>null</code> is returned. + * + * @return a {@link Coordinate} or <code>null</code> + */ + geom::Coordinate getSegmentEnd() const; +}; +} +} +#endif Index: source/headers/geos/linearref/ExtractLineByLocation.h =================================================================== --- source/headers/geos/linearref/ExtractLineByLocation.h (revision 0) +++ source/headers/geos/linearref/ExtractLineByLocation.h (revision 0) @@ -0,0 +1,91 @@ +/********************************************************************** + * $Id: ExtractLineByLocation.h 1938 2009-07-23 10:45:16Z novalis $ + * + * GEOS - Geometry Engine Open Source + * http://geos.refractions.net + * + * Copyright (C) 2005-2006 Refractions Research Inc. + * Copyright (C) 2001-2002 Vivid Solutions Inc. + * + * 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/ExtractLineByLocation.java rev. 1.10 + * + **********************************************************************/ + +#ifndef GEOS_LINEARREF_EXTRACTLINEBYLOCATION_H +#define GEOS_LINEARREF_EXTRACTLINEBYLOCATION_H + +#include <geos/geom/Coordinate.h> +#include <geos/geom/Geometry.h> +#include <geos/linearref/LinearLocation.h> + +namespace geos +{ +namespace linearref // geos::linearref +{ + +/** + * Extracts the subline of a linear {@link Geometry} between + * two {@link LinearLocation}s on the line. + */ +class ExtractLineByLocation +{ + +private: + geom::Geometry *line; + geom::Geometry *reverse(geom::Geometry *linear); + + /** + * Assumes input is valid (e.g. start <= end) + * + * @param start + * @param end + * @return a linear geometry + */ + geom::LineString* computeLine(const LinearLocation& start, const LinearLocation& end); + + /** + * Assumes input is valid (e.g. start <= end) + * + * @param start + * @param end + * @return a linear geometry + */ + geom::Geometry *computeLinear(const LinearLocation& start, const LinearLocation& end); + +public: + /** + * Computes the subline of a {@link LineString} between + * two {@link LineStringLocation}s on the line. + * If the start location is after the end location, + * the computed geometry is reversed. + * + * @param line the line to use as the baseline + * @param start the start location + * @param end the end location + * @return the extracted subline + */ + static geom::Geometry *extract(geom::Geometry *line, const LinearLocation& start, const LinearLocation& end); + + ExtractLineByLocation(geom::Geometry *line); + + /** + * Extracts a subline of the input. + * If <code>end < start</code> the linear geometry computed will be reversed. + * + * @param start the start location + * @param end the end location + * @return a linear geometry + */ + geom::Geometry *extract(const LinearLocation& start, const LinearLocation& end); + +}; +} +} +#endif Index: source/headers/geos/linearref/LengthLocationMap.h =================================================================== --- source/headers/geos/linearref/LengthLocationMap.h (revision 0) +++ source/headers/geos/linearref/LengthLocationMap.h (revision 0) @@ -0,0 +1,91 @@ +/********************************************************************** + * $Id: LengthLocationMap.h 1938 2009-07-23 10:45:16Z novalis $ + * + * GEOS - Geometry Engine Open Source + * http://geos.refractions.net + * + * Copyright (C) 2005-2006 Refractions Research Inc. + * Copyright (C) 2001-2002 Vivid Solutions Inc. + * + * 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/LengthLocationMap.java rev. 1.10 + * + **********************************************************************/ + +#ifndef GEOS_LINEARREF_LENGTHLOCATIONMAP_H +#define GEOS_LINEARREF_LENGTHLOCATIONMAP_H + +#include <geos/geom/Coordinate.h> +#include <geos/geom/Geometry.h> +#include <geos/linearref/LinearLocation.h> + +namespace geos +{ +namespace linearref // geos::linearref +{ + +/** + * Computes the {@link LinearLocation} for a given length + * along a linear {@link Geometry}. + * Negative lengths are measured in reverse from end of the linear geometry. + * Out-of-range values are clamped. + */ +class LengthLocationMap +{ + + +private: + geom::Geometry *linearGeom; + + LinearLocation getLocationForward(double length) const; + +public: + + // TODO: cache computed cumulative length for each vertex + // TODO: support user-defined measures + // TODO: support measure index for fast mapping to a location + + /** + * 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 + * @return the {@link LinearLocation} for the length + */ + static LinearLocation getLocation(geom::Geometry *linearGeom, double length); + + /** + * Computes the length for a given {@link LinearLocation} + * on a linear {@link Geometry}. + * + * @param line the linear geometry to use + * @param loc the {@link LinearLocation} index of the location + * @return the length for the {@link LinearLocation} + */ + static double getLength(geom::Geometry *linearGeom, const LinearLocation& loc); + + LengthLocationMap(geom::Geometry *linearGeom); + + /** + * 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. + * + * @param length the length index + * @return the corresponding LinearLocation + */ + LinearLocation getLocation(double length) const; + + double getLength(const LinearLocation& loc) const; + +}; +} +} +#endif Index: source/headers/geos/linearref/LengthIndexOfPoint.h =================================================================== --- source/headers/geos/linearref/LengthIndexOfPoint.h (revision 0) +++ source/headers/geos/linearref/LengthIndexOfPoint.h (revision 0) @@ -0,0 +1,82 @@ +/********************************************************************** + * $Id: LengthIndexOfPoint.h 1938 2009-07-23 10:45:16Z novalis $ + * + * GEOS - Geometry Engine Open Source + * http://geos.refractions.net + * + * Copyright (C) 2005-2006 Refractions Research Inc. + * Copyright (C) 2001-2002 Vivid Solutions Inc. + * + * 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/LengthIndexOfPoint.java rev. 1.10 + * + **********************************************************************/ + +#ifndef GEOS_LINEARREF_LENGTHINDEXOFPOINT_H +#define GEOS_LINEARREF_LENGTHINDEXOFPOINT_H + +#include <string> + +#include <geos/geom/Coordinate.h> +#include <geos/geom/Geometry.h> +#include <geos/geom/LineSegment.h> +#include <geos/linearref/LinearLocation.h> + + +namespace geos +{ +namespace linearref // geos::linearref +{ + +class LengthIndexOfPoint +{ + +private: + geom::Geometry *linearGeom; + + double indexOfFromStart(geom::Coordinate& inputPt, double minIndex); + + double segmentNearestMeasure(geom::LineSegment *seg, geom::Coordinate& inputPt, + double segmentStartMeasure); +public: + static double indexOf(geom::Geometry *linearGeom, geom::Coordinate& inputPt); + + static double indexOfAfter(geom::Geometry *linearGeom, geom::Coordinate& inputPt, double minIndex); + + LengthIndexOfPoint(geom::Geometry *linearGeom); + + /** + * Find the nearest location along a linear {@link Geometry} to a given point. + * + * @param inputPt the coordinate to locate + * @return the location of the nearest point + */ + double indexOf(geom::Coordinate& inputPt); + + /** + * Finds the nearest index along the linear {@link Geometry} + * to a given {@link Coordinate} + * after the specified minimum index. + * If possible the location returned will be strictly greater than the + * <code>minLocation</code>. + * If this is not possible, the + * value returned will equal <code>minLocation</code>. + * (An example where this is not possible is when + * minLocation = [end of line] ). + * + * @param inputPt the coordinate to locate + * @param minLocation the minimum location for the point location + * @return the location of the nearest point + */ + double indexOfAfter(geom::Coordinate& inputPt, double minIndex); + +}; +} +} +#endif Index: source/headers/geos/geom/CoordinateList.h =================================================================== --- source/headers/geos/geom/CoordinateList.h (revision 2616) +++ source/headers/geos/geom/CoordinateList.h (working copy) @@ -59,6 +59,12 @@ { } + CoordinateList() + : + coords() + { + } + size_type size() const { return coords.size(); Index: source/headers/geos/Makefile.am =================================================================== --- source/headers/geos/Makefile.am (revision 2616) +++ source/headers/geos/Makefile.am (working copy) @@ -4,6 +4,7 @@ geomgraph \ index \ io \ + linearref \ noding \ operation \ planargraph \ Index: tests/unit/linearref/LengthIndexedLineTest.cpp =================================================================== --- tests/unit/linearref/LengthIndexedLineTest.cpp (revision 0) +++ tests/unit/linearref/LengthIndexedLineTest.cpp (revision 0) @@ -0,0 +1,414 @@ +// $Id$ +// +// Ported from JTS junit/linearref/AbstractIndexedLineTest.java rev. 1.10 +// and junit/linearref/LengthIndexedLineTest.java rev. 1.10 + +#include <tut.hpp> +#include <utility.h> +// geos +#include <geos/io/WKTReader.h> +#include <geos/geom/PrecisionModel.h> +#include <geos/geom/GeometryFactory.h> +#include <geos/geom/Geometry.h> // required for use in auto_ptr +#include <geos/geom/LineString.h> +#include <geos/geom/Coordinate.h> +#include <geos/linearref/LengthIndexedLine.h> + +// std +#include <sstream> +#include <string> +#include <memory> + +using namespace geos::geom; +using namespace geos::linearref; +using namespace std; + +/** + * Tests the {@link LocationIndexedLine} class + */ + +namespace tut { + + typedef auto_ptr<Geometry> GeomPtr; + static const double TOLERANCE_DIST = 0.001; + + struct test_lengthindexedline_data { + + test_lengthindexedline_data() + : + pm(), + gf(&pm), + reader(&gf) + { + } + + PrecisionModel pm; + GeometryFactory gf; + geos::io::WKTReader reader; + + void checkExpected(Geometry* result, const string expected) + { + GeomPtr subLine(reader.read(expected)); + ensure_equals_geometry(subLine.get(), result); + } + + void checkExpected(Geometry* result, const Geometry* expected) + { + ensure_equals_geometry(expected, result); + } + + void runIndicesOfThenExtract(string inputStr, + string subLineStr) + { + GeomPtr input(reader.read(inputStr)); + GeomPtr subLine(reader.read(subLineStr)); + GeomPtr result(indicesOfThenExtract(input.get(), subLine.get())); + + checkExpected(result.get(), subLine.get()); + } + + +/* + // example of indicesOfThenLocate method + private Geometry indicesOfThenLocate(LineString input, LineString subLine) + { + LocationIndexedLine indexedLine = new LocationIndexedLine(input); + LineStringLocation[] loc = indexedLine.indicesOf(subLine); + Geometry result = indexedLine.locate(loc[0], loc[1]); + return result; + } +*/ + + bool indexOfAfterCheck(Geometry* linearGeom, Coordinate testPt) + { + LengthIndexedLine indexedLine(linearGeom); + + // check locations are consecutive + double loc1 = indexedLine.indexOf(testPt); + double loc2 = indexedLine.indexOfAfter(testPt, loc1); + if (loc2 <= loc1) return false; + + // check extracted points are the same as the input + Coordinate pt1 = indexedLine.extractPoint(loc1); + Coordinate pt2 = indexedLine.extractPoint(loc2); + if (! pt1.equals2D(testPt)) return false; + if (! pt2.equals2D(testPt)) return false; + + return true; + } + + + void runIndexOfAfterTest(string inputStr, + string testPtWKT) + { + GeomPtr input(reader.read(inputStr)); + GeomPtr testPoint(reader.read(testPtWKT)); + const Coordinate* testPt = testPoint->getCoordinate(); + bool resultOK = indexOfAfterCheck(input.get(), *testPt); + ensure(resultOK); + } + + + void runOffsetTest(const string inputWKT, + const string testPtWKT, double offsetDistance, string expectedPtWKT) + { + GeomPtr input(reader.read(inputWKT)); + GeomPtr testPoint(reader.read(testPtWKT)); + GeomPtr expectedPoint(reader.read(expectedPtWKT)); + const Coordinate* testPt = testPoint->getCoordinate(); + const Coordinate* expectedPt = expectedPoint->getCoordinate(); + Coordinate offsetPt = extractOffsetAt(input.get(), *testPt, offsetDistance); + + bool isOk = offsetPt.distance(*expectedPt) < TOLERANCE_DIST; + if (! isOk) + cout << "Expected = " << *expectedPoint << " Actual = " << offsetPt << endl; + ensure(isOk); + } + + + Coordinate extractOffsetAt(Geometry* linearGeom, Coordinate testPt, double offsetDistance) + { + LengthIndexedLine indexedLine(linearGeom); + double index = indexedLine.indexOf(testPt); + return indexedLine.extractPoint(index, offsetDistance); + } + + void checkExtractLine(const char* wkt, double start, double end, const char* expected) + { + string wktstr(wkt); + GeomPtr linearGeom(reader.read(wktstr)); + LengthIndexedLine indexedLine(linearGeom.get()); + GeomPtr result(indexedLine.extractLine(start, end)); + checkExpected(result.get(), expected); + } + + + Geometry* indicesOfThenExtract(Geometry* linearGeom, Geometry* subLine) + { + LengthIndexedLine indexedLine(linearGeom); + double* loc = indexedLine.indicesOf(subLine); + Geometry* result = indexedLine.extractLine(loc[0], loc[1]); + delete loc; + return result; + } + +}; + typedef test_group<test_lengthindexedline_data> group; + typedef group::object object; + + group test_lengthindexedline_group( + "geos::linearref::LocationIndexedLine"); + + //1 - testML + template<> + template<> + void object::test<1>() + { + runIndicesOfThenExtract("MULTILINESTRING ((0 0, 10 10), (20 20, 30 30))", + "MULTILINESTRING ((1 1, 10 10), (20 20, 25 25))"); +} + + + //2 - testPartOfSegmentNoVertex + template<> + template<> + void object::test<2>() + { + runIndicesOfThenExtract("LINESTRING (0 0, 10 10, 20 20)", + "LINESTRING (1 1, 9 9)"); + } + + //3 - testPartOfSegmentContainingVertex() + template<> + template<> + void object::test<3>() + { + runIndicesOfThenExtract("LINESTRING (0 0, 10 10, 20 20)", + "LINESTRING (5 5, 10 10, 15 15)"); + } + + /** + * Tests that duplicate coordinates are handled correctly. + * + * @throws Exception + */ + // 4 - testPartOfSegmentContainingDuplicateCoords + template<> + template<> + void object::test<4>() + { + runIndicesOfThenExtract("LINESTRING (0 0, 10 10, 10 10, 20 20)", + "LINESTRING (5 5, 10 10, 10 10, 15 15)"); + } + + /** + * Following tests check that correct portion of loop is identified. + * This requires that the correct vertex for (0,0) is selected. + */ + + //5 - testLoopWithStartSubLine + template<> + template<> + void object::test<5>() + { + runIndicesOfThenExtract("LINESTRING (0 0, 0 10, 10 10, 10 0, 0 0)", + "LINESTRING (0 0, 0 10, 10 10)"); + } + + //6 - testLoopWithEndingSubLine() + template<> + template<> + void object::test<6>() + { + runIndicesOfThenExtract("LINESTRING (0 0, 0 10, 10 10, 10 0, 0 0)", + "LINESTRING (10 10, 10 0, 0 0)"); + } + + // test a subline equal to the parent loop + //7 - testLoopWithIdenticalSubLine() + template<> + template<> + void object::test<7>() + { + runIndicesOfThenExtract("LINESTRING (0 0, 0 10, 10 10, 10 0, 0 0)", + "LINESTRING (0 0, 0 10, 10 10, 10 0, 0 0)"); + } + + // test a zero-length subline equal to the start point + //8 - testZeroLenSubLineAtStart() + template<> + template<> + void object::test<8>() + { + runIndicesOfThenExtract("LINESTRING (0 0, 0 10, 10 10, 10 0, 0 0)", + "LINESTRING (0 0, 0 0)"); + } + + // test a zero-length subline equal to a mid point + //9 - testZeroLenSubLineAtMidVertex() + template<> + template<> + void object::test<9>() + { + runIndicesOfThenExtract("LINESTRING (0 0, 0 10, 10 10, 10 0, 0 0)", + "LINESTRING (10 10, 10 10)"); + } + + //10 - testIndexOfAfterSquare() + template<> + template<> + void object::test<10>() + { + runIndexOfAfterTest("LINESTRING (0 0, 0 10, 10 10, 10 0, 0 0)", + "POINT (0 0)"); + } + + //11 - testIndexOfAfterRibbon() + template<> + template<> + void object::test<11>() + { + runIndexOfAfterTest("LINESTRING (0 0, 0 60, 50 60, 50 20, -20 20)", + "POINT (0 20)"); + } + + //12 - testOffsetStartPoint() + template<> + template<> + void object::test<12>() + { + runOffsetTest("LINESTRING (0 0, 10 10, 10 10, 20 20)", "POINT(0 0)", 1.0, "POINT (-0.7071067811865475 0.7071067811865475)"); + runOffsetTest("LINESTRING (0 0, 10 10, 10 10, 20 20)", "POINT(0 0)", -1.0, "POINT (0.7071067811865475 -0.7071067811865475)"); + runOffsetTest("LINESTRING (0 0, 10 10, 10 10, 20 20)", "POINT(10 10)", 5.0, "POINT (6.464466094067262 13.535533905932738)"); + runOffsetTest("LINESTRING (0 0, 10 10, 10 10, 20 20)", "POINT(10 10)", -5.0, "POINT (13.535533905932738 6.464466094067262)"); + } + + + //13 - testExtractLineBeyondRange() + template<> + template<> + void object::test<13>() + { + checkExtractLine("LINESTRING (0 0, 10 10)", -100, 100, "LINESTRING (0 0, 10 10)"); + } + + //14 - testExtractLineReverse() + template<> + template<> + void object::test<14>() + { + checkExtractLine("LINESTRING (0 0, 10 0)", 9, 1, "LINESTRING (9 0, 1 0)"); + } + + //15 - testExtractLineReverseMulti() + template<> + template<> + void object::test<15>() + { + checkExtractLine("MULTILINESTRING ((0 0, 10 0), (20 0, 25 0, 30 0))", + 19, 1, "MULTILINESTRING ((29 0, 25 0, 20 0), (10 0, 1 0))"); + } + + //16 - testExtractLineNegative() + template<> + template<> + void object::test<16>() + { + checkExtractLine("LINESTRING (0 0, 10 0)", -9, -1, "LINESTRING (1 0, 9 0)"); + } + + //17 - testExtractLineNegativeReverse() + template<> + template<> + void object::test<17>() + { + checkExtractLine("LINESTRING (0 0, 10 0)", -1, -9, "LINESTRING (9 0, 1 0)"); + } + + //18 - testExtractLineIndexAtEndpoint() + template<> + template<> + void object::test<18>() + { + checkExtractLine("MULTILINESTRING ((0 0, 10 0), (20 0, 25 0, 30 0))", + 10, -1, "LINESTRING (20 0, 25 0, 29 0)"); + } + + //19 - testExtractLineBothIndicesAtEndpoint() + template<> + template<> + void object::test<19>() + { + checkExtractLine("MULTILINESTRING ((0 0, 10 0), (20 0, 25 0, 30 0))", + 10, 10, "LINESTRING (20 0, 20 0)"); + } + + //20 - testExtractLineBothIndicesAtEndpointNegative() + template<> + template<> + void object::test<20>() + { + checkExtractLine("MULTILINESTRING ((0 0, 10 0), (20 0, 25 0, 30 0))", + -10, 10, "LINESTRING (20 0, 20 0)"); + } + + //21 - testExtractPointBeyondRange() + template<> + template<> + void object::test<21>() + { + GeomPtr linearGeom(reader.read("LINESTRING (0 0, 10 10)")); + LengthIndexedLine indexedLine(linearGeom.get()); + Coordinate pt = indexedLine.extractPoint(100); + ensure(pt == Coordinate(10, 10)); + + Coordinate pt2 = indexedLine.extractPoint(0); + ensure(pt2 == Coordinate(0, 0)); + } + + //22 - testProjectPointWithDuplicateCoords() + template<> + template<> + void object::test<22>() + { + GeomPtr linearGeom(reader.read("LINESTRING (0 0, 10 0, 10 0, 20 0)")); + LengthIndexedLine indexedLine(linearGeom.get()); + double projIndex = indexedLine.project(Coordinate(10, 1)); + ensure(projIndex == 10.0); + } + + /** + * Tests that z values are interpolated + * + */ + //23 - testComputeZ() + template<> + template<> + void object::test<23>() + { + GeomPtr linearGeom(reader.read("LINESTRING (0 0 0, 10 10 10)")); + LengthIndexedLine indexedLine(linearGeom.get()); + double projIndex = indexedLine.project(Coordinate(5, 5)); + Coordinate projPt = indexedLine.extractPoint(projIndex); +// System.out.println(projPt); + ensure(projPt.equals3D(Coordinate(5, 5, 5))); + } + + /** + * Tests that if the input does not have Z ordinates, neither does the output. + * + */ + //24 - testComputeZNaN() + template<> + template<> + void object::test<24>() + { + + GeomPtr linearGeom(reader.read("LINESTRING (0 0, 10 10 10)")); + LengthIndexedLine indexedLine(linearGeom.get()); + double projIndex = indexedLine.project(Coordinate(5, 5)); + Coordinate projPt = indexedLine.extractPoint(projIndex); + ensure(isnan(projPt.z)); + } + +} Index: tests/unit/Makefile.am =================================================================== --- tests/unit/Makefile.am (revision 2616) +++ tests/unit/Makefile.am (working copy) @@ -61,6 +61,7 @@ index/quadtree/DoubleBitsTest.cpp \ io/ByteOrderValuesTest.cpp \ io/WKBReaderTest.cpp \ + linearref/LengthIndexedLineTest.cpp \ noding/BasicSegmentStringTest.cpp \ noding/NodedSegmentStringTest.cpp \ noding/SegmentNodeTest.cpp \ _______________________________________________ geos-devel mailing list [hidden email] http://lists.osgeo.org/mailman/listinfo/geos-devel |
||||||||||||||||
|
David Turner-3
|
Did I send this to the right place? Or should I create a ticket
somewhere? Or is my patch totally off-base? Just trying to make sure this doesn't get lost in the noise. On Fri, 2009-08-07 at 16:45 -0400, David Turner wrote: > OK, I've done the port. A patch, with ported tests, is attached. > > On Thu, 2009-07-23 at 11:13 -0400, David Turner wrote: > > JTS has a class called LengthIndexedLine with a method "project", which > > lets you figure out the nearest point on a line to a given point. This > > is useful, for instance, if you are trying to figure out what street a > > person is on from (possibly slightly inaccurate) GPS observations. > > > > http://tsusiatsoftware.net/jts/javadoc/com/vividsolutions/jts/linearref/LengthIndexedLine.html#project(com.vividsolutions.jts.geom.Coordinate) > > > > PostGIS calls this function st_line_locate_point. > > > > GEOS doesn't seem to have it, even though I was under the impression > > that GEOS was merely a port of JTS. If I port JTS's project function > > and related functions such as extractPoint to GEOS, would that patch be > > likely to be accepted? Or am I missing something about the relationship > > between JTS and GEOS? > > > > > > _______________________________________________ > > geos-devel mailing list > > [hidden email] > > http://lists.osgeo.org/mailman/listinfo/geos-devel > _______________________________________________ > geos-devel mailing list > [hidden email] > http://lists.osgeo.org/mailman/listinfo/geos-devel _______________________________________________ geos-devel mailing list [hidden email] http://lists.osgeo.org/mailman/listinfo/geos-devel |
||||||||||||||||
|
Howard Butler
|
Filing a ticket and attaching the patch is the best way to ensure it
doesn't get lost. Putting a milestone on it (like 3.2) will also help ensure someone looks at it. Howard On Aug 11, 2009, at 8:22 PM, David Turner wrote: > Did I send this to the right place? Or should I create a ticket > somewhere? Or is my patch totally off-base? > > Just trying to make sure this doesn't get lost in the noise. > > On Fri, 2009-08-07 at 16:45 -0400, David Turner wrote: >> OK, I've done the port. A patch, with ported tests, is attached. >> >> On Thu, 2009-07-23 at 11:13 -0400, David Turner wrote: >>> JTS has a class called LengthIndexedLine with a method "project", >>> which >>> lets you figure out the nearest point on a line to a given >>> point. This >>> is useful, for instance, if you are trying to figure out what >>> street a >>> person is on from (possibly slightly inaccurate) GPS observations. >>> >>> http://tsusiatsoftware.net/jts/javadoc/com/vividsolutions/jts/linearref/LengthIndexedLine.html#project(com.vividsolutions.jts.geom.Coordinate) >>> >>> PostGIS calls this function st_line_locate_point. >>> >>> GEOS doesn't seem to have it, even though I was under the impression >>> that GEOS was merely a port of JTS. If I port JTS's project >>> function >>> and related functions such as extractPoint to GEOS, would that >>> patch be >>> likely to be accepted? Or am I missing something about the >>> relationship >>> between JTS and GEOS? >>> >>> >>> _______________________________________________ >>> geos-devel mailing list >>> [hidden email] >>> http://lists.osgeo.org/mailman/listinfo/geos-devel >> _______________________________________________ >> geos-devel mailing list >> [hidden email] >> http://lists.osgeo.org/mailman/listinfo/geos-devel > > _______________________________________________ > geos-devel mailing list > [hidden email] > http://lists.osgeo.org/mailman/listinfo/geos-devel _______________________________________________ geos-devel mailing list [hidden email] http://lists.osgeo.org/mailman/listinfo/geos-devel |
||||||||||||||||
|
David Turner-3
|
http://trac.osgeo.org/geos/ticket/283
On Tue, 2009-08-11 at 20:51 -0500, Howard Butler wrote: > Filing a ticket and attaching the patch is the best way to ensure it > doesn't get lost. Putting a milestone on it (like 3.2) will also help > ensure someone looks at it. > > Howard > > On Aug 11, 2009, at 8:22 PM, David Turner wrote: > > > Did I send this to the right place? Or should I create a ticket > > somewhere? Or is my patch totally off-base? > > > > Just trying to make sure this doesn't get lost in the noise. > > > > On Fri, 2009-08-07 at 16:45 -0400, David Turner wrote: > >> OK, I've done the port. A patch, with ported tests, is attached. > >> > >> On Thu, 2009-07-23 at 11:13 -0400, David Turner wrote: > >>> JTS has a class called LengthIndexedLine with a method "project", > >>> which > >>> lets you figure out the nearest point on a line to a given > >>> point. This > >>> is useful, for instance, if you are trying to figure out what > >>> street a > >>> person is on from (possibly slightly inaccurate) GPS observations. > >>> > >>> http://tsusiatsoftware.net/jts/javadoc/com/vividsolutions/jts/linearref/LengthIndexedLine.html#project(com.vividsolutions.jts.geom.Coordinate) > >>> > >>> PostGIS calls this function st_line_locate_point. > >>> > >>> GEOS doesn't seem to have it, even though I was under the impression > >>> that GEOS was merely a port of JTS. If I port JTS's project > >>> function > >>> and related functions such as extractPoint to GEOS, would that > >>> patch be > >>> likely to be accepted? Or am I missing something about the > >>> relationship > >>> between JTS and GEOS? > >>> > >>> > >>> _______________________________________________ > >>> geos-devel mailing list > >>> [hidden email] > >>> http://lists.osgeo.org/mailman/listinfo/geos-devel > >> _______________________________________________ > >> geos-devel mailing list > >> [hidden email] > >> http://lists.osgeo.org/mailman/listinfo/geos-devel > > > > _______________________________________________ > > geos-devel mailing list > > [hidden email] > > http://lists.osgeo.org/mailman/listinfo/geos-devel > > _______________________________________________ > geos-devel mailing list > [hidden email] > http://lists.osgeo.org/mailman/listinfo/geos-devel _______________________________________________ geos-devel mailing list [hidden email] http://lists.osgeo.org/mailman/listinfo/geos-devel |
||||||||||||||||
| Free Embeddable Forum Powered by Nabble | Help |