package pl.edu.agh.logic; import static com.google.common.collect.Lists.newArrayList; import static com.google.common.collect.Sets.newHashSet; import static pl.edu.agh.spatial.HaversineDistanceCalculator.EARTH_DISTANCE_CALCULATOR; import java.util.List; import java.util.ListIterator; import java.util.Set; import pl.edu.agh.model.Way; import pl.edu.agh.spatial.LineSegmentList; import com.google.common.collect.Lists; import com.vividsolutions.jts.geom.LineSegment; import com.vividsolutions.jts.geom.Point; public class WayWithBothEndPoints extends WayWithEndPoints { private Point start; private Point end; public WayWithBothEndPoints(Way way, Point start, Point end) { super(way, start.getFactory()); this.start = start; this.end = end; } public boolean isValid() { return !way.isOneWay() || EARTH_DISTANCE_CALCULATOR.distance(way.getStartPoint(), start) <= EARTH_DISTANCE_CALCULATOR.distance( way.getStartPoint(), end); } public List<Point> createRoute() { LineSegmentList lines = new LineSegmentList(way.getLineString()); LineSegment startNearestLine = lines.nearestLine(start); LineSegment endNearestLine = lines.nearestLine(end); if (startNearestLine.equals(endNearestLine)) { return newArrayList(geometryFactory.createPoint(startNearestLine.closestPoint(start.getCoordinate())), geometryFactory.createPoint(endNearestLine.closestPoint(end.getCoordinate()))); } ListIterator<LineSegment> linesIterator = lines.listIterator(); LineSegment routeStart = skipLinesOutsideRoute(linesIterator, newHashSet(startNearestLine, endNearestLine)); boolean correctlyDirected = routeStart.equals(startNearestLine); List<Point> points = newArrayList(); addPointsInsideRoute(linesIterator, newHashSet(startNearestLine, endNearestLine), points); if (!correctlyDirected) { points = Lists.reverse(points); } points.add(0, geometryFactory.createPoint(startNearestLine.closestPoint(start.getCoordinate()))); points.add(geometryFactory.createPoint(endNearestLine.closestPoint(end.getCoordinate()))); return points; } private LineSegment skipLinesOutsideRoute(ListIterator<LineSegment> linesIterator, Set<LineSegment> edgeLines) { LineSegment segment = linesIterator.next(); while (!edgeLines.contains(segment)) { segment = linesIterator.next(); } linesIterator.previous(); return linesIterator.next(); } private void addPointsInsideRoute(ListIterator<LineSegment> linesIterator, Set<LineSegment> edgeLines, List<Point> points) { LineSegment segment; do { segment = linesIterator.next(); points.add(geometryFactory.createPoint(segment.p0)); } while (!edgeLines.contains(segment)); } }