RouteSegmentInfo.java

/*  This file is part of Openrouteservice.
 *
 *  Openrouteservice is free software; you can redistribute it and/or modify it under the terms of the
 *  GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1
 *  of the License, or (at your option) any later version.

 *  This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 *  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *  See the GNU Lesser General Public License for more details.

 *  You should have received a copy of the GNU Lesser General Public License along with this library;
 *  if not, see <https://www.gnu.org/licenses/>.
 */
package org.heigit.ors.mapmatching;

import com.graphhopper.routing.querygraph.EdgeIteratorStateHelper;
import com.graphhopper.util.*;
import org.heigit.ors.util.FrechetDistance;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.LineString;

import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;

public class RouteSegmentInfo {
    private final List<EdgeIteratorState> edges;
    private final Geometry geometry;
    private final long time;
    private final double distance;

    public RouteSegmentInfo(List<EdgeIteratorState> edges, double distance, long time, Geometry geom) {
        this.edges = edges;
        this.time = time;
        this.distance = distance;
        this.geometry = geom;
    }

    public boolean isEmpty() {
        return this.edges == null || this.edges.isEmpty();
    }

    public double getDistance() {
        return this.distance;
    }

    public long getTime() {
        return this.time;
    }

    public String getEdgeName(int index) {
        return edges.get(index).getName();
    }

    /**
     * @return Returns all Edges.
     */
    public List<EdgeIteratorState> getEdgesStates() {
        return edges;
    }

    public List<Integer> getEdges() {
        List<Integer> res = new ArrayList<>(edges.size());

        for (EdgeIteratorState edge : edges)
            res.add(EdgeIteratorStateHelper.getOriginalEdge(edge));

        return res;
    }

    public Geometry getGeometry() {
        return this.geometry;
    }

    public double getLength() {
        return this.geometry.getLength();
    }

    public double getLength(DistanceCalc dc) {
        double res = 0;

        if (this.getGeometry() != null) {
            LineString ls = (LineString) this.getGeometry();
            int nPoints = ls.getNumPoints();

            if (nPoints > 1) {
                Coordinate c = ls.getCoordinateN(0);
                double x0 = c.x;
                double y0 = c.y;
                for (int i = 1; i < ls.getNumPoints(); i++) {
                    c = ls.getCoordinateN(i);

                    res += dc.calcDist(y0, x0, c.y, c.x);
                    x0 = c.x;
                    y0 = c.y;
                }
            }
        }

        return res;
    }

    public String getNearbyStreetName(PointList points, boolean ignoreAdjacency) {
        if (edges.isEmpty())
            return null;

        String result = null;
        Point2D[] p = getPoints(points);
        double minValue = Double.MAX_VALUE;

        for (EdgeIteratorState edge : edges) {
            String edgeName = edge.getName();
            if (Helper.isEmpty(edgeName))
                continue;

            PointList pl = edge.fetchWayGeometry(FetchMode.ALL);
            if (pl.size() <= 1)
                continue;

            if (ignoreAdjacency && arePolylinesAdjacent(points, pl))
                return null;

            Point2D[] q = getPoints(pl);

            FrechetDistance fd = new FrechetDistance(p, q);

            try {
                double value = fd.computeFrechetDistance();// * pl.calcDistance(dc)/1000.0
                if (value < minValue && value < 1.5E-6) {
                    minValue = value;
                    result = edgeName;
                }
            } catch (Exception ex) {
                // do nothing
            }
        }

        return result;
    }

    private Point2D[] getPoints(PointList points) {
        List<Point2D> res = new ArrayList<>(points.size());
        double lon0 = 0;
        double lat0 = 0;
        double lon1;
        double lat1;
        for (int i = 0; i < points.size(); i++) {
            lon1 = points.getLon(i);
            lat1 = points.getLat(i);
            if (i > 0 && (lon0 == lon1 || lat0 == lat1))
                continue;

            Point2D p = new Point2D.Double(lon1, lat1);
            res.add(p);
            lon0 = lon1;
            lat0 = lat1;
        }
        return res.toArray(new Point2D[0]);
    }

    private boolean arePolylinesAdjacent(PointList pl1, PointList pl2) {
        for (int i = 0; i < pl1.size(); i++) {
            double lon0 = pl1.getLon(i);
            double lat0 = pl1.getLat(i);

            for (int j = 0; j < pl2.size(); j++) {
                double lon1 = pl2.getLon(j);
                double lat1 = pl2.getLat(j);

                if (lon0 == lon1 && lat0 == lat1)
                    return true;
            }
        }
        return false;
    }
}