大疆无人机航点飞行KMZ文件提取航点坐标

一、需要插件

复制代码
<!--        解析KMZ航线-->
        <dependency>
            <groupId>jaxen</groupId>
            <artifactId>jaxen</artifactId>
            <version>1.1.4</version>
        </dependency>


        <dependency>
            <groupId>dom4j</groupId>
            <artifactId>dom4j</artifactId>
            <version>1.6.1</version>
        </dependency>

二、KMZ解压成KML

复制代码
package com.dji.sample.common.util;

import org.dom4j.Document;
import org.dom4j.io.SAXReader;


import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;

//将KMZ航线转成KML航线
public class KmzKml {
    public Document unzipKmzToKml() throws Exception, Exception {
        String strkmz="/home/ych/KmzKml/航点飞行测试.kmz";

        System.out.println("**********************     【KMZ转kml开始】kmz路径:       **********************\n"+ strkmz);

        File file = new File(strkmz);

        ZipFile zipFile = new ZipFile(file);

        ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(file));
        InputStream inputStream = null;
        ZipEntry entry = null;
        Document doc = null;
        while ((entry = zipInputStream.getNextEntry()) != null) {
            String zipEntryName = entry.getName();
            //获取所需文件的节点
            if (zipEntryName.equals("wpmz/template.kml")) {

                inputStream = zipFile.getInputStream(entry);
                SAXReader reader = new SAXReader();
                doc = (Document) reader.read(inputStream);

                inputStream.close();
            }
        }
        zipFile.close();
        zipInputStream.close();
        return doc;
    }

}

三、KML提取航点坐标

复制代码
package com.dji.sample.common.util;

import org.dom4j.Document;
import org.dom4j.io.SAXReader;


import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;

//将KMZ航线转成KML航线
public class KmzKml {
    public Document unzipKmzToKml() throws Exception, Exception {
        String strkmz="/home/ych/KmzKml/航点飞行测试.kmz";

        System.out.println("**********************     【KMZ转kml开始】kmz路径:       **********************\n"+ strkmz);

        File file = new File(strkmz);

        ZipFile zipFile = new ZipFile(file);

        ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(file));
        InputStream inputStream = null;
        ZipEntry entry = null;
        Document doc = null;
        while ((entry = zipInputStream.getNextEntry()) != null) {
            String zipEntryName = entry.getName();
            //获取所需文件的节点
            if (zipEntryName.equals("wpmz/template.kml")) {

                inputStream = zipFile.getInputStream(entry);
                SAXReader reader = new SAXReader();
                doc = (Document) reader.read(inputStream);

                inputStream.close();
            }
        }
        zipFile.close();
        zipInputStream.close();
        return doc;
    }

}

四、调用

复制代码
@PostMapping("${url.wayline.prefix}${url.wayline.version}/workspaces/{workspace_id}/waylines/{wayline_id}/kmzKml")
    public HttpResultResponse<?> Kmz() throws Exception {
        KmzKml kmz = new KmzKml();
        Document unzipKmzToKml = kmz.unzipKmzToKml();

        // 将dom4j 的document对象转换成String
        // String asXML = unzipKmzToKml.asXML();

        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddhhmmss");
        Date date = new Date();
        String fileName = sdf.format(date);
        String strkml = "/home/ych/KmzKml/航点飞行.kml";

        // 创建kml到本地
        OutputFormat format = OutputFormat.createPrettyPrint();
        format.setEncoding("utf-8");
        XMLWriter xmlWriter = new XMLWriter(new FileOutputStream(strkml),format);
        xmlWriter.write(unzipKmzToKml);
        xmlWriter.close();

        System.out.println("\n**********************     【KMZ转kml成功】kml路径:       **********************\n"+ strkml);

        return HttpResultResponse.success();
    }
    @GetMapping("${url.wayline.prefix}${url.wayline.version}/workspaces/{workspace_id}/waylines/{wayline_id}/singlePoint")
    public  HttpResultResponse<?> Kml() throws Exception {
        File file = new File("/home/ych/KmzKml/航点飞行.kml");
        InputStream in  = new FileInputStream(file);
        Kml kml = new Kml();
        Collection<? extends String> coordinatesList = kml.parseXmlWithDom4j(in);
        List<?>  list = (List)coordinatesList;
        System.out.println(list.get(3));

        System.out.println("获取到的坐标值:");
        for (String coordinates : coordinatesList) {
            System.out.println(coordinates);
        }


        return HttpResultResponse.success(list);
    }

五、效果

复制代码
获取到的坐标值:
[121.369754843606, 37.5227177120414]
[121.370733797755, 37.5233089872322]
[121.370402874547, 37.5243355293892]
[121.372488283707, 37.5240973025597]
[121.372337081214, 37.5227352183251]
[121.370980455301, 37.5213158608334]
[121.372248708559, 37.5224800846951]

六、航线文件解读

复制代码
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:wpml="http://www.dji.com/wpmz/1.0.2">
<Document>

  <!-- Step 1: Implement File Creation Information -->
  <wpml:author>Name</wpml:author>
  <wpml:createTime>1637600807044</wpml:createTime>
  <wpml:updateTime>1637600875837</wpml:updateTime>
 
  <!-- Step 2: Setup Mission Configuration -->
  <wpml:missionConfig>
    <wpml:flyToWaylineMode>safely</wpml:flyToWaylineMode>
    <wpml:finishAction>goHome</wpml:finishAction>
    <wpml:exitOnRCLost>goContinue</wpml:exitOnRCLost>
    <wpml:executeRCLostAction>hover</wpml:executeRCLostAction>
    <wpml:takeOffSecurityHeight>20</wpml:takeOffSecurityHeight>
    <wpml:takeOffRefPoint>23.98057,115.987663,100</wpml:takeOffRefPoint>
    <wpml:takeOffRefPointAGLHeight>35</wpml:takeOffRefPointAGLHeight>
    <wpml:globalTransitionalSpeed>8</wpml:globalTransitionalSpeed>
    <wpml:droneInfo>
      <!-- Declare drone model with M30 -->
      <wpml:droneEnumValue>67</wpml:droneEnumValue>
      <wpml:droneSubEnumValue>0</wpml:droneSubEnumValue>
    </wpml:droneInfo>
    <wpml:payloadInfo>
      <!-- Declare payload model with M30 -->
      <wpml:payloadEnumValue>52</wpml:payloadEnumValue>
      <wpml:payloadPositionIndex>0</wpml:payloadPositionIndex>
    </wpml:payloadInfo>
  </wpml:missionConfig>
 
  <!-- Step 3: Setup A Folder for Waypoint Template -->
  <Folder>
    <wpml:templateType>waypoint</wpml:templateType>
    <wpml:useGlobalTransitionalSpeed>0</wpml:useGlobalTransitionalSpeed>
    <wpml:templateId>0</wpml:templateId>
    <wpml:waylineCoordinateSysParam>
      <wpml:coordinateMode>WGS84</wpml:coordinateMode>
      <wpml:heightMode>EGM96</wpml:heightMode>
      <wpml:globalShootHeight>50</wpml:globalShootHeight>
      <wpml:positioningType>GPS</wpml:positioningType>
      <wpml:surfaceFollowModeEnable>1</wpml:surfaceFollowModeEnable>
      <wpml:surfaceRelativeHeight>100</wpml:surfaceRelativeHeight>
    </wpml:waylineCoordinateSysParam>
    <wpml:autoFlightSpeed>7</wpml:autoFlightSpeed>
    <wpml:gimbalPitchMode>usePointSetting</wpml:gimbalPitchMode>
    <wpml:globalWaypointHeadingParam>
      <wpml:waypointHeadingMode>followWayline</wpml:waypointHeadingMode>
      <wpml:waypointHeadingAngle>45</wpml:waypointHeadingAngle>
      <wpml:waypointPoiPoint>24.323345,116.324532,31.000000</wpml:waypointPoiPoint>
      <wpml:waypointHeadingPathMode>clockwise</wpml:waypointHeadingPathMode>
    </wpml:globalWaypointHeadingParam>
    <wpml:globalWaypointTurnMode>toPointAndStopWithDiscontinuityCurvature</wpml:globalWaypointTurnMode>
    <wpml:globalUseStraightLine>0</wpml:globalUseStraightLine>
    <Placemark>
      <Point>
        <!-- Fill longitude and latitude here -->
        <coordinates>
          longitude,latitude
        </coordinates>
      </Point>
      <wpml:index>0</wpml:index>
      <wpml:ellipsoidHeight>90.2</wpml:ellipsoidHeight>
      <wpml:height>100</wpml:height>
      <wpml:useGlobalHeight>1</wpml:useGlobalHeight>
      <wpml:useGlobalSpeed>1</wpml:useGlobalSpeed>
      <wpml:useGlobalHeadingParam>1</wpml:useGlobalHeadingParam>
      <wpml:useGlobalTurnParam>1</wpml:useGlobalTurnParam>
      <wpml:gimbalPitchAngle>0</wpml:gimbalPitchAngle>
    </Placemark>
    <Placemark>
      <Point>
        <!-- Fill longitude and latitude here -->
        <coordinates>
          longitude,latitude
        </coordinates>
      </Point>
      <wpml:index>1</wpml:index>
      <wpml:ellipsoidHeight>90.2</wpml:ellipsoidHeight>
      <wpml:height>100</wpml:height>
      <wpml:useGlobalHeight>1</wpml:useGlobalHeight>
      <wpml:useGlobalSpeed>1</wpml:useGlobalSpeed>
      <wpml:useGlobalHeadingParam>1</wpml:useGlobalHeadingParam>
      <wpml:useGlobalTurnParam>1</wpml:useGlobalTurnParam>
      <wpml:gimbalPitchAngle>0</wpml:gimbalPitchAngle>
      <!-- Declare action group for waypoint 1# -->
      <wpml:actionGroup>
        <wpml:actionGroupId>0</wpml:actionGroupId>
        <wpml:actionGroupStartIndex>1</wpml:actionGroupStartIndex>
        <wpml:actionGroupEndIndex>1</wpml:actionGroupEndIndex>
        <wpml:actionGroupMode>sequence</wpml:actionGroupMode>
        <wpml:actionTrigger>
          <wpml:actionTriggerType>reachPoint</wpml:actionTriggerType>
        </wpml:actionTrigger>
        <!-- Declare the 1st action: rotate gimbal -->
        <wpml:action>
          <wpml:actionId>0</wpml:actionId>
          <wpml:actionActuatorFunc>gimbalRotate</wpml:actionActuatorFunc>
          <wpml:actionActuatorFuncParam>
            <wpml:gimbalRotateMode>absoluteAngle</wpml:gimbalRotateMode>
            <wpml:gimbalPitchRotateEnable>0</wpml:gimbalPitchRotateEnable>
            <wpml:gimbalPitchRotateAngle>0</wpml:gimbalPitchRotateAngle>
            <wpml:gimbalRollRotateEnable>0</wpml:gimbalRollRotateEnable>
            <wpml:gimbalRollRotateAngle>0</wpml:gimbalRollRotateAngle>
            <wpml:gimbalYawRotateEnable>1</wpml:gimbalYawRotateEnable>
            <wpml:gimbalYawRotateAngle>30</wpml:gimbalYawRotateAngle>
            <wpml:gimbalRotateTimeEnable>0</wpml:gimbalRotateTimeEnable>
            <wpml:gimbalRotateTime>0</wpml:gimbalRotateTime>
            <wpml:payloadPositionIndex>0</wpml:payloadPositionIndex>
          </wpml:actionActuatorFuncParam>
        </wpml:action>
        <!-- Declare the 2nd action: take photo -->
        <wpml:action>
          <wpml:actionId>1</wpml:actionId>
          <wpml:actionActuatorFunc>takePhoto</wpml:actionActuatorFunc>
          <wpml:actionActuatorFuncParam>
            <wpml:fileSuffix>point1</wpml:fileSuffix>
            <wpml:payloadPositionIndex>0</wpml:payloadPositionIndex>
          </wpml:actionActuatorFuncParam>
        </wpml:action>
      </wpml:actionGroup>
    </Placemark>
  </Folder>
</Document>
</kml>

将航线里的<coordinates>标签检测到并读取值即可获得坐标,可以按照该思路获取其它类型的航线,再将坐标系转换即可将航线展示到前端。

相关推荐
wuminyu2 小时前
专家视角看Java字节码加载与存储指令机制
java·linux·c语言·jvm·c++
callJJ3 小时前
Spring Data Redis 两种编程模型详解:同步 vs 响应式
java·spring boot·redis·python·spring
phltxy4 小时前
Spring Cloud 分布式服务部署实战:从 0 到 1 实现微服务上线
spring·spring cloud·微服务
wbs_scy4 小时前
Linux线程同步与互斥(三):线程同步深度解析之POSIX 信号量与环形队列生产者消费者模型,从原理到源码彻底吃透
java·开发语言
jinanwuhuaguo6 小时前
(第三十三篇)五月的文明奠基:OpenClaw 2026.5.2版本的文明级解读
android·java·开发语言·人工智能·github·拓扑学·openclaw
xmjd msup6 小时前
spring security 超详细使用教程(接入springboot、前后端分离)
java·spring boot·spring
952366 小时前
SpringBoot统一功能处理
java·spring boot·后端
Lyyaoo.7 小时前
优惠券秒杀业务分析
java·开发语言
消失的旧时光-19437 小时前
统一并发模型:线程、Reactor、协程本质是一件事(从线程到协程 · 第6篇·终章)
java·python·算法
勿忘初心12217 小时前
Java 国密 SM4 加密工具类实战(Hutool + BouncyCastle)|企业级数据加密 + 兼容 JDK8
java·数据安全·数据加密·后端开发·企业级开发·国密 sm4