|
|
@@ -3,11 +3,9 @@ package bus.service.impl;
|
|
|
import bus.model.SnowflakeUtil;
|
|
|
import bus.model.dto.*;
|
|
|
import bus.model.dto.page.BBusInfoPageDto;
|
|
|
-import bus.model.po.BCourseBusPo;
|
|
|
-import bus.model.po.BCourseInfoPo;
|
|
|
-import bus.model.po.BCourseStationPo;
|
|
|
+import bus.model.dto.req.BTrackLocalReqDto;
|
|
|
+import bus.model.po.*;
|
|
|
import bus.model.vo.BBusInfoVo;
|
|
|
-import bus.model.po.BBusInfoPo;
|
|
|
import bus.mapper.BBusInfoMapper;
|
|
|
|
|
|
import bus.service.*;
|
|
|
@@ -26,6 +24,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.beans.BeanUtils;
|
|
|
|
|
|
import javax.annotation.Resource;
|
|
|
+import java.math.BigDecimal;
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.Date;
|
|
|
import java.util.List;
|
|
|
@@ -268,6 +267,180 @@ public class BBusInfoServiceImpl extends ServiceImpl<BBusInfoMapper,BBusInfoPo>
|
|
|
return dto;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 根据车辆ID获取车辆实时追踪信息
|
|
|
+ * @param bTrackLocalReqDto 车辆位置请求信息
|
|
|
+ * @return 车辆位置和相邻站点信息
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public BTrackLocalDto getLocalBusInfo(BTrackLocalReqDto bTrackLocalReqDto) {
|
|
|
+ // 1. 根据车牌号获取车辆信息
|
|
|
+ QueryWrapper<BBusInfoPo> busQuery = new QueryWrapper<>();
|
|
|
+ busQuery.eq("bus_no", bTrackLocalReqDto.getBusNo())
|
|
|
+ .eq("is_delete", 0);
|
|
|
+ BBusInfoPo busInfo = this.getOne(busQuery);
|
|
|
+ if (busInfo == null) {
|
|
|
+ throw new BusinessException("车辆不存在");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 获取车辆所在路线
|
|
|
+ QueryWrapper<BCourseBusPo> courseQuery = new QueryWrapper<>();
|
|
|
+ courseQuery.eq("bus_id", busInfo.getId())
|
|
|
+ .eq("is_delete", 0)
|
|
|
+ .orderByDesc("create_time")
|
|
|
+ .last("LIMIT 1");
|
|
|
+ BCourseBusPo courseBus = bCourseBusService.getOne(courseQuery);
|
|
|
+ if (courseBus == null) {
|
|
|
+ throw new BusinessException("该车辆未分配路线");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 获取路线所有站点
|
|
|
+ List<BCourseStationPo> stationList = bCourseStationService.getListByCourse(courseBus.getCourseId());
|
|
|
+ if (CollectionUtil.isEmpty(stationList)) {
|
|
|
+ throw new BusinessException("路线站点信息不存在");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 4. 获取所有站点信息
|
|
|
+ List<String> stationIds = stationList.stream()
|
|
|
+ .map(BCourseStationPo::getStationId)
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ List<BStationInfoPo> stations = bStationInfoService.listByIds(stationIds);
|
|
|
+
|
|
|
+ // 按路线顺序排序站点
|
|
|
+ Map<String, BStationInfoPo> stationMap = stations.stream()
|
|
|
+ .collect(Collectors.toMap(BStationInfoPo::getId, station -> station));
|
|
|
+ List<BStationInfoPo> orderedStations = stationList.stream()
|
|
|
+ .map(station -> stationMap.get(station.getStationId()))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ // 5. 找出车辆当前位置的前后站点
|
|
|
+ BStationInfoPo prevStation = null;
|
|
|
+ BStationInfoPo nextStation = null;
|
|
|
+ double minDistance = Double.MAX_VALUE;
|
|
|
+ int currentIndex = -1;
|
|
|
+
|
|
|
+ for (int i = 0; i < orderedStations.size() - 1; i++) {
|
|
|
+ BStationInfoPo station1 = orderedStations.get(i);
|
|
|
+ BStationInfoPo station2 = orderedStations.get(i + 1);
|
|
|
+
|
|
|
+ // 计算车辆到这两个站点的距离
|
|
|
+ double dist1 = calculateDistance(
|
|
|
+ bTrackLocalReqDto.getLocalLatitude().doubleValue(),
|
|
|
+ bTrackLocalReqDto.getLocalLongitude().doubleValue(),
|
|
|
+ station1.getLatitude().doubleValue(),
|
|
|
+ station1.getLongitude().doubleValue()
|
|
|
+ );
|
|
|
+ double dist2 = calculateDistance(
|
|
|
+ bTrackLocalReqDto.getLocalLatitude().doubleValue(),
|
|
|
+ bTrackLocalReqDto.getLocalLongitude().doubleValue(),
|
|
|
+ station2.getLatitude().doubleValue(),
|
|
|
+ station2.getLongitude().doubleValue()
|
|
|
+ );
|
|
|
+
|
|
|
+ // 计算车辆是否在这两个站点之间
|
|
|
+ // 使用三角形不等式判断:如果车辆在两站点之间,那么到两站点的距离之和应该接近两站点之间的距离
|
|
|
+ double stationDistance = calculateDistance(
|
|
|
+ station1.getLatitude().doubleValue(),
|
|
|
+ station1.getLongitude().doubleValue(),
|
|
|
+ station2.getLatitude().doubleValue(),
|
|
|
+ station2.getLongitude().doubleValue()
|
|
|
+ );
|
|
|
+
|
|
|
+ double totalDistance = dist1 + dist2;
|
|
|
+ // 允许5%的误差
|
|
|
+ if (Math.abs(totalDistance - stationDistance) < stationDistance * 0.05
|
|
|
+ && totalDistance < minDistance) {
|
|
|
+ minDistance = totalDistance;
|
|
|
+ prevStation = station1;
|
|
|
+ nextStation = station2;
|
|
|
+ currentIndex = i;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 6. 构建返回数据
|
|
|
+ BTrackLocalDto result = new BTrackLocalDto();
|
|
|
+
|
|
|
+ // 设置当前位置信息
|
|
|
+ result.setLocalLatitude(bTrackLocalReqDto.getLocalLatitude());
|
|
|
+ result.setLocalLongitude(bTrackLocalReqDto.getLocalLongitude());
|
|
|
+ result.setLocalSpeed(bTrackLocalReqDto.getLocalSpeed());
|
|
|
+
|
|
|
+ if (prevStation != null && nextStation != null) {
|
|
|
+ // 设置站点信息
|
|
|
+ result.setLastStationId(prevStation.getId());
|
|
|
+ result.setLastStationName(prevStation.getName());
|
|
|
+ result.setNextStationId(nextStation.getId());
|
|
|
+ result.setNextStationName(nextStation.getName());
|
|
|
+
|
|
|
+ // 计算到下一站的距离(米)
|
|
|
+ double distanceToNext = calculateDistance(
|
|
|
+ bTrackLocalReqDto.getLocalLatitude().doubleValue(),
|
|
|
+ bTrackLocalReqDto.getLocalLongitude().doubleValue(),
|
|
|
+ nextStation.getLatitude().doubleValue(),
|
|
|
+ nextStation.getLongitude().doubleValue()
|
|
|
+ );
|
|
|
+
|
|
|
+ // 设置到下一站的距离和预计时间
|
|
|
+ result.setToNextStationDistance(String.format("%.0f", distanceToNext));
|
|
|
+
|
|
|
+ // 如果有速度信息,计算预计到达时间
|
|
|
+ if (bTrackLocalReqDto.getLocalSpeed() != null && bTrackLocalReqDto.getLocalSpeed().compareTo(BigDecimal.ZERO) > 0) {
|
|
|
+ // 速度转换为米/秒
|
|
|
+ double speedMps = bTrackLocalReqDto.getLocalSpeed().doubleValue() * 1000 / 3600;
|
|
|
+ // 计算预计时间(秒)
|
|
|
+ int estimatedSeconds = (int) (distanceToNext / speedMps);
|
|
|
+ // 转换为分钟
|
|
|
+ int estimatedMinutes = Math.max(1, estimatedSeconds / 60);
|
|
|
+ result.setToNextStationTime(String.format("%d", estimatedMinutes));
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置行驶方向(0表示向下,1表示向上)
|
|
|
+ result.setBusDirection("0"); // 因为我们是按照路线顺序遍历的,所以一定是向下
|
|
|
+ } else {
|
|
|
+ // 如果没有找到合适的站点对,找最近的站点
|
|
|
+ BStationInfoPo nearestStation = findNearestStation(
|
|
|
+ bTrackLocalReqDto.getLocalLatitude().doubleValue(),
|
|
|
+ bTrackLocalReqDto.getLocalLongitude().doubleValue(),
|
|
|
+ orderedStations
|
|
|
+ );
|
|
|
+ if (nearestStation != null) {
|
|
|
+ result.setLastStationId(nearestStation.getId());
|
|
|
+ result.setNextStationName(nearestStation.getName());
|
|
|
+ // 设置一个默认距离
|
|
|
+ result.setToNextStationDistance("未知");
|
|
|
+ result.setToNextStationTime("未知");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 找出最近的站点
|
|
|
+ */
|
|
|
+ private BStationInfoPo findNearestStation(double lat, double lon, List<BStationInfoPo> stations) {
|
|
|
+ if (CollectionUtil.isEmpty(stations)) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ BStationInfoPo nearest = null;
|
|
|
+ double minDistance = Double.MAX_VALUE;
|
|
|
+
|
|
|
+ for (BStationInfoPo station : stations) {
|
|
|
+ double distance = calculateDistance(
|
|
|
+ lat, lon,
|
|
|
+ station.getLatitude().doubleValue(),
|
|
|
+ station.getLongitude().doubleValue()
|
|
|
+ );
|
|
|
+ if (distance < minDistance) {
|
|
|
+ minDistance = distance;
|
|
|
+ nearest = station;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return nearest;
|
|
|
+ }
|
|
|
+
|
|
|
@Override
|
|
|
public BTrackStationDto getPoint(String busId) {
|
|
|
BTrackStationDto dto = new BTrackStationDto();
|
|
|
@@ -309,4 +482,29 @@ public class BBusInfoServiceImpl extends ServiceImpl<BBusInfoMapper,BBusInfoPo>
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 计算两个地理坐标点之间的距离(米)
|
|
|
+ * 使用球面余弦定理计算,计算量更少,对于城市内短距离计算精度足够
|
|
|
+ * @param lat1 第一个点的纬度
|
|
|
+ * @param lon1 第一个点的经度
|
|
|
+ * @param lat2 第二个点的纬度
|
|
|
+ * @param lon2 第二个点的经度
|
|
|
+ * @return 两点之间的距离,单位:米
|
|
|
+ */
|
|
|
+ private double calculateDistance(double lat1, double lon1, double lat2, double lon2) {
|
|
|
+ // 将经纬度转换为弧度
|
|
|
+ lat1 = Math.toRadians(lat1);
|
|
|
+ lon1 = Math.toRadians(lon1);
|
|
|
+ lat2 = Math.toRadians(lat2);
|
|
|
+ lon2 = Math.toRadians(lon2);
|
|
|
+
|
|
|
+ // 使用球面余弦定理计算
|
|
|
+ double distance = Math.acos(
|
|
|
+ Math.sin(lat1) * Math.sin(lat2) +
|
|
|
+ Math.cos(lat1) * Math.cos(lat2) * Math.cos(lon2 - lon1)
|
|
|
+ ) * 6371000; // 6371000是地球平均半径(米)
|
|
|
+
|
|
|
+ return distance;
|
|
|
+ }
|
|
|
}
|