package org.croudtrip.closestpair; import org.croudtrip.api.account.User; import org.croudtrip.api.directions.NavigationResult; import org.croudtrip.api.directions.Route; import org.croudtrip.api.directions.RouteLocation; import org.croudtrip.logs.LogManager; import java.util.ArrayList; import java.util.List; import javax.inject.Inject; /** */ public class ClosestPair { private final LogManager logManager; @Inject public ClosestPair(LogManager logManager) { this.logManager = logManager; } /** * Find the closest pair of two routes that pick up and drop one specific passenger. * @param passenger The passenger that will be taken. * @param pickupNavigationResult A navigation result for the rout that picks up the passenger at his starting point * @param dropNavigationResult A navigation result for the route that drops the passenger at his destination * @return A {@link org.croudtrip.closestpair.ClosestPairResult} for the solved Closest pair problem. */ public ClosestPairResult findClosestPair( User passenger, NavigationResult pickupNavigationResult, NavigationResult dropNavigationResult ) { // subdivide both routes into multiple points // this will get us a list of locations from the passenger pickup until the end of the trips // since we are creating a super trip there will be only one starting waypoint for this user List<RouteLocation> pickupLocations = pickupNavigationResult.getRoute().getPolylineWaypointsForUser(passenger, pickupNavigationResult.getUserWayPoints()); logManager.d("cp: found " + pickupLocations.size() + " pickup waypoints"); // for the drop route only one end waypoint will exist and we will simple get all the points from the // beginning of the trip. So this is exactly what we want, since we don't need points if the // passenger is not in the car. List<RouteLocation> dropLocations = dropNavigationResult.getRoute().getPolylineWaypointsForUser(passenger, dropNavigationResult.getUserWayPoints()); logManager.d("cp: found " + dropLocations.size() + " drop waypoints"); return findClosestPair( pickupLocations, dropLocations ); } /** * First simple O(n*m) approach for the closest pair problem. */ private ClosestPairResult findClosestPair( List<RouteLocation> pickupLocations, List<RouteLocation> dropLocations ) { double minDistance = Double.MAX_VALUE; RouteLocation pickUp = null, drop = null; for( RouteLocation pickupLoc : pickupLocations ) { for( RouteLocation dropLoc : dropLocations ) { double dist = pickupLoc.distanceFrom(dropLoc); if( dist < minDistance ) { minDistance = dist; pickUp = pickupLoc; drop = dropLoc; } } } logManager.d("cp: finished: " + minDistance); return new ClosestPairResult( pickUp, drop ); } }