1 /**********************************************************************
2  *
3  * GEOS - Geometry Engine Open Source
4  * http://geos.osgeo.org
5  *
6  * Copyright (C) 2011 Sandro Santilli <strk@kbt.io>
7  *
8  * This is free software; you can redistribute and/or modify it under
9  * the terms of the GNU Lesser General Public Licence as published
10  * by the Free Software Foundation.
11  * See the COPYING file for more information.
12  *
13  **********************************************************************
14  *
15  * Last port: linearref/LocationIndexedLine.java r466
16  *
17  **********************************************************************/
18 
19 #ifndef GEOS_LINEARREF_LOCATIONINDEXEDLINE_H
20 #define GEOS_LINEARREF_LOCATIONINDEXEDLINE_H
21 
22 #include <geos/export.h>
23 #include <geos/geom/Coordinate.h>
24 #include <geos/geom/Geometry.h>
25 #include <geos/linearref/LinearLocation.h>
26 #include <geos/linearref/LocationIndexOfPoint.h>
27 #include <geos/linearref/LocationIndexOfLine.h>
28 #include <geos/util/IllegalArgumentException.h>
29 
30 namespace geos {
31 namespace linearref { // geos::linearref
32 
33 /**
34  * \brief
35  * Supports linear referencing along a linear
36  * [Geometry](@ref geom::Geometry) using
37  * [LinearLocations](@ref LinearLocation) as the index.
38  */
39 class GEOS_DLL LocationIndexedLine {
40 private:
41     const geom::Geometry* linearGeom;
42 
43     void
checkGeometryType()44     checkGeometryType()
45     {
46         if(!linearGeom->isLineal()) {
47             throw util::IllegalArgumentException("Input geometry must be linear");
48         }
49     }
50 
51 public:
52 
53     /**
54      * \brief
55      * Constructs an object which allows linear referencing along
56      * a given linear [Geometry](@ref geom::Geometry).
57      *
58      * @param p_linearGeom the linear geometry to reference along
59      */
LocationIndexedLine(const geom::Geometry * p_linearGeom)60     LocationIndexedLine(const geom::Geometry* p_linearGeom)
61         : linearGeom(p_linearGeom)
62     {
63         checkGeometryType();
64     }
65 
66     /**
67      * \brief
68      * Computes the [Coordinate](@ref geom::Coordinate) for the point
69      * on the line at the given index.
70      *
71      * If the index is out of range the first or last point on the
72      * line will be returned.
73      * The Z-ordinate of the computed point will be interpolated from
74      * the Z-ordinates of the line segment containing it, if they exist.
75      *
76      * @param index the index of the desired point
77      * @return the Coordinate at the given index
78      */
79     geom::Coordinate
extractPoint(const LinearLocation & index)80     extractPoint(const LinearLocation& index) const
81     {
82         return index.getCoordinate(linearGeom);
83     }
84 
85 
86     /**
87      * \brief
88      * Computes the [Coordinate](@ref geom::Coordinate) for the point
89      * on the line at the given index, offset by the given distance.
90      *
91      * If the index is out of range the first or last point on the
92      * line will be returned.
93      * The computed point is offset to the left of the line if the offset
94      * distance is positive, to the right if negative.
95      *
96      * The Z-ordinate of the computed point will be interpolated from
97      * the Z-ordinates of the line segment containing it, if they exist.
98      *
99      * @param index the index of the desired point
100      * @param offsetDistance the distance the point is offset from the segment
101      *                       (positive is to the left, negative is to the right)
102      * @return the Coordinate at the given index
103      */
104     geom::Coordinate
extractPoint(const LinearLocation & index,double offsetDistance)105     extractPoint(const LinearLocation& index,
106                  double offsetDistance) const
107     {
108         geom::Coordinate ret;
109         index.getSegment(linearGeom)->pointAlongOffset(
110             index.getSegmentFraction(), offsetDistance, ret
111         );
112         return ret;
113     }
114 
115     /**
116      * \brief
117      * Computes the [LineString](@ref geom::LineString) for the interval
118      * on the line between the given indices.
119      *
120      * If the endIndex lies before the startIndex,
121      * the computed geometry is reversed.
122      *
123      * @param startIndex the index of the start of the interval
124      * @param endIndex the index of the end of the interval
125      * @return the linear interval between the indices
126      */
127     std::unique_ptr<geom::Geometry>
extractLine(const LinearLocation & startIndex,const LinearLocation & endIndex)128     extractLine(const LinearLocation& startIndex,
129                 const LinearLocation& endIndex) const
130     {
131         return ExtractLineByLocation::extract(linearGeom, startIndex, endIndex);
132     }
133 
134 
135     /**
136      * \brief
137      * Computes the index for a given point on the line.
138      *
139      * The supplied point does not <i>necessarily</i> have to lie precisely
140      * on the line, but if it is far from the line the accuracy and
141      * performance of this function is not guaranteed.
142      * Use {@link #project} to compute a guaranteed result for points
143      * which may be far from the line.
144      *
145      * @param pt a point on the line
146      * @return the index of the point
147      *
148      * @see project
149      */
150     LinearLocation
indexOf(const geom::Coordinate & pt)151     indexOf(const geom::Coordinate& pt) const
152     {
153         return LocationIndexOfPoint::indexOf(linearGeom, pt);
154     }
155 
156     /**
157      * \brief
158      * Finds the index for a point on the line
159      * which is greater than the given index.
160      *
161      * If no such index exists, returns <tt>minIndex</tt>.
162      * This method can be used to determine all indexes for
163      * a point which occurs more than once on a non-simple line.
164      * It can also be used to disambiguate cases where the given point lies
165      * slightly off the line and is equidistant from two different
166      * points on the line.
167      *
168      * The supplied point does not <i>necessarily</i> have to lie precisely
169      * on the line, but if it is far from the line the accuracy and
170      * performance of this function is not guaranteed.
171      * Use {@link #project} to compute a guaranteed result for points
172      * which may be far from the line.
173      *
174      * @param pt a point on the line
175      * @param minIndex the value the returned index must be greater than
176      * @return the index of the point greater than the given minimum index
177      *
178      * @see project
179      */
180     LinearLocation
indexOfAfter(const geom::Coordinate & pt,const LinearLocation & minIndex)181     indexOfAfter(const geom::Coordinate& pt,
182                  const LinearLocation& minIndex) const
183     {
184         return LocationIndexOfPoint::indexOfAfter(linearGeom, pt, &minIndex);
185     }
186 
187     /**
188      * \brief
189      * Computes the indices for a subline of the line.
190      *
191      * (The subline must <b>conform</b> to the line; that is,
192      * all vertices in the subline (except possibly the first and last)
193      * must be vertices of the line and occur in the same order).
194      *
195      * @param subLine a subLine of the line
196      * @return a pair of indices for the start and end of the subline.
197      */
198     LinearLocation*
indicesOf(const geom::Geometry * subLine)199     indicesOf(const geom::Geometry* subLine) const
200     {
201         return LocationIndexOfLine::indicesOf(linearGeom, subLine);
202     }
203 
204 
205     /**
206      * \brief
207      * Computes the index for the closest point on the line to the given point.
208      *
209      * If more than one point has the closest distance the first one along
210      * the line is returned.
211      * (The point does not necessarily have to lie precisely on the line.)
212      *
213      * @param pt a point on the line
214      * @return the index of the point
215      */
216     LinearLocation
project(const geom::Coordinate & pt)217     project(const geom::Coordinate& pt) const
218     {
219         return LocationIndexOfPoint::indexOf(linearGeom, pt);
220     }
221 
222     /**
223      * \brief
224      * Returns the index of the start of the line
225      *
226      * @return the start index
227      */
228     LinearLocation
getStartIndex()229     getStartIndex() const
230     {
231         return LinearLocation();
232     }
233 
234     /**
235      * \brief
236      * Returns the index of the end of the line
237      *
238      * @return the end index
239      */
240     LinearLocation
getEndIndex()241     getEndIndex() const
242     {
243         return LinearLocation::getEndLocation(linearGeom);
244     }
245 
246     /**
247      * \brief
248      * Tests whether an index is in the valid index range for the line.
249      *
250      * @param index the index to test
251      * @return `true` if the index is in the valid range
252      */
253     bool
isValidIndex(const LinearLocation & index)254     isValidIndex(const LinearLocation& index) const
255     {
256         return index.isValid(linearGeom);
257     }
258 
259 
260     /**
261      * \brief
262      * Computes a valid index for this line
263      * by clamping the given index to the valid range of index values
264      *
265      * @return a valid index value
266      */
267     LinearLocation
clampIndex(const LinearLocation & index)268     clampIndex(const LinearLocation& index) const
269     {
270         LinearLocation loc = index;
271         loc.clamp(linearGeom);
272         return loc;
273     }
274 };
275 
276 } // geos::linearref
277 } // geos
278 #endif
279