All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openlr.map.MapOperations Maven / Gradle / Ivy

There is a newer version: 2.0-beta3
Show newest version
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