FlashDeliveryRouteService.java 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
  1. package com.ruoyi.app.flashdelivery.route;
  2. import com.ruoyi.system.domain.flash.FlashDeliveryVehicleType;
  3. import org.slf4j.Logger;
  4. import org.slf4j.LoggerFactory;
  5. import org.springframework.stereotype.Service;
  6. /** 路线距离服务:优先请求地图路线,异常时使用球面直线距离保证报价仍然可用。 */
  7. @Service
  8. public class FlashDeliveryRouteService {
  9. private static final double EARTH_RADIUS_METERS = 6_371_000D;
  10. private static final Logger log = LoggerFactory.getLogger(FlashDeliveryRouteService.class);
  11. private final RouteDistanceProvider provider;
  12. public FlashDeliveryRouteService(RouteDistanceProvider provider) {
  13. this.provider = provider;
  14. }
  15. /** 按用户选择车型计算取送路线:优先地图路线,异常或无结果时降级球面直线距离。 */
  16. public RouteDistance calculate(GeoPoint origin, GeoPoint destination, Integer vehicleType) {
  17. validate(origin);
  18. validate(destination);
  19. int selectedVehicle = FlashDeliveryVehicleType.isSupported(vehicleType)
  20. ? vehicleType : FlashDeliveryVehicleType.MOTORCYCLE;
  21. try {
  22. RouteDistance route = provider.route(origin.latitude(), origin.longitude(),
  23. destination.latitude(), destination.longitude(), selectedVehicle);
  24. if (route != null && route.distanceMeters() > 0) {
  25. return route;
  26. }
  27. } catch (RuntimeException exception) {
  28. // 不记录地址、坐标或 Key;保留车型和失败原因以定位 Google Routes 降级。
  29. log.warn("Google Routes unavailable; use straight-line fallback. vehicleType={}, reason={}",
  30. selectedVehicle, exception.getMessage());
  31. }
  32. // Haversine 只作为降级结果,并通过 source=STRAIGHT_LINE 明确告知调用方。
  33. double lat1 = Math.toRadians(origin.latitude().doubleValue());
  34. double lat2 = Math.toRadians(destination.latitude().doubleValue());
  35. double deltaLat = lat2 - lat1;
  36. double deltaLon = Math.toRadians(destination.longitude().doubleValue()
  37. - origin.longitude().doubleValue());
  38. double a = Math.sin(deltaLat / 2) * Math.sin(deltaLat / 2)
  39. + Math.cos(lat1) * Math.cos(lat2)
  40. * Math.sin(deltaLon / 2) * Math.sin(deltaLon / 2);
  41. int meters = (int) Math.round(EARTH_RADIUS_METERS * 2D * Math.atan2(Math.sqrt(a), Math.sqrt(1D - a)));
  42. return new RouteDistance(Math.max(1, meters), null, "STRAIGHT_LINE");
  43. }
  44. private void validate(GeoPoint point) {
  45. if (point == null || point.latitude() == null || point.longitude() == null
  46. || point.latitude().doubleValue() < -90D || point.latitude().doubleValue() > 90D
  47. || point.longitude().doubleValue() < -180D || point.longitude().doubleValue() > 180D) {
  48. throw new IllegalArgumentException("invalid coordinates");
  49. }
  50. }
  51. }