org.openlr.map.MapOperations Maven / Gradle / Ivy
package org.openlr.map;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import org.locationtech.jts.geom.Coordinate;
import org.openlr.geo.Geo;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class MapOperations {
private final Geo geo;
private final double precisionError;
MapOperations(Geo geo, double precisionError) {
this.geo = geo;
this.precisionError = precisionError;
}
public MapOperations(Geo geo) {
this(geo, 0.001);
}
public MapOperations() {
this(new Geo());
}
public > PointAlongLine projectOnLine(Coordinate coordinate, L line) {
double fraction = geo.projectOnLineString(coordinate, line.getGeometry());
double positiveOffset = line.getLength() * fraction;
return new PointAlongLineImpl<>(line, positiveOffset, geo);
}
public > PointAlongLine calculatePointAlongLineFromStart(L line, double positiveOffset) {
return new PointAlongLineImpl<>(line, positiveOffset, geo);
}
public > PointAlongLine calculatePointAlongLineFromEnd(L line, double negativeOffset) {
return new PointAlongLineImpl<>(line, line.getLength() - negativeOffset, geo);
}
public > PointAlongLine calculatePointAlongPathFromStart(Path path, double positiveOffset) {
LinkedList lines = new LinkedList<>(path.getLines());
double s = path.getPositiveOffset() + positiveOffset;
while (!lines.isEmpty() && lines.getFirst().getLength() < s + precisionError) {
L line = lines.removeFirst();
s -= line.getLength();
}
if (s < precisionError) {
s = 0;
}
if (lines.isEmpty()) {
throw new IllegalArgumentException("Positive offset is greater than path length");
}
return new PointAlongLineImpl<>(lines.getFirst(), s, geo);
}
public > double calculateBearing(PointAlongLine pointAlongLine, boolean forward, double distance) {
L line = pointAlongLine.getLine();
double positiveOffset = pointAlongLine.getPositiveOffset();
double referenceOffset = forward ?
Math.min(positiveOffset + distance, line.getLength()) :
Math.max(positiveOffset - distance, 0);
double fraction = positiveOffset / line.getLength();
double referenceFraction = referenceOffset / line.getLength();
Coordinate coordinate = geo.calculateCoordinateAlongLineString(line.getGeometry(), fraction);
Coordinate referenceCoordinate = geo.calculateCoordinateAlongLineString(line.getGeometry(), referenceFraction);
return geo.calculateBearing(coordinate, referenceCoordinate);
}
public > Path joinPaths(List> paths) {
List lines = new ArrayList<>();
L previousLine = null;
for (Path path : paths) {
for (L line : path.getLines()) {
if (line.equals(previousLine)) {
continue;
}
lines.add(line);
previousLine = line;
}
}
Path firstPath = paths.get(0);
Path lastPath = paths.get(paths.size() - 1);
return new PathImpl<>(lines, firstPath.getPositiveOffset(), lastPath.getNegativeOffset(), geo);
}
public > Path trimPath(Path path, double positiveOffset, double negativeOffset) {
LinkedList lines = new LinkedList<>(path.getLines());
double s = path.getPositiveOffset() + positiveOffset;
double e = path.getNegativeOffset() + negativeOffset;
while (!lines.isEmpty() && lines.getFirst().getLength() < s + precisionError) {
L line = lines.removeFirst();
s -= line.getLength();
}
if (s < precisionError) {
s = 0;
}
while (!lines.isEmpty() && lines.getLast().getLength() < e + precisionError) {
L line = lines.removeLast();
e -= line.getLength();
}
if (e < precisionError) {
e = 0;
}
if (lines.isEmpty()) {
throw new IllegalArgumentException("Total trim length is longer than path length");
}
return new PathImpl<>(lines, s, e, geo);
}
public > Pair, Path> splitPath(Path path, double positiveOffset) {
LinkedList beforeLines = new LinkedList<>();
LinkedList afterLines = new LinkedList<>(path.getLines());
double s = path.getPositiveOffset() + positiveOffset;
while (!afterLines.isEmpty() && afterLines.getFirst().getLength() <= s + precisionError) {
L line = afterLines.removeFirst();
beforeLines.addLast(line);
s -= line.getLength();
}
if (s < precisionError) {
s = 0;
}
if (afterLines.isEmpty()) {
throw new IllegalArgumentException("Positive offset is not less than path length");
}
L lineWithSplitPoint = afterLines.getFirst();
if (s > 0) {
beforeLines.addLast(lineWithSplitPoint);
}
double e = s > 0 ? lineWithSplitPoint.getLength() - s : 0;
Path beforePath = new PathImpl<>(beforeLines, path.getPositiveOffset(), e, geo);
Path afterPath = new PathImpl<>(afterLines, s, path.getNegativeOffset(), geo);
return new ImmutablePair<>(beforePath, afterPath);
}
public > Path expandToValidNode(PointAlongLine pointAlongLine, boolean forward) {
L fromLine = pointAlongLine.getLine();
LinkedList lines = new LinkedList<>();
lines.add(fromLine);
L currentLine = fromLine;
Node currentNode = forward ? currentLine.getEndNode() : currentLine.getStartNode();
while (!currentNode.isValid()) {
List nextLines = forward ? currentLine.getOutgoingLines() : currentLine.getIncomingLines();
if (nextLines.isEmpty()) {
break;
}
currentLine = nextLines.get(0);
currentNode = forward ? currentLine.getEndNode() : currentLine.getStartNode();
if (forward) {
lines.addLast(currentLine);
}
else {
lines.addFirst(currentLine);
}
}
if (forward) {
return new PathImpl<>(lines, pointAlongLine.getPositiveOffset(), 0, geo);
}
else {
return new PathImpl<>(lines, 0, pointAlongLine.getNegativeOffset(), geo);
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy