package com.ard.tianyu.service.impl;
|
|
import com.ard.common.constant.UserConstants;
|
import com.ard.common.core.domain.entity.SysUser;
|
import com.ard.common.utils.DateUtils;
|
import com.ard.common.utils.StringUtils;
|
import com.ard.common.utils.uuid.IdUtils;
|
import com.ard.tianyu.controller.wayline.terrain.TerrainFollowingPlanner;
|
import com.ard.tianyu.domain.dto.wayline.ArdUavPositionDTO;
|
import com.ard.tianyu.domain.dto.wayline.ArdWaylineDTO;
|
import com.ard.tianyu.domain.entity.UavWayline;
|
import com.ard.tianyu.mapper.UavWaylineMapper;
|
import com.ard.tianyu.service.IUavWaylineService;
|
import com.ard.tianyu.service.IKmzFileService;
|
import com.ard.tianyu.util.GeoTools;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.stereotype.Service;
|
|
import javax.annotation.Resource;
|
import java.io.IOException;
|
import java.util.List;
|
import java.util.Optional;
|
|
/**
|
* 航线Service业务层处理
|
*
|
* @author ruoyi
|
* @date 2025-06-27
|
*/
|
@Slf4j
|
@Service
|
public class UavWaylineServiceImpl implements IUavWaylineService {
|
ObjectMapper mapper = new ObjectMapper();
|
|
@Resource
|
private UavWaylineMapper uavWaylineMapper;
|
@Resource
|
private IKmzFileService waylineFileService;
|
@Resource
|
private TerrainFollowingPlanner terrainFollowingPlanner;
|
|
/**
|
* 查询航线
|
*
|
* @param id 航线主键
|
* @return 航线
|
*/
|
@Override
|
public ArdWaylineDTO selectUavWaylineById(String id) {
|
UavWayline uavWayline = uavWaylineMapper.selectUavWaylineById(id);
|
return EntityConverterTowaylineDTO(uavWayline);
|
}
|
|
/**
|
* 查询航线列表
|
*
|
* @param uavWayline 航线
|
* @return 航线
|
*/
|
@Override
|
public List<UavWayline> selectUavWaylineList(UavWayline uavWayline) {
|
return uavWaylineMapper.selectUavWaylineList(uavWayline);
|
}
|
|
/**
|
* 新增航线
|
*
|
* @param ardWaylineDTO 航线
|
* @return 结果
|
*/
|
@Override
|
public int insertUavWayline(ArdWaylineDTO ardWaylineDTO) {
|
UavWayline uavWayline = waylineDTOConverterToEntity(ardWaylineDTO);
|
uavWayline.setCreateTime(DateUtils.getNowDate());
|
int row = uavWaylineMapper.insertUavWayline(uavWayline);
|
if (row > 0) {
|
waylineFileService.outputKmz(ardWaylineDTO);
|
}
|
return row;
|
}
|
|
/**
|
* 修改航线
|
*
|
* @param ardWaylineDTO 航线
|
* @return 结果
|
*/
|
@Override
|
public int updateUavWayline(ArdWaylineDTO ardWaylineDTO) {
|
UavWayline uavWayline = waylineDTOConverterToEntity(ardWaylineDTO);
|
uavWayline.setUpdateTime(DateUtils.getNowDate());
|
int row = uavWaylineMapper.updateUavWayline(uavWayline);
|
if (row > 0) {
|
waylineFileService.outputKmz(ardWaylineDTO);
|
}
|
return row;
|
}
|
|
/**
|
* 批量删除航线
|
*
|
* @param ids 需要删除的航线主键
|
* @return 结果
|
*/
|
@Override
|
public int deleteUavWaylineByIds(String[] ids) {
|
return uavWaylineMapper.deleteUavWaylineByIds(ids);
|
}
|
|
/**
|
* 删除航线信息
|
*
|
* @param id 航线主键
|
* @return 结果
|
*/
|
@Override
|
public int deleteUavWaylineById(String id) {
|
return uavWaylineMapper.deleteUavWaylineById(id);
|
}
|
|
/**
|
* 校验航线是否唯一
|
*
|
* @param ardWaylineDTO 航线信息
|
* @return 结果
|
*/
|
@Override
|
public boolean checkWaylineNameUnique(ArdWaylineDTO ardWaylineDTO)
|
{
|
String waylineId = ardWaylineDTO.getWaylineId();
|
UavWayline info = uavWaylineMapper.checkUavWaylineNameUnique(ardWaylineDTO.getWaylineName());
|
if (StringUtils.isNotNull(info) && !info.getId().equals(waylineId))
|
{
|
return UserConstants.NOT_UNIQUE;
|
}
|
return UserConstants.UNIQUE;
|
}
|
|
// DTO转换为实体类
|
private UavWayline waylineDTOConverterToEntity(ArdWaylineDTO ardWaylineDTO) {
|
UavWayline uavWayline = UavWayline.builder()
|
.id(Optional.ofNullable(ardWaylineDTO.getWaylineId()).orElse(IdUtils.simpleUUID()))
|
.name(ardWaylineDTO.getWaylineName())
|
.type(ardWaylineDTO.getWaylineType())
|
.uavModel(ardWaylineDTO.getUavModel())
|
.payloadModel(ardWaylineDTO.getPayloadModel())
|
.userWaypointCount(ardWaylineDTO.waylineUserPointCount)
|
.globalSpeed(ardWaylineDTO.getGlobalFlySpeed())
|
.globalHeight(ardWaylineDTO.getGlobalFlyHeight())
|
.build();
|
generateWaylineBytes(ardWaylineDTO, uavWayline);
|
return uavWayline;
|
}
|
|
// 实体类转换DTO
|
private ArdWaylineDTO EntityConverterTowaylineDTO(UavWayline uavWayline) {
|
try {
|
ArdWaylineDTO ardWaylineDTO = ArdWaylineDTO.builder()
|
.waylineId(uavWayline.getId())
|
.waylineName(uavWayline.getName())
|
.waylineType(uavWayline.getType())
|
.uavModel(uavWayline.getUavModel())
|
.payloadModel(uavWayline.getPayloadModel())
|
.waylineUserPointCount(uavWayline.getUserWaypointCount())
|
.waylineAllPointCount(uavWayline.getPlanWaypointCount())
|
.globalFlySpeed(uavWayline.getGlobalSpeed())
|
.globalFlyHeight(uavWayline.getGlobalHeight())
|
.build();
|
byte[] planWaylineBytes = uavWayline.getPlanWaylineData();
|
ardWaylineDTO = mapper.readValue(planWaylineBytes, ArdWaylineDTO.class);
|
|
//计算长度
|
double length = calculateWaylineLength(ardWaylineDTO);
|
ardWaylineDTO.setWaylineLength(length);
|
//计算飞行时间
|
double flyTime = calculateFlyTime(ardWaylineDTO);
|
ardWaylineDTO.setWaylineBaseFlyTime(flyTime);
|
return ardWaylineDTO;
|
} catch (IOException e) {
|
throw new RuntimeException("恢复航线对象错误!" + e.getMessage());
|
}
|
}
|
|
// 生成航线字节数组
|
private void generateWaylineBytes(ArdWaylineDTO ardWaylineDTO, UavWayline uavWayline) {
|
try {
|
ardWaylineDTO.setWaylineId(uavWayline.getId());
|
//二进制航线编码,保存原始航线数据
|
byte[] waylineBytes = mapper.writeValueAsBytes(ardWaylineDTO);
|
uavWayline.setSrcWaylineData(waylineBytes);
|
if (ardWaylineDTO.getWaylineType() == 1) {
|
log.info("面向逐点的航线规划!");
|
byte[] newWaylineBytes = mapper.writeValueAsBytes(ardWaylineDTO);
|
uavWayline.setPlanWaylineData(newWaylineBytes);
|
uavWayline.setPlanWaypointCount(ardWaylineDTO.getWaylineUserPointCount());
|
} else if (ardWaylineDTO.getWaylineType() == 3) {
|
log.info("面向仿地的航线规划!");
|
//仿地飞行算法
|
ArdWaylineDTO newWayline = terrainFollowingWayline(ardWaylineDTO);
|
byte[] newWaylineBytes = mapper.writeValueAsBytes(newWayline);
|
uavWayline.setPlanWaylineData(newWaylineBytes);
|
uavWayline.setPlanWaypointCount(newWayline.getWaylineUserPointCount());
|
} else {
|
log.error("航线设置错误:{}", ardWaylineDTO.getWaylineType());
|
throw new RuntimeException("航线类型错误" + ardWaylineDTO.getWaylineType());
|
}
|
} catch (Exception e) {
|
log.error("航线规划失败:{}", e.getMessage());
|
throw new RuntimeException("航线规划失败!" + e.getMessage());
|
}
|
}
|
|
//调用仿地航线算法
|
private ArdWaylineDTO terrainFollowingWayline(ArdWaylineDTO ardWaylineDTO) throws Exception {
|
|
ArdWaylineDTO newWaylineDTO = deepCopyWayline(ardWaylineDTO);
|
//使用仿地飞行规划器
|
List<ArdUavPositionDTO> ardUavPositionDTOS = terrainFollowingPlanner.interpolateWithTerrain(ardWaylineDTO);
|
newWaylineDTO.setWaylineAllPointCount(ardUavPositionDTOS.size());//总航点数量
|
long userPointCount = ardUavPositionDTOS.stream()
|
.filter(p -> p.getType() == 0)
|
.count();
|
newWaylineDTO.setWaylineUserPointCount((int) userPointCount);//用户航点数量
|
newWaylineDTO.setUavPositions(ardUavPositionDTOS);
|
// 规划成功,返回结果
|
return newWaylineDTO;
|
|
}
|
|
private ArdWaylineDTO deepCopyWayline(ArdWaylineDTO ardWaylineDTO) {
|
|
ArdWaylineDTO newWaylineDTO = null;
|
try {
|
byte[] waylineBytes = mapper.writeValueAsBytes(ardWaylineDTO);
|
|
newWaylineDTO = mapper.readValue(waylineBytes, ArdWaylineDTO.class);
|
|
} catch (JsonProcessingException e) {
|
e.printStackTrace();
|
} catch (IOException e) {
|
e.printStackTrace();
|
}
|
return newWaylineDTO;
|
}
|
|
//计算航线长度
|
public double calculateWaylineLength( ArdWaylineDTO ardWaylineDTO) {
|
List<ArdUavPositionDTO> uavPositions = ardWaylineDTO.getUavPositions();
|
if (uavPositions == null || uavPositions.size() < 2) {
|
return 0.0;
|
}
|
|
double totalLength = 0.0;
|
for (int i = 1; i < uavPositions.size(); i++) {
|
ArdUavPositionDTO prev = uavPositions.get(i - 1);
|
ArdUavPositionDTO curr = uavPositions.get(i);
|
totalLength += GeoTools.calculateDistance(
|
prev.getUavPosition().getLatitude(), prev.getUavPosition().getLongitude(),
|
curr.getUavPosition().getLatitude(), curr.getUavPosition().getLongitude()
|
);
|
}
|
return totalLength;
|
}
|
//计算飞行时间
|
public double calculateFlyTime(ArdWaylineDTO ardWaylineDTO) {
|
double totalLength = calculateWaylineLength(ardWaylineDTO); // 单位:米
|
Float globalSpeed = ardWaylineDTO.getGlobalFlySpeed(); // 单位:米/秒
|
|
if (globalSpeed == null || globalSpeed <= 0) {
|
throw new IllegalArgumentException("全局速度无效,必须大于0");
|
}
|
return totalLength / globalSpeed; // 返回时间,单位:秒
|
}
|
|
|
}
|