package com.ard.route.service.impl; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.io.FileUtil; import com.ard.common.utils.SecurityUtils; import com.ard.oss.service.impl.OssServiceContext; import com.ard.route.constant.FileTypeConstants; import com.ard.route.domain.RoutePointReq; import com.ard.route.domain.UavRouteReq; import com.ard.route.domain.WaypointHeadingReq; import com.ard.route.domain.WaypointTurnReq; import com.ard.route.domain.kml.*; import com.ard.route.domain.route.ArdRouteInformation; import com.ard.route.domain.vo.KmzInfoVO; import com.ard.route.enums.kml.ExitOnRCLostEnums; import com.ard.route.service.IArdRouteInformationService; import com.ard.route.util.FileUtils; 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.Value; 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.getFileNameWithoutExtension; /** * Author:songjian * Date: 2024/12/22 10:36 **/ @Service public class UavRouteServiceImpl implements UavRouteService { private Boolean isLocal = false; private String localFilePath = "KmzFile/kmz/"; private String kmzPath = "kmz"; @Resource private OssServiceContext ossService; @Resource private IArdRouteInformationService ardRouteInformationService; /** * XML 头部 */ private static final String XML_HEADER = "\n"; @Override public String updateKmz(UavRouteReq uavRouteReq) { // TODO 替换本地文件路径!!! File file = FileUtil.file("/Users/songjian/Project/IdeaProjects/dj-uav/file/kmz/航线kmz文件.kmz"); try (ArchiveInputStream archiveInputStream = new ZipArchiveInputStream(FileUtil.getInputStream(file))) { 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); } } return RouteFileUtils.buildKmz("更新航线kmz文件", kmlInfo, wpmlInfo, kmzPath); } catch (Exception e) { e.printStackTrace(); return "更新航线kmz文件失败"; } } 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); } } @Override public String buildKmz(UavRouteReq uavRouteReq, String fileName) { KmlParams kmlParams = new KmlParams(); BeanUtils.copyProperties(uavRouteReq, kmlParams); kmlParams.setRoutePointList(BeanUtil.copyToList(uavRouteReq.getRoutePointList(), RoutePointInfo.class)); return buildKmz(fileName, kmlParams); } /** * 生成航线 KMZ 文件 * * @param fileName 文件名 * @param kmlParams 参数对象 * @return 本地文件路径 */ public String buildKmz(String fileName, KmlParams kmlParams) { KmlInfo kmlInfo = buildKml(kmlParams); KmlInfo wpmlInfo = buildWpml(kmlParams); return buildKmz(fileName, kmlInfo, wpmlInfo); } /** * 生成航线 KMZ 文件 * * @param fileName 文件名 * @param kmlInfo kml 文件信息 * @param wpmlInfo wpml 文件信息 * @return 本地文件路径 */ public String buildKmz(String fileName, KmlInfo kmlInfo, KmlInfo wpmlInfo) { XStream xStream = new XStream(new DomDriver()); xStream.processAnnotations(KmlInfo.class); xStream.addImplicitCollection(KmlActionGroup.class, "action"); String kml = XML_HEADER + xStream.toXML(kmlInfo); String wpml = XML_HEADER + xStream.toXML(wpmlInfo); // 判断本地生成kmz文件 if (isLocal) { try (FileOutputStream fileOutputStream = new FileOutputStream(localFilePath + fileName + ".kmz"); ZipOutputStream zipOutputStream = new ZipOutputStream(fileOutputStream)) { zipOutputStream.setLevel(0); // 0 表示不压缩,存储方式 // 创建KMZ文件内容 buildZipFile("wpmz/template.kml", zipOutputStream, kml); buildZipFile("wpmz/waylines.wpml", zipOutputStream, wpml); } catch (Exception e) { throw new RuntimeException(e); } return localFilePath + fileName + ".kmz"; }else { try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); ZipOutputStream zipOutputStream = new ZipOutputStream(baos)) { zipOutputStream.setLevel(0); // 创建KMZ文件内容 buildZipFile("wpmz/template.kml", zipOutputStream, kml); buildZipFile("wpmz/waylines.wpml", zipOutputStream, wpml); zipOutputStream.finish(); zipOutputStream.flush(); // 获取文件大小 Double fileSize = (double) baos.size(); // 字节数 // 创建MultipartFile对象 MultipartFile multipartFile = new MockMultipartFile( fileName + ".kmz", fileName + ".kmz", "application/vnd.google-earth.kmz", new ByteArrayInputStream(baos.toByteArray()) ); String kmzFilePath = ossService.upload(kmzPath,multipartFile); // KMZ信息管理 ArdRouteInformation ardRouteInformation = new ArdRouteInformation(); ardRouteInformation.setFileName(fileName); ardRouteInformation.setFileNameNew(getFileNameWithoutExtension(kmzFilePath)); ardRouteInformation.setUpPath(kmzFilePath); ardRouteInformation.setUpFileSize(fileSize); ardRouteInformation.setCreateBy(SecurityUtils.getUsername()); ardRouteInformationService.insertArdRouteInformation(ardRouteInformation); return kmzFilePath; } catch (Exception e) { throw new RuntimeException("KMZ文件生成或上传失败", e); } } } @Override public KmzInfoVO parseKmz(String fileUrl) throws IOException { KmzInfoVO kmzInfoVO = new KmzInfoVO(); File file = FileUtils.downloadUrlToTempFile(fileUrl); try (ArchiveInputStream archiveInputStream = new ZipArchiveInputStream(FileUtil.getInputStream(file))) { 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; } }