package com.ard.route.service.impl; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollectionUtil; import com.ard.oss.service.impl.OssServiceContext; import com.ard.ossdock.service.impl.OssDockServiceContext; import com.ard.route.constant.FileTypeConstants; import com.ard.route.domain.djuav.RoutePointReq; import com.ard.route.domain.djuav.UavRouteReq; import com.ard.route.domain.djuav.WaypointHeadingReq; import com.ard.route.domain.djuav.WaypointTurnReq; import com.ard.route.domain.djuav.kml.*; import com.ard.route.domain.route.ArdRouteInfo; import com.ard.route.domain.vo.KmzInfoVo; import com.ard.route.domain.vo.KmzResultVo; import com.ard.route.enums.kml.ExitOnRCLostEnums; import com.ard.route.service.IArdRouteInfoService; import com.ard.route.util.InitializationUtils; import com.ard.route.util.RouteFileUtils; import com.ard.route.service.UavRouteService; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.DomDriver; import org.apache.commons.compress.archivers.ArchiveEntry; import org.apache.commons.compress.archivers.ArchiveInputStream; import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.mock.web.MockMultipartFile; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; import java.io.*; import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.zip.ZipOutputStream; import static com.ard.route.util.RouteFileUtils.*; import static com.ard.route.util.ToolUtils.*; import static com.ard.route.util.UavRouteReqUtils.kmzInfoVoToUavRouteReq; /** * Author:xia * Date: 2024/12/22 10:36 **/ @Service public class UavRouteServiceImpl implements UavRouteService { @Resource private OssServiceContext ossService; @Resource private OssDockServiceContext ossDockService; @Resource private IArdRouteInfoService ardRouteInformationService; InitializationUtils init = new InitializationUtils(); /** * 编辑kmz文件 */ @Override public KmzResultVo updateKmz(UavRouteReq uavRouteReq,String fileName){ KmzResultVo result = new KmzResultVo(); // 校验修改的文件是否存在 ArdRouteInfo routeInformation = ardRouteInformationService.selectArdRouteInfoByName(fileName); if ( routeInformation == null ){ result.setData("修改航线文件失败,请检查文件是否存在"); return result; } // 获取文件 String minioUrlName = subStringMinioUrlName(routeInformation.getPath()); try (InputStream inputStream = ossService.getObject(kmzPath,minioUrlName); ArchiveInputStream archiveInputStream = new ZipArchiveInputStream(inputStream)){ ArchiveEntry entry; KmlInfo kmlInfo = new KmlInfo(); KmlInfo wpmlInfo = new KmlInfo(); KmlParams kmlParams = new KmlParams(); while (!Objects.isNull(entry = archiveInputStream.getNextEntry())) { String name = entry.getName(); if (name.toLowerCase().endsWith(".kml")) { kmlInfo = RouteFileUtils.parseKml(archiveInputStream); buildKmlParams(kmlParams, kmlInfo); this.handleRouteUpdate(kmlInfo, uavRouteReq, FileTypeConstants.KML, kmlParams); } else if (name.toLowerCase().endsWith(".wpml")) { wpmlInfo = RouteFileUtils.parseKml(archiveInputStream); this.handleRouteUpdate(wpmlInfo, uavRouteReq, FileTypeConstants.WPML, kmlParams); } } // 删除文件 if ("100".equals(kmlInfo.getDocument().getKmlMissionConfig().getDroneInfo().getDroneEnumValue()) ||"91".equals(kmlInfo.getDocument().getKmlMissionConfig().getDroneInfo().getDroneEnumValue())){ ossDockService.deleteObject(kmzPath,minioUrlName); } ossService.deleteObject(kmzPath, minioUrlName); return buildKmzMethod(routeInformation.getName(), kmlInfo, wpmlInfo); } catch (Exception e) { e.printStackTrace(); result.setData("更新航线kmz文件失败"); return result; } } private static void buildKmlParams(KmlParams kmlParams, KmlInfo kmlInfo) { KmlFolder folder = kmlInfo.getDocument().getFolder(); kmlParams.setGlobalHeight(Double.valueOf(kmlInfo.getDocument().getKmlMissionConfig().getGlobalRTHHeight())); kmlParams.setAutoFlightSpeed(Double.valueOf(folder.getAutoFlightSpeed())); WaypointHeadingReq waypointHeadingReq = new WaypointHeadingReq(); waypointHeadingReq.setWaypointHeadingMode(folder.getGlobalWaypointHeadingParam().getWaypointHeadingMode()); waypointHeadingReq.setWaypointHeadingAngle(StringUtils.isNotBlank(folder.getGlobalWaypointHeadingParam().getWaypointHeadingAngle()) ? Double.valueOf(folder.getGlobalWaypointHeadingParam().getWaypointHeadingAngle()) : null); waypointHeadingReq.setWaypointPoiPoint(StringUtils.isNotBlank(folder.getGlobalWaypointHeadingParam().getWaypointPoiPoint()) ? folder.getGlobalWaypointHeadingParam().getWaypointPoiPoint() : null); kmlParams.setWaypointHeadingReq(waypointHeadingReq); WaypointTurnReq waypointTurnReq = new WaypointTurnReq(); waypointTurnReq.setWaypointTurnMode(folder.getGlobalWaypointTurnMode()); waypointTurnReq.setUseStraightLine(StringUtils.isNotBlank(folder.getGlobalUseStraightLine()) ? Integer.valueOf(folder.getGlobalUseStraightLine()) : null); kmlParams.setWaypointTurnReq(waypointTurnReq); kmlParams.setGimbalPitchMode(folder.getGimbalPitchMode()); kmlParams.setPayloadPosition(Integer.valueOf(kmlInfo.getDocument().getKmlMissionConfig().getPayloadInfo().getPayloadPositionIndex())); kmlParams.setImageFormat(folder.getPayloadParam().getImageFormat()); } private void handleRouteUpdate(KmlInfo kmlInfo, UavRouteReq uavRouteReq, String fileType, KmlParams kmlParams) { if (StringUtils.isNotBlank(uavRouteReq.getFinishAction())) { kmlInfo.getDocument().getKmlMissionConfig().setFinishAction(uavRouteReq.getFinishAction()); } if (StringUtils.isNotBlank(uavRouteReq.getExitOnRcLostAction())) { kmlInfo.getDocument().getKmlMissionConfig().setExitOnRCLost(ExitOnRCLostEnums.EXECUTE_LOST_ACTION.getValue()); kmlInfo.getDocument().getKmlMissionConfig().setExecuteRCLostAction(uavRouteReq.getExitOnRcLostAction()); } if (CollectionUtil.isNotEmpty(uavRouteReq.getRoutePointList())) { List placemarkList = new ArrayList<>(); for (RoutePointReq routePointReq : uavRouteReq.getRoutePointList()) { RoutePointInfo routePointInfo = BeanUtil.copyProperties(routePointReq, RoutePointInfo.class); KmlPlacemark kmlPlacemark = RouteFileUtils.buildKmlPlacemark(routePointInfo, kmlParams, fileType); placemarkList.add(kmlPlacemark); } kmlInfo.getDocument().getFolder().setPlacemarkList(placemarkList); } } /** * 生成kmz文件(带航点) */ @Override public KmzResultVo buildKmz(UavRouteReq uavRouteReq, String kmzName) { // 赋值默认参数 init.initialization(uavRouteReq); KmlParams kmlParams = new KmlParams(); BeanUtils.copyProperties(uavRouteReq, kmlParams); kmlParams.setRoutePointList(BeanUtil.copyToList(uavRouteReq.getRoutePointList(), RoutePointInfo.class)); return buildKmz(kmzName, kmlParams); } /** * 生成航线 KMZ 文件 * * @param fileName 文件名 * @param kmlParams 参数对象 * @return 本地文件路径 */ public KmzResultVo buildKmz(String fileName, KmlParams kmlParams) { KmlInfo kmlInfo = buildKml(kmlParams); KmlInfo wpmlInfo = buildWpml(kmlParams); return buildKmzMethod(fileName, kmlInfo, wpmlInfo); } /** * 生成航线 KMZ 文件 * * @param fileName 文件名 * @param kmlInfo kml 文件信息 * @param wpmlInfo wpml 文件信息 * @return 本地文件路径 */ public KmzResultVo buildKmzMethod(String fileName, KmlInfo kmlInfo, KmlInfo wpmlInfo) { XStream xStream = new XStream(new DomDriver()); xStream.processAnnotations(KmlInfo.class); xStream.addImplicitCollection(KmlActionGroup.class, "action"); xStream.addImplicitCollection(KmlPlacemark.class, "actionGroup"); String kml = XML_HEADER + xStream.toXML(kmlInfo); String wpml = XML_HEADER + xStream.toXML(wpmlInfo); KmzResultVo result = new KmzResultVo(); try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); ZipOutputStream zipOutputStream = new ZipOutputStream(baos)) { zipOutputStream.setLevel(0); // 创建 wpmz 目录中的 template.kml 文件条目 buildZipFile("wpmz/template.kml", zipOutputStream, kml); // 创建 wpmz 目录中的 waylines.wpml 文件条目 buildZipFile("wpmz/waylines.wpml", zipOutputStream, wpml); zipOutputStream.finish(); zipOutputStream.flush(); // 创建MultipartFile对象 MultipartFile multipartFile = new MockMultipartFile( fileName + ".kmz", fileName + ".kmz", "application/vnd.google-earth.kmz", new ByteArrayInputStream(baos.toByteArray()) ); // 通过无人机类型,判断上传文件 if ("100".equals(kmlInfo.getDocument().getKmlMissionConfig().getDroneInfo().getDroneEnumValue()) ||"91".equals(kmlInfo.getDocument().getKmlMissionConfig().getDroneInfo().getDroneEnumValue())){ String kmzFilePathDock = ossDockService.upload(kmzPath,multipartFile); result.setPathDock(kmzFilePathDock); } String kmzFilePath = ossService.upload(kmzPath,multipartFile); result.setPath(kmzFilePath); return result; } catch (Exception e) { throw new RuntimeException("KMZ文件生成或上传失败", e); } } /** * 解析kmz文件 */ @Override public KmzInfoVo parseKmz(String fileUrl){ KmzInfoVo kmzInfoVO = new KmzInfoVo(); try (InputStream inputStream = ossService.getObject(kmzPath,fileUrl); ArchiveInputStream archiveInputStream = new ZipArchiveInputStream(inputStream)){ ArchiveEntry entry; while (!Objects.isNull(entry = archiveInputStream.getNextEntry())) { String name = entry.getName(); if (name.toLowerCase().endsWith(".kml")) { kmzInfoVO.setKmlInfo(RouteFileUtils.parseKml(archiveInputStream)); } else if (name.toLowerCase().endsWith(".wpml")) { kmzInfoVO.setWpmlInfo(RouteFileUtils.parseKml(archiveInputStream)); } } return kmzInfoVO; }catch (Exception e) { e.printStackTrace(); } return null; } /** * KmzInfoVo实体类转换为UavRouteReq实体类 */ @Override public UavRouteReq kmzInfoVoToUavRouteReq(KmzInfoVo kmzInfoVo) { return kmzInfoVoToUavRouteReq(kmzInfoVo); } }