1 /* 2 * Copyright (c) 2016 Vivid Solutions. 3 * 4 * All rights reserved. This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * and Eclipse Distribution License v. 1.0 which accompanies this distribution. 7 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v20.html 8 * and the Eclipse Distribution License is available at 9 * 10 * http://www.eclipse.org/org/documents/edl-v10.php. 11 */ 12 13 package org.locationtech.jts.linearref; 14 15 import org.locationtech.jts.geom.Coordinate; 16 import org.locationtech.jts.geom.Geometry; 17 import org.locationtech.jts.geom.LineString; 18 import org.locationtech.jts.geom.MultiLineString; 19 20 /** 21 * Supports linear referencing 22 * along a linear {@link Geometry} 23 * using {@link LinearLocation}s as the index. 24 */ 25 public class LocationIndexedLine 26 { 27 private Geometry linearGeom; 28 29 /** 30 * Constructs an object which allows linear referencing along 31 * a given linear {@link Geometry}. 32 * 33 * @param linearGeom the linear geometry to reference along 34 */ LocationIndexedLine(Geometry linearGeom)35 public LocationIndexedLine(Geometry linearGeom) 36 { 37 this.linearGeom = linearGeom; 38 checkGeometryType(); 39 } 40 checkGeometryType()41 private void checkGeometryType() 42 { 43 if (! (linearGeom instanceof LineString || linearGeom instanceof MultiLineString)) 44 throw new IllegalArgumentException("Input geometry must be linear"); 45 } 46 /** 47 * Computes the {@link Coordinate} for the point 48 * on the line at the given index. 49 * If the index is out of range the first or last point on the 50 * line will be returned. 51 * The Z-ordinate of the computed point will be interpolated from 52 * the Z-ordinates of the line segment containing it, if they exist. 53 * 54 * @param index the index of the desired point 55 * @return the Coordinate at the given index 56 */ extractPoint(LinearLocation index)57 public Coordinate extractPoint(LinearLocation index) 58 { 59 return index.getCoordinate(linearGeom); 60 } 61 62 /** 63 * Computes the {@link Coordinate} for the point 64 * on the line at the given index, offset by the given distance. 65 * If the index is out of range the first or last point on the 66 * line will be returned. 67 * The computed point is offset to the left of the line if the offset distance is 68 * positive, to the right if negative. 69 * 70 * The Z-ordinate of the computed point will be interpolated from 71 * the Z-ordinates of the line segment containing it, if they exist. 72 * 73 * @param index the index of the desired point 74 * @param offsetDistance the distance the point is offset from the segment 75 * (positive is to the left, negative is to the right) 76 * @return the Coordinate at the given index 77 */ extractPoint(LinearLocation index, double offsetDistance)78 public Coordinate extractPoint(LinearLocation index, double offsetDistance) 79 { 80 LinearLocation indexLow = index.toLowest(linearGeom); 81 return indexLow.getSegment(linearGeom).pointAlongOffset(indexLow.getSegmentFraction(), offsetDistance); 82 } 83 84 /** 85 * Computes the {@link LineString} for the interval 86 * on the line between the given indices. 87 * If the start location is after the end location, 88 * the computed linear geometry has reverse orientation to the input line. 89 * 90 * @param startIndex the index of the start of the interval 91 * @param endIndex the index of the end of the interval 92 * @return the linear geometry between the indices 93 */ extractLine(LinearLocation startIndex, LinearLocation endIndex)94 public Geometry extractLine(LinearLocation startIndex, LinearLocation endIndex) 95 { 96 return ExtractLineByLocation.extract(linearGeom, startIndex, endIndex); 97 } 98 99 /** 100 * Computes the index for a given point on the line. 101 * <p> 102 * The supplied point does not <i>necessarily</i> have to lie precisely 103 * on the line, but if it is far from the line the accuracy and 104 * performance of this function is not guaranteed. 105 * Use {@link #project} to compute a guaranteed result for points 106 * which may be far from the line. 107 * 108 * @param pt a point on the line 109 * @return the index of the point 110 * @see #project(Coordinate) 111 */ indexOf(Coordinate pt)112 public LinearLocation indexOf(Coordinate pt) 113 { 114 return LocationIndexOfPoint.indexOf(linearGeom, pt); 115 } 116 117 /** 118 * Finds the index for a point on the line 119 * which is greater than the given index. 120 * If no such index exists, returns <tt>minIndex</tt>. 121 * This method can be used to determine all indexes for 122 * a point which occurs more than once on a non-simple line. 123 * It can also be used to disambiguate cases where the given point lies 124 * slightly off the line and is equidistant from two different 125 * points on the line. 126 * 127 * The supplied point does not <i>necessarily</i> have to lie precisely 128 * on the line, but if it is far from the line the accuracy and 129 * performance of this function is not guaranteed. 130 * Use {@link #project} to compute a guaranteed result for points 131 * which may be far from the line. 132 * 133 * @param pt a point on the line 134 * @param minIndex the value the returned index must be greater than 135 * @return the index of the point greater than the given minimum index 136 * 137 * @see #project(Coordinate) 138 */ indexOfAfter(Coordinate pt, LinearLocation minIndex)139 public LinearLocation indexOfAfter(Coordinate pt, LinearLocation minIndex) 140 { 141 return LocationIndexOfPoint.indexOfAfter(linearGeom, pt, minIndex); 142 } 143 144 145 /** 146 * Computes the indices for a subline of the line. 147 * (The subline must <i>conform</i> to the line; that is, 148 * all vertices in the subline (except possibly the first and last) 149 * must be vertices of the line and occur in the same order). 150 * 151 * @param subLine a subLine of the line 152 * @return a pair of indices for the start and end of the subline. 153 */ indicesOf(Geometry subLine)154 public LinearLocation[] indicesOf(Geometry subLine) 155 { 156 return LocationIndexOfLine.indicesOf(linearGeom, subLine); 157 } 158 159 /** 160 * Computes the index for the closest point on the line to the given point. 161 * If more than one point has the closest distance the first one along the line 162 * is returned. 163 * (The point does not necessarily have to lie precisely on the line.) 164 * 165 * @param pt a point on the line 166 * @return the index of the point 167 */ project(Coordinate pt)168 public LinearLocation project(Coordinate pt) 169 { 170 return LocationIndexOfPoint.indexOf(linearGeom, pt); 171 } 172 173 /** 174 * Returns the index of the start of the line 175 * @return the location index 176 */ getStartIndex()177 public LinearLocation getStartIndex() 178 { 179 return new LinearLocation(); 180 } 181 182 /** 183 * Returns the index of the end of the line 184 * @return the location index 185 */ getEndIndex()186 public LinearLocation getEndIndex() 187 { 188 return LinearLocation.getEndLocation(linearGeom); 189 } 190 191 /** 192 * Tests whether an index is in the valid index range for the line. 193 * 194 * @param index the index to test 195 * @return <code>true</code> if the index is in the valid range 196 */ isValidIndex(LinearLocation index)197 public boolean isValidIndex(LinearLocation index) 198 { 199 return index.isValid(linearGeom); 200 } 201 202 /** 203 * Computes a valid index for this line 204 * by clamping the given index to the valid range of index values 205 * 206 * @return a valid index value 207 */ clampIndex(LinearLocation index)208 public LinearLocation clampIndex(LinearLocation index) 209 { 210 LinearLocation loc = index.copy(); 211 loc.clamp(linearGeom); 212 return loc; 213 } 214 } 215