package pl.edu.agh.logic; import static com.google.common.collect.Lists.newArrayList; import static pl.edu.agh.utils.DateUtils.timeDifference; import java.util.Date; import java.util.List; import java.util.ListIterator; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.LineSegment; import pl.edu.agh.model.SpeedInfo; import pl.edu.agh.utils.DateUtils; public class SpeedInfoProcessor { public List<SpeedInfo> retrieveSpeedInfoFromPath(Path path) { List<SpeedInfo> infos = newArrayList(); if (path.getPointsNumber() < 2) { return infos; } List<PointMatching> matchings = path.getMatchings(); ListIterator<PointMatching> currentRoadMatching = matchings.listIterator(); IntersectionMatching currentRoadBegin = createIntersectionMatching(currentRoadMatching, matchings); while (currentRoadBegin.getNextRoadMatching() != null) { ListIterator<PointMatching> nextRoadFirstMatching = PathUtils.iteratorForNextRoadMatching( currentRoadMatching, matchings); IntersectionMatching nextRoadBegin = createIntersectionMatching(nextRoadFirstMatching, matchings); double distance = calculateDistanceOfMatchedRoad(matchings, currentRoadMatching, currentRoadBegin, nextRoadFirstMatching, nextRoadBegin); double timeDifference = timeDifference(currentRoadBegin.getIntersectionTime(), nextRoadBegin.getIntersectionTime()).toSeconds(); if (distance != 0 && timeDifference != 0) { infos.add(createSpeedInfo(nextRoadBegin.getPreviousRoadMatching().getRoad(), timeDifference, distance, nextRoadBegin.getIntersectionTime())); } currentRoadMatching = nextRoadFirstMatching; currentRoadBegin = nextRoadBegin; } return infos; } private IntersectionMatching createIntersectionMatching(ListIterator<PointMatching> intersectionMatching, List<PointMatching> matchings) { if (!intersectionMatching.hasNext()) { return new IntersectionMatching(matchings.get(intersectionMatching.previousIndex()), null); } if (!intersectionMatching.hasPrevious()) { return new IntersectionMatching(null, matchings.get(intersectionMatching.nextIndex())); } PointMatching lastMatchingOfPreviuosRoad = matchings.get(intersectionMatching.previousIndex()); PointMatching firstMatchingOfNextRoad = matchings.get(intersectionMatching.nextIndex()); return createMatchingForIntersection(lastMatchingOfPreviuosRoad, firstMatchingOfNextRoad); } private double calculateDistanceOfMatchedRoad(List<PointMatching> matchings, ListIterator<PointMatching> currentRoadMatching, IntersectionMatching currentRoadBegin, ListIterator<PointMatching> nextRoadFirstMatching, IntersectionMatching nextRoadBegin) { double distance = 0.0; distance += PathUtils.getDistanceBetweenPointMatchings(currentRoadBegin.getNextRoadMatching(), matchings.get(currentRoadMatching.nextIndex())); distance += getDistanceBetweenPointsMatchedToOneRoad(currentRoadMatching, nextRoadFirstMatching, matchings); distance += PathUtils.getDistanceBetweenPointMatchings(currentRoadMatching.next(), nextRoadBegin.getPreviousRoadMatching()); return distance; } private SpeedInfo createSpeedInfo(Road road, double timeDifference, double distance, Date intersectionTime) { SpeedInfo info = new SpeedInfo(); double speed = distance / timeDifference; info.setWayGid(road.getId()); info.setTime(intersectionTime); if (road.isReversed()) { info.setReverseWaySpeed(speed); info.setReverseDistance(distance); } else { info.setDirectWaySpeed(speed); info.setDirectDistance(distance); } return info; } private IntersectionMatching createMatchingForIntersection(PointMatching lastMatchingOfPreviuosRoad, PointMatching firstMatchingOfNextRoad) { Coordinate intersectionPoint = new LineSegment(lastMatchingOfPreviuosRoad.getRoad().getEndPoint(), firstMatchingOfNextRoad.getRoad().getStartPoint()).midPoint(); Date intersectionTime = calculateIntersectionTime(lastMatchingOfPreviuosRoad, firstMatchingOfNextRoad, intersectionPoint); return new IntersectionMatching(intersectionPoint, intersectionTime, lastMatchingOfPreviuosRoad.getRoad(), firstMatchingOfNextRoad.getRoad()); } private double getDistanceBetweenPointsMatchedToOneRoad(ListIterator<PointMatching> currentRoadMatching, ListIterator<PointMatching> nextRoadFirstMatching, List<PointMatching> matchings) { double distance = 0.0; while (currentRoadMatching.nextIndex() + 1 != nextRoadFirstMatching.nextIndex()) { distance += PathUtils.getDistanceBetweenPointMatchings(matchings.get(currentRoadMatching.nextIndex()), matchings.get(currentRoadMatching.nextIndex() + 1)); currentRoadMatching.next(); } return distance; } private Date calculateIntersectionTime(PointMatching lastMatchingOfPreviuosRoad, PointMatching firstMatchingOfNextRoad, Coordinate intersectionPoint) { double distanceToIntersection = PathUtils.getDistanceBetweenPointMatchings(lastMatchingOfPreviuosRoad, new PointMatching(intersectionPoint, lastMatchingOfPreviuosRoad.getRoad(), null)); double distanceFromIntersection = PathUtils.getDistanceBetweenPointMatchings(new PointMatching( intersectionPoint, firstMatchingOfNextRoad.getRoad(), null), firstMatchingOfNextRoad); return DateUtils.add( lastMatchingOfPreviuosRoad.getTime(), timeDifference(lastMatchingOfPreviuosRoad.getTime(), firstMatchingOfNextRoad.getTime()).multiplyBy( distanceToIntersection / (distanceToIntersection + distanceFromIntersection))); } }