package com.dongni.collisionavoidance.common.service; import com.dongni.collisionavoidance.common.model.spatial.VehicleLocation; import com.dongni.collisionavoidance.common.model.repository.VehicleLocationRepository; import com.dongni.collisionavoidance.common.model.MovingObjectType; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.GeometryFactory; import org.locationtech.jts.geom.Point; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.time.LocalDateTime; import java.util.List; import java.util.Optional; /** * 车辆位置服务类 - 基于PostGIS的空间数据管理 * 提供车辆位置的保存、查询、空间分析等功能 */ @Service @RequiredArgsConstructor @Slf4j public class VehicleLocationService { private final VehicleLocationRepository vehicleLocationRepository; private final GeometryFactory geometryFactory = new GeometryFactory(); /** * 保存车辆位置信息 */ @Transactional public VehicleLocation saveVehicleLocation(VehicleLocation vehicleLocation) { try { VehicleLocation saved = vehicleLocationRepository.save(vehicleLocation); log.debug("保存车辆位置: vehicleId={}, location=({}, {})", saved.getVehicleId(), saved.getLocation().getX(), saved.getLocation().getY()); return saved; } catch (Exception e) { log.error("保存车辆位置失败: vehicleId={}", vehicleLocation.getVehicleId(), e); throw new RuntimeException("保存车辆位置失败", e); } } /** * 批量保存车辆位置信息 */ @Transactional public List saveVehicleLocations(List vehicleLocations) { try { List saved = vehicleLocationRepository.saveAll(vehicleLocations); log.info("批量保存车辆位置: 数量={}", saved.size()); return saved; } catch (Exception e) { log.error("批量保存车辆位置失败: 数量={}", vehicleLocations.size(), e); throw new RuntimeException("批量保存车辆位置失败", e); } } /** * 创建车辆位置记录 */ public VehicleLocation createVehicleLocation(String vehicleId, MovingObjectType vehicleType, double longitude, double latitude, Double altitude, Double heading, Double speed) { Point location = geometryFactory.createPoint(new Coordinate(longitude, latitude)); location.setSRID(4326); // 设置WGS84坐标系 VehicleLocation vehicleLocation = new VehicleLocation(); vehicleLocation.setVehicleId(vehicleId); vehicleLocation.setVehicleType(vehicleType); vehicleLocation.setLocation(location); vehicleLocation.setAltitude(altitude); vehicleLocation.setHeading(heading); vehicleLocation.setSpeed(speed); vehicleLocation.setTimestamp(LocalDateTime.now()); return vehicleLocation; } /** * 根据车辆ID获取最新位置 */ public Optional getLatestVehicleLocation(String vehicleId) { try { return vehicleLocationRepository.findLatestByVehicleId(vehicleId); } catch (Exception e) { log.error("获取车辆最新位置失败: vehicleId={}", vehicleId, e); return Optional.empty(); } } /** * 根据车辆类型获取活跃车辆 */ public List getActiveVehiclesByType(String vehicleType, int minutesBack) { LocalDateTime since = LocalDateTime.now().minusMinutes(minutesBack); try { return vehicleLocationRepository.findActiveByVehicleType(vehicleType, since); } catch (Exception e) { log.error("获取活跃车辆失败: vehicleType={}, minutesBack={}", vehicleType, minutesBack, e); return List.of(); } } /** * 空间查询:获取指定半径范围内的车辆 */ public List getVehiclesWithinRadius(double longitude, double latitude, double radiusMeters, int minutesBack) { Point centerPoint = geometryFactory.createPoint(new Coordinate(longitude, latitude)); centerPoint.setSRID(4326); LocalDateTime since = LocalDateTime.now().minusMinutes(minutesBack); try { return vehicleLocationRepository.findVehiclesWithinRadius(centerPoint, radiusMeters, since); } catch (Exception e) { log.error("半径查询失败: center=({}, {}), radius={}m", longitude, latitude, radiusMeters, e); return List.of(); } } /** * 空间查询:获取指定区域内的车辆 */ public List getVehiclesInArea(String areaWkt, int minutesBack) { LocalDateTime since = LocalDateTime.now().minusMinutes(minutesBack); try { return vehicleLocationRepository.findVehiclesInArea(areaWkt, since); } catch (Exception e) { log.error("区域查询失败: areaWkt={}", areaWkt, e); return List.of(); } } /** * 获取车辆轨迹数据 */ public List getVehicleTrajectory(String vehicleId, LocalDateTime startTime, LocalDateTime endTime) { try { return vehicleLocationRepository.findVehicleTrajectory(vehicleId, startTime, endTime); } catch (Exception e) { log.error("获取车辆轨迹失败: vehicleId={}, 时间范围=[{}, {}]", vehicleId, startTime, endTime, e); return List.of(); } } /** * 获取指定高度范围内的车辆 */ public List getVehiclesByAltitudeRange(double minAltitude, double maxAltitude, int minutesBack) { LocalDateTime since = LocalDateTime.now().minusMinutes(minutesBack); try { return vehicleLocationRepository.findVehiclesByAltitudeRange(minAltitude, maxAltitude, since); } catch (Exception e) { log.error("高度范围查询失败: 高度范围=[{}, {}]", minAltitude, maxAltitude, e); return List.of(); } } /** * 获取高速移动的车辆 */ public List getHighSpeedVehicles(double speedThreshold, int minutesBack) { LocalDateTime since = LocalDateTime.now().minusMinutes(minutesBack); try { return vehicleLocationRepository.findHighSpeedVehicles(speedThreshold, since); } catch (Exception e) { log.error("高速车辆查询失败: speedThreshold={}", speedThreshold, e); return List.of(); } } /** * 获取最近的N个车辆 */ public List getNearestVehicles(double longitude, double latitude, int limit, int minutesBack) { Point referencePoint = geometryFactory.createPoint(new Coordinate(longitude, latitude)); referencePoint.setSRID(4326); LocalDateTime since = LocalDateTime.now().minusMinutes(minutesBack); try { return vehicleLocationRepository.findNearestVehicles(referencePoint, since, limit); } catch (Exception e) { log.error("最近车辆查询失败: reference=({}, {}), limit={}", longitude, latitude, limit, e); return List.of(); } } /** * 统计指定时间段内的唯一车辆数量 */ public long countUniqueVehiclesInTimeRange(LocalDateTime startTime, LocalDateTime endTime) { try { return vehicleLocationRepository.countUniqueVehiclesInTimeRange(startTime, endTime); } catch (Exception e) { log.error("车辆统计失败: 时间范围=[{}, {}]", startTime, endTime, e); return 0; } } /** * 清理历史数据 */ @Transactional public int cleanupHistoricalData(LocalDateTime beforeTime) { try { int deletedCount = vehicleLocationRepository.deleteHistoricalData(beforeTime); log.info("清理历史数据完成: 删除记录数={}, 清理时间点={}", deletedCount, beforeTime); return deletedCount; } catch (Exception e) { log.error("清理历史数据失败: beforeTime={}", beforeTime, e); throw new RuntimeException("清理历史数据失败", e); } } /** * 更新车辆位置 (如果存在则更新,否则创建新记录) */ @Transactional public VehicleLocation updateOrCreateVehicleLocation(String vehicleId, MovingObjectType vehicleType, double longitude, double latitude, Double altitude, Double heading, Double speed) { VehicleLocation vehicleLocation = createVehicleLocation(vehicleId, vehicleType, longitude, latitude, altitude, heading, speed); vehicleLocation.setTimestamp(LocalDateTime.now()); return saveVehicleLocation(vehicleLocation); } /** * 验证车辆位置数据的有效性 */ public boolean isValidVehicleLocation(double longitude, double latitude, Double altitude, Double heading, Double speed) { // 经度范围检查 if (longitude < -180 || longitude > 180) { log.warn("无效的经度值: {}", longitude); return false; } // 纬度范围检查 if (latitude < -90 || latitude > 90) { log.warn("无效的纬度值: {}", latitude); return false; } // 高度检查 if (altitude != null && (altitude < -1000 || altitude > 50000)) { log.warn("无效的高度值: {}", altitude); return false; } // 航向检查 if (heading != null && (heading < 0 || heading >= 360)) { log.warn("无效的航向值: {}", heading); return false; } // 速度检查 if (speed != null && (speed < 0 || speed > 1000)) { log.warn("无效的速度值: {}", speed); return false; } return true; } /** * 根据车辆ID删除所有历史位置记录 */ @Transactional public void deleteVehicleLocations(String vehicleId) { try { vehicleLocationRepository.deleteAll( vehicleLocationRepository.findVehicleTrajectory(vehicleId, LocalDateTime.now().minusYears(10), LocalDateTime.now()) ); log.info("删除车辆位置记录: vehicleId={}", vehicleId); } catch (Exception e) { log.error("删除车辆位置记录失败: vehicleId={}", vehicleId, e); throw new RuntimeException("删除车辆位置记录失败", e); } } }