public void LongPolylineRectWithinDistanceSanityTest2() { List <GeoCoordinates> points = new List <GeoCoordinates>(); for (int i = 0; i < 1000; ++i) { // Points stretch from (0,0) to (9.99, 9.99) points.Add(new GeoCoordinates(i / 100.0, i / 100.0)); } GeoPolyline pl = new GeoPolyline(points); // Rect is in upper left corner of the square (0,0),(10,0),(10,10),(0,10) // and has side length 4. It should be sqrt(2) units away from line. Rect r = new Rect { xMin = 0, xMax = 4, yMin = 6, yMax = 10 }; Assert.False(pl.RectWithinDistance(r, 1.3)); Assert.True(pl.RectWithinDistance(r, 1.5)); }
public void SinglePointPolylineRectWithinDistanceIsCircleTest() { GeoPolyline pl = new GeoPolyline(new GeoCoordinates(0, 0)); Rect r = new Rect { xMin = 1, xMax = 2, yMin = 1, yMax = 2 }; Assert.False(pl.RectWithinDistance(r, 1.1)); Assert.True(pl.RectWithinDistance(r, 1.5)); }
public void LongPolylineRectWithinDistanceSanityTest1() { List <GeoCoordinates> points = new List <GeoCoordinates>(); for (int i = 0; i < 1000; ++i) { // Points stretch from lng=0 to lng=9.99 points.Add(new GeoCoordinates(0, i / 100.0)); } GeoPolyline pl = new GeoPolyline(points); // Rect 1 unit above line. Rect r = new Rect { xMin = 0, xMax = 10, yMin = 1, yMax = 2 }; Assert.False(pl.RectWithinDistance(r, 0.9)); Assert.True(pl.RectWithinDistance(r, 1.1)); }
GetRide(UserRideOffer offer, ConcurrentGeoQuadtree <MatchableRideRequest> origins, ConcurrentGeoQuadtree <MatchableRideRequest> destinations) { RouteInfo driverRoute = await GetRoute(offer); var originsTask = GetElementsInsideAsync(origins, NearRoute); var destinationsTask = GetElementsInsideAsync(destinations, NearRoute); // Only consider passengers whose origins and destinations are near // the driver's route. var potentialPassengers = new HashSet <MatchableRideRequest>( from element in await originsTask select element.Data); potentialPassengers.IntersectWith( from element in await destinationsTask select element.Data); // Find a passenger going in the same direction as the driver such that // picking up the passenger does not put the driver too far out of their way. foreach (var passenger in potentialPassengers.Where(GoingInDriversDirection)) { RouteInfo routeWithPassenger = await GetRouteWithPassenger(offer, passenger); // Reject route if it's too far out of the way according to // the driver's settings. if (driverRoute.drivingTime.HasValue && routeWithPassenger.drivingTime.HasValue) { TimeSpan originalTime = driverRoute.drivingTime.Value; TimeSpan newTime = routeWithPassenger.drivingTime.Value; TimeSpan maxTime = originalTime + TimeSpan.FromMinutes(offer.RideOffer.MaxTimeOutOfWay); if (newTime > maxTime) { // Output debug info for demos. Program.LogError($"Matched {offer.User.UserInfo.UserId} with {passenger.Request.User.UserInfo.UserId}" + " but resulting route was too long." + $" Original trip duration: {originalTime.Minutes} mins." + $" Matched trip duration: {newTime.Minutes} mins." + $" Driver's max time out of way: {offer.RideOffer.MaxTimeOutOfWay} mins."); continue; } } return(RideWithPassenger(offer, passenger)); } return(EmptyRide(offer, driverRoute)); /// <summary> /// Tests whether any point in the rect is close enough to <see cref="route"/>. /// </summary> bool NearRoute(Rect rect) { // Ignore passengers more than approximately 1km of the route. // TODO Take large max-time-out-of-way values into account when choosing max-dist-out-of-way. double maxDistMeters = 1000; double maxDistDegrees = offer.RideOffer.Trip.Source.DegreesUpperBound(maxDistMeters); GeoPolyline route = driverRoute.overviewPolyline; return(route.RectWithinDistance(rect, maxDistDegrees)); } /// <summary> /// Tests whether this passenger is going in the same direction as the driver. /// </summary> bool GoingInDriversDirection(MatchableRideRequest request) { var driverDest = offer.RideOffer.Trip.Destination; var driverOrig = offer.RideOffer.Trip.Source; var driverSeg = new GeoSegment(driverOrig, driverDest); var passDest = request.Request.RideRequest.Trip.Destination; var passOrig = request.Request.RideRequest.Trip.Source; var passSeg = new GeoSegment(passOrig, passDest); // Use GeoSegments so that this works near prime meridian. var passDiff = passSeg.Point2Representative - passSeg.Point1Representative; var driverDiff = driverSeg.Point2Representative - driverSeg.Point1Representative; // Compute the dot product of the vectors. This is a pretty rough // estimate and doesn't take into account the Earth's curvature. return(passDiff.Dot(driverDiff) > 0); } }