You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

906 lines
36 KiB
TypeScript

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/**
* 面状航线航线文件生成
*
* 目标构造方法传入template.json、wayline.json参数
*
* 结果返回kmz航线文件的Blob二进制数据的对象
*
*/
import { XMLBuilder } from 'fast-xml-parser';
import JSZip from "jszip";
import { saveAs } from "file-saver";
import { calculateGsd,calculateSpacing,calculateInterval,uavModel } from './calculateAirLine'
export default class Mapping2d {
/**
* 基础信息
*/
private templateKmlConfig;
private waylineWpmlConfig;
private gsd;
/**
* 构造方法
*/
constructor(templateKmlConfig:Object,waylineWpmlConfig:Object){
this.templateKmlConfig = templateKmlConfig;
this.waylineWpmlConfig = waylineWpmlConfig;
}
/**
* 计算获取结果
*/
generateAirLine(){
// 测区
let polygon = this.handlerCalculateParams();
// 根据航线文件中高度计算gsd
this.gsd = calculateGsd(this.templateKmlConfig.Folder.Placemark.height,uavModel['m4td']);
// 间距
let spacing = calculateSpacing(this.gsd,this.templateKmlConfig.Folder.Placemark.overlap.orthoCameraOverlapW/100,uavModel['m4td']);
// 初始化角度
let angle = this.templateKmlConfig.Folder.Placemark.direction ? this.templateKmlConfig.Folder.Placemark.direction : 0;
// 获取航点
let airPoints = this.generateScanLines(polygon,spacing/10000,angle);
// 获取文件
let blob = this.handlerWaylineWpmlConfig(airPoints);
return blob;
}
/**
* 根据航线文件高度计算gsd
*
* 根据gsd 和 航线文件中重叠率 计算航线间距
*
*/
/**
* 处理测区范围
*/
handlerCalculateParams(){
let coordinateArray =this.templateKmlConfig.Folder.Placemark.Polygon.outerBoundaryIs.LinearRing.coordinates.split('\n');
let geomtryCoorinate = [];
coordinateArray.forEach((item, index) => {
let trimStr = item.trim();
let arr = trimStr.split(',');
for (let i = 0; i < arr.length; i++) {
arr[i] = parseFloat(arr[i]);
}
geomtryCoorinate.push(arr);
});
geomtryCoorinate.push(geomtryCoorinate[0]);
let geometry = {
type: 'Polygon',
coordinates: [geomtryCoorinate],
};
console.log("geometry123",geometry)
return geometry;
}
/**
* 生成航线
*/
generateScanLines(polygon, spacing, angle = 0) {
if (!turf.booleanValid(polygon)) throw new Error('无效的多边形');
spacing = Math.abs(spacing);
// 获取多边形的旋转边界框
const bbox = turf.bbox(polygon);
const center = turf.center(polygon).geometry.coordinates;
// 计算需要生成的线数量(加缓冲确保完全覆盖)
const diagLength = turf.distance(
turf.point([bbox[0], bbox[1]]),
turf.point([bbox[2], bbox[3]]),
);
const lineCount = Math.ceil(diagLength / spacing) + 2;
// 生成基础水平线
const lines = [];
for (let i = -1; i <= lineCount; i++) {
const y = bbox[1] + i * spacing * 0.11 - spacing * 0.11;
lines.push(
turf.lineString([
[bbox[0] - spacing, y],
[bbox[2] + spacing, y],
]),
);
}
// 旋转线条到指定角度
const rotatedLines = lines.map((line) =>
turf.transformRotate(line, angle - 90, { pivot: center }),
);
// 裁剪线条到多边形内并处理结果
const coverageLines = [];
rotatedLines.forEach((line) => {
try {
const intersection = turf.lineIntersect(line, polygon);
if (intersection.features.length >= 2) {
// 按与线起点距离排序交点
const sortedPoints = intersection.features
.map((f) => f.geometry.coordinates)
.sort(
(a, b) =>
turf.distance(line.geometry.coordinates[0], turf.point(a)) -
turf.distance(line.geometry.coordinates[0], turf.point(b)),
);
// 创建连接最远两个交点的线段
coverageLines.push(
turf.lineString([sortedPoints[0], sortedPoints[sortedPoints.length - 1]]),
);
}
} catch (e) {
console.warn('处理线段时出错:', e);
}
});
let connectedLine = this.connectLinesManual(turf.featureCollection(coverageLines));
// 将航点提取并添加到airPoints
let airPoints = [];
connectedLine.geometry.coordinates?.forEach((item, index) => {
let point = {
id: index,
lng: item[0],
lat: item[1],
alt: item[2],
aircraftHorizontalAngle: 0,
cameraHorizontalAngle: 0,
cameraVerticalAngle: 0,
focalLength: 1,
};
airPoints?.push(point);
});
// 倒数第2个点
let penultimatePoint = JSON.parse(JSON.stringify(airPoints[airPoints.length - 1]));
penultimatePoint.id = penultimatePoint.id + 1;
airPoints?.push(penultimatePoint);
// 添加测区中心点 最后1个点
// let turfPolygon = turf.polygon([polygonGeoJson.value]);
let polygonCenter = turf.centroid(polygon);
let lastPoint = {
id: airPoints[airPoints.length - 1].id + 1,
lng: polygonCenter.geometry.coordinates[0],
lat: polygonCenter.geometry.coordinates[1],
alt: airPoints[airPoints.length - 1].alt,
aircraftHorizontalAngle: 0,
cameraHorizontalAngle: 0,
cameraVerticalAngle: 0,
focalLength: 1,
};
airPoints?.push(lastPoint);
// 添加最后一个点到线数据中
connectedLine.geometry.coordinates.push([lastPoint.lng, lastPoint.lat, lastPoint.alt]);
// return connectedLine;
return airPoints;
}
/**
* 处理航点高度
*/
connectLinesManual(lines){
// 确保输入是FeatureCollection
if (lines.type !== 'FeatureCollection') {
lines = turf.featureCollection([lines]);
}
// 收集所有坐标点
let allCoords = [];
lines.features.forEach((line, index) => {
// 相对起飞点高度
let relativeHeight = 120;
line.geometry.coordinates?.forEach((item, idx) => {
line.geometry.coordinates[idx].push(relativeHeight);
});
if (line.geometry.type === 'LineString' && index % 2 == 0) {
allCoords = allCoords.concat(line.geometry.coordinates.reverse());
} else {
allCoords = allCoords.concat(line.geometry.coordinates);
}
});
// 移除连续重复的点
const cleanedCoords = [];
if (allCoords.length > 0) {
cleanedCoords.push(allCoords[0]);
for (let i = 1; i < allCoords.length; i++) {
const prev = cleanedCoords[cleanedCoords.length - 1];
if (prev[0] !== allCoords[i][0] || prev[1] !== allCoords[i][1]) {
cleanedCoords.push(allCoords[i]);
}
}
}
return turf.lineString(cleanedCoords);
};
/**
* 处理wayline.json数据
*/
async handlerWaylineWpmlConfig(airPoints:array){
this.waylineWpmlConfig.Folder.Placemark = [];
airPoints.forEach((item,index)=>{
let point = null;
// 根据高度模式 设置高度
let height = 0;
// 计算间隔时间
let spaceTime = (calculateInterval(this.gsd,this.templateKmlConfig.Folder.Placemark.overlap.orthoCameraOverlapH/100,uavModel['m4td']) / this.templateKmlConfig.Folder.autoFlightSpeed) * 2
// 起飞点高度
let heightArr = this.templateKmlConfig.missionConfig.takeOffRefPoint.split(",");
height = heightArr[2]
// 处理第1个航点
if(index == 0){
point = {
"Point": {
"coordinates":"\n"+item.lng+","+item.lat+"\n"
},
"index": item.id,
"executeHeight": this.templateKmlConfig.Folder.Placemark.height,
"waypointSpeed": this.templateKmlConfig.Folder.autoFlightSpeed,
"waypointHeadingParam": {
"waypointHeadingMode": "followWayline",
"waypointHeadingAngle": -96.9990577342362,
"waypointPoiPoint": "0.000000,0.000000,0.000000",
"waypointHeadingAngleEnable": 1,
"waypointHeadingPathMode": "followBadArc",
"waypointHeadingPoiIndex": 0
},
"waypointTurnParam": {
"waypointTurnMode": "toPointAndStopWithDiscontinuityCurvature",
"waypointTurnDampingDist": 0
},
"useStraightLine": 1,
"actionGroup": [
{
"actionGroupId": 0,
"actionGroupStartIndex": item.id,
"actionGroupEndIndex": airPoints.length - 2,
"actionGroupMode": "sequence",
"actionTrigger": {
"actionTriggerType": "betweenAdjacentPoints"
},
"action": [
{
"actionId": 0,
"actionActuatorFunc": "gimbalAngleLock"
},
{
"actionId": 1,
"actionActuatorFunc": "gimbalRotate",
"actionActuatorFuncParam": {
"gimbalHeadingYawBase": "aircraft",
"gimbalRotateMode": "absoluteAngle",
"gimbalPitchRotateEnable": 1,
"gimbalPitchRotateAngle": -90,
"gimbalRollRotateEnable": 0,
"gimbalRollRotateAngle": 0,
"gimbalYawRotateEnable": 0,
"gimbalYawRotateAngle": 0,
"gimbalRotateTimeEnable": 0,
"gimbalRotateTime": 10,
"payloadPositionIndex": 0
}
},
{
"actionId": 2,
"actionActuatorFunc": "startTimeLapse",
"actionActuatorFuncParam": {
"payloadPositionIndex": 0,
"useGlobalPayloadLensIndex": 0,
"payloadLensIndex": "visable",
"minShootInterval":spaceTime
}
}
]
},
{
"actionGroupId": 1,
"actionGroupStartIndex": item.id,
"actionGroupEndIndex": airPoints.length - 2,
"actionGroupMode": "sequence",
"actionTrigger": {
"actionTriggerType": "multipleTiming",
"actionTriggerParam": 2
},
"action": {
"actionId": 0,
"actionActuatorFunc": "gimbalRotate",
"actionActuatorFuncParam": {
"gimbalHeadingYawBase": "aircraft",
"gimbalRotateMode": "absoluteAngle",
"gimbalPitchRotateEnable": 1,
"gimbalPitchRotateAngle": -90,
"gimbalRollRotateEnable": 0,
"gimbalRollRotateAngle": 0,
"gimbalYawRotateEnable": 0,
"gimbalYawRotateAngle": 0,
"gimbalRotateTimeEnable": 0,
"gimbalRotateTime": 10,
"payloadPositionIndex": 0
}
}
}
],
"waypointGimbalHeadingParam": {
"waypointGimbalPitchAngle": 0,
"waypointGimbalYawAngle": 0
},
"isRisky": 0,
"waypointWorkType": 0
}
}else if(index == airPoints.length -1){ // 处理最后1个航点
point = {
"Point": {
"coordinates":"\n"+item.lng+","+item.lat +"\n"
},
"index": item.id,
"executeHeight": this.templateKmlConfig.Folder.Placemark.height,
"waypointSpeed": this.templateKmlConfig.Folder.autoFlightSpeed,
"waypointHeadingParam": {
"waypointHeadingMode": "followWayline",
"waypointHeadingAngle": 0,
"waypointPoiPoint": "0.000000,0.000000,0.000000",
"waypointHeadingAngleEnable": 0,
"waypointHeadingPathMode": "followBadArc",
"waypointHeadingPoiIndex": 0
},
"waypointTurnParam": {
"waypointTurnMode": "toPointAndStopWithDiscontinuityCurvature",
"waypointTurnDampingDist": 0
},
"useStraightLine": 1,
"actionGroup": {
"actionGroupId": 6,
"actionGroupStartIndex": item.id,
"actionGroupEndIndex": item.id,
"actionGroupMode": "sequence",
"actionTrigger": {
"actionTriggerType": "reachPoint"
},
"action": [
{
"actionId": 0,
"actionActuatorFunc": "stopTimeLapse",
"actionActuatorFuncParam": {
"payloadPositionIndex": 0,
"payloadLensIndex": "visable"
}
},
{
"actionId": 1,
"actionActuatorFunc": "gimbalAngleUnlock"
}
]
},
"waypointGimbalHeadingParam": {
"waypointGimbalPitchAngle": 0,
"waypointGimbalYawAngle": 0
},
"isRisky": 0,
"waypointWorkType": 0
}
}else if(index == airPoints.length -2){ // 处理倒数第2个航点
point = {
"Point": {
"coordinates":"\n"+ (item.lng+0.00001)+","+(item.lat+0.00001)+"\n"
},
"index": item.id,
"executeHeight": this.templateKmlConfig.Folder.Placemark.height,
"waypointSpeed": this.templateKmlConfig.Folder.autoFlightSpeed,
"waypointHeadingParam": {
"waypointHeadingMode": "followWayline",
"waypointHeadingAngle": -120.875268753987,
"waypointPoiPoint": "0.000000,0.000000,0.000000",
"waypointHeadingAngleEnable": 1,
"waypointHeadingPathMode": "followBadArc",
"waypointHeadingPoiIndex": 0
},
"waypointTurnParam": {
"waypointTurnMode": "toPointAndStopWithDiscontinuityCurvature",
"waypointTurnDampingDist": 0
},
"useStraightLine": 1,
"actionGroup": [
{
"actionGroupId": 3,
"actionGroupStartIndex": item.id,
"actionGroupEndIndex": item.id,
"actionGroupMode": "sequence",
"actionTrigger": {
"actionTriggerType": "reachPoint"
},
"action": [
{
"actionId": 0,
"actionActuatorFunc": "gimbalRotate",
"actionActuatorFuncParam": {
"gimbalHeadingYawBase": "aircraft",
"gimbalRotateMode": "absoluteAngle",
"gimbalPitchRotateEnable": 1,
"gimbalPitchRotateAngle": -45,
"gimbalRollRotateEnable": 0,
"gimbalRollRotateAngle": 0,
"gimbalYawRotateEnable": 1,
"gimbalYawRotateAngle": 0,
"gimbalRotateTimeEnable": 0,
"gimbalRotateTime": 10,
"payloadPositionIndex": 0
}
},
{
"actionId": 1,
"actionActuatorFunc": "hover",
"actionActuatorFuncParam": {
"hoverTime": 0.5
}
}
]
},
{
"actionGroupId": 4,
"actionGroupStartIndex": item.id,
"actionGroupEndIndex": item.id+1,
"actionGroupMode": "sequence",
"actionTrigger": {
"actionTriggerType": "multipleTiming",
"actionTriggerParam": 2
},
"action": {
"actionId": 0,
"actionActuatorFunc": "gimbalRotate",
"actionActuatorFuncParam": {
"gimbalHeadingYawBase": "aircraft",
"gimbalRotateMode": "absoluteAngle",
"gimbalPitchRotateEnable": 1,
"gimbalPitchRotateAngle": -45,
"gimbalRollRotateEnable": 0,
"gimbalRollRotateAngle": 0,
"gimbalYawRotateEnable": 0,
"gimbalYawRotateAngle": 0,
"gimbalRotateTimeEnable": 0,
"gimbalRotateTime": 10,
"payloadPositionIndex": 0
}
}
},
{
"actionGroupId": 5,
"actionGroupStartIndex": item.id,
"actionGroupEndIndex": item.id+1,
"actionGroupMode": "sequence",
"actionTrigger": {
"actionTriggerType": "betweenAdjacentPoints"
},
"action": [
{
"actionId": 0,
"actionActuatorFunc": "gimbalAngleLock"
},
{
"actionId": 1,
"actionActuatorFunc": "gimbalRotate",
"actionActuatorFuncParam": {
"gimbalHeadingYawBase": "aircraft",
"gimbalRotateMode": "absoluteAngle",
"gimbalPitchRotateEnable": 1,
"gimbalPitchRotateAngle": -45,
"gimbalRollRotateEnable": 0,
"gimbalRollRotateAngle": 0,
"gimbalYawRotateEnable": 0,
"gimbalYawRotateAngle": 0,
"gimbalRotateTimeEnable": 0,
"gimbalRotateTime": 10,
"payloadPositionIndex": 0
}
},
{
"actionId": 2,
"actionActuatorFunc": "startTimeLapse",
"actionActuatorFuncParam": {
"payloadPositionIndex": 0,
"useGlobalPayloadLensIndex": 0,
"payloadLensIndex": "visable",
"minShootInterval": spaceTime
}
}
]
}
],
"waypointGimbalHeadingParam": {
"waypointGimbalPitchAngle": 0,
"waypointGimbalYawAngle": 0
},
"isRisky": 0,
"waypointWorkType": 0
};
let point2 = {
"Point": {
"coordinates":(item.lng+0.00001)+","+(item.lat+0.00001)
},
"index": item.id,
"executeHeight": this.templateKmlConfig.Folder.Placemark.height,
"waypointSpeed": this.templateKmlConfig.Folder.autoFlightSpeed,
"waypointHeadingParam": {
"waypointHeadingMode": "followWayline",
"waypointHeadingAngle": -44.6751949389683,
"waypointPoiPoint": "0.000000,0.000000,0.000000",
"waypointHeadingAngleEnable": 1,
"waypointHeadingPathMode": "followBadArc",
"waypointHeadingPoiIndex": 0
},
"waypointTurnParam": {
"waypointTurnMode": "toPointAndStopWithDiscontinuityCurvature",
"waypointTurnDampingDist": 0
},
"useStraightLine": 1,
"actionGroup": [
{
"actionGroupId": 3,
"actionGroupStartIndex": item.id,
"actionGroupEndIndex": item.id,
"actionGroupMode": "sequence",
"actionTrigger": {
"actionTriggerType": "reachPoint"
},
"action": [
{
"actionId": 0,
"actionActuatorFunc": "gimbalRotate",
"actionActuatorFuncParam": {
"gimbalHeadingYawBase": "aircraft",
"gimbalRotateMode": "absoluteAngle",
"gimbalPitchRotateEnable": 1,
"gimbalPitchRotateAngle": -45,
"gimbalRollRotateEnable": 0,
"gimbalRollRotateAngle": 0,
"gimbalYawRotateEnable": 1,
"gimbalYawRotateAngle": 0,
"gimbalRotateTimeEnable": 0,
"gimbalRotateTime": 10,
"payloadPositionIndex": 0
}
},
{
"actionId": 1,
"actionActuatorFunc": "hover",
"actionActuatorFuncParam": {
"hoverTime": 0.5
}
}
]
},
{
"actionGroupId": 4,
"actionGroupStartIndex": item.id,
"actionGroupEndIndex": item.id+1,
"actionGroupMode": "sequence",
"actionTrigger": {
"actionTriggerType": "multipleTiming",
"actionTriggerParam": 2
},
"action": {
"actionId": 0,
"actionActuatorFunc": "gimbalRotate",
"actionActuatorFuncParam": {
"gimbalHeadingYawBase": "aircraft",
"gimbalRotateMode": "absoluteAngle",
"gimbalPitchRotateEnable": 1,
"gimbalPitchRotateAngle": -45,
"gimbalRollRotateEnable": 0,
"gimbalRollRotateAngle": 0,
"gimbalYawRotateEnable": 0,
"gimbalYawRotateAngle": 0,
"gimbalRotateTimeEnable": 0,
"gimbalRotateTime": 10,
"payloadPositionIndex": 0
}
}
},
{
"actionGroupId":5,
"actionGroupStartIndex": item.id,
"actionGroupEndIndex": item.id+1,
"actionGroupMode": "sequence",
"actionTrigger": {
"actionTriggerType": "betweenAdjacentPoints"
},
"action": [
{
"actionId": 0,
"actionActuatorFunc": "gimbalAngleLock"
},
{
"actionId": 1,
"actionActuatorFunc": "gimbalRotate",
"actionActuatorFuncParam": {
"gimbalHeadingYawBase": "aircraft",
"gimbalRotateMode": "absoluteAngle",
"gimbalPitchRotateEnable": 1,
"gimbalPitchRotateAngle": -45,
"gimbalRollRotateEnable": 0,
"gimbalRollRotateAngle": 0,
"gimbalYawRotateEnable": 0,
"gimbalYawRotateAngle": 0,
"gimbalRotateTimeEnable": 0,
"gimbalRotateTime": 10,
"payloadPositionIndex": 0
}
},
{
"actionId": 2,
"actionActuatorFunc": "startTimeLapse",
"actionActuatorFuncParam": {
"payloadPositionIndex": 0,
"useGlobalPayloadLensIndex": 0,
"payloadLensIndex": "visable",
"minShootInterval": spaceTime
}
}
]
},
],
"waypointGimbalHeadingParam": {
"waypointGimbalPitchAngle": 0,
"waypointGimbalYawAngle": 0
},
"isRisky": 0,
"waypointWorkType": 0
}
}else if(index == airPoints.length -3){
point = {
"Point": {
"coordinates":"\n"+item.lng+","+item.lat+"\n"
},
"index": item.id,
"executeHeight": this.templateKmlConfig.Folder.Placemark.height,
"waypointSpeed": this.templateKmlConfig.Folder.autoFlightSpeed,
"waypointHeadingParam": {
"waypointHeadingMode": "followWayline",
"waypointHeadingAngle": -90.9999957673264,
"waypointPoiPoint": "0.000000,0.000000,0.000000",
"waypointHeadingAngleEnable": 1,
"waypointHeadingPathMode": "followBadArc",
"waypointHeadingPoiIndex": 0
},
"waypointTurnParam": {
"waypointTurnMode": "toPointAndStopWithDiscontinuityCurvature",
"waypointTurnDampingDist": 0
},
"useStraightLine": 1,
"actionGroup": {
"actionGroupId": 2,
"actionGroupStartIndex": item.id,
"actionGroupEndIndex": item.id,
"actionGroupMode": "sequence",
"actionTrigger": {
"actionTriggerType": "reachPoint"
},
"action": [
{
"actionId": 0,
"actionActuatorFunc": "stopTimeLapse",
"actionActuatorFuncParam": {
"payloadPositionIndex": 0,
"payloadLensIndex": "visable"
}
},
{
"actionId": 1,
"actionActuatorFunc": "gimbalAngleUnlock"
}
]
},
"waypointGimbalHeadingParam": {
"waypointGimbalPitchAngle": 0,
"waypointGimbalYawAngle": 0
},
"isRisky": 0,
"waypointWorkType": 0
}
}else{ // 处理中间航点
point = {
"Point": {
"coordinates":"\n"+item.lng+","+item.lat+"\n"
},
"index": item.id,
"executeHeight": this.templateKmlConfig.Folder.Placemark.height,
"waypointSpeed": this.templateKmlConfig.Folder.autoFlightSpeed,
"waypointHeadingParam": {
"waypointHeadingMode": "followWayline",
"waypointHeadingAngle": -96.9993404112147,
"waypointPoiPoint": "0.000000,0.000000,0.000000",
"waypointHeadingAngleEnable": 1,
"waypointHeadingPathMode": "followBadArc",
"waypointHeadingPoiIndex": 0
},
"waypointTurnParam": {
"waypointTurnMode": "coordinateTurn",
"waypointTurnDampingDist": 10
},
"useStraightLine": 1,
"waypointGimbalHeadingParam": {
"waypointGimbalPitchAngle": 0,
"waypointGimbalYawAngle": 0
},
"isRisky": 0,
"waypointWorkType": 0
}
}
this.waylineWpmlConfig.Folder.Placemark.push(point);
})
return await this.generateKmzFile();
}
/**
* 生成kmz航线文件
*/
async generateKmzFile(){
// 将template中的 missionConfig 赋值 给wayline
this.waylineWpmlConfig.missionConfig = JSON.parse(JSON.stringify(this.templateKmlConfig.missionConfig))
const builder = new XMLBuilder({
format: true, // 启用换行和缩进
indentBy: " ", // 缩进字符默认2空格可自定义为 \t 等)
suppressEmptyNode: true, // 可选:是否忽略空节点
});
// 带wpml前缀的 template json数据
let templateJson = {kml:{Document:this.templateKmlConfig}}
let templateWpmlJson = this.handlerPrefixWpml(templateJson);
let templateXmlStr = builder.build(templateWpmlJson);
let templateXmlStrTemp = templateXmlStr.replace(/<\/?\d+>/g, "")
let templateXml = templateXmlStrTemp.replace("<kml>",`<?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.6">`)
let waylineJosn = {kml:{Document:this.waylineWpmlConfig}}
let waylienWpmlJson = this.handlerPrefixWpml(waylineJosn);
let waylineXmlStr = builder.build(waylienWpmlJson);
let waylineXmlStrTemp = waylineXmlStr.replace(/<\/?\d+>/g, "")
let waylineXml = waylineXmlStrTemp.replace("<kml>",`<?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.6">`)
// 创建压缩文件
return await this.handlerCreateFile(templateXml,waylineXml);
}
/**
* 处理标签前缀
*/
handlerPrefixWpml(obj){
for (const key in obj) {
if (typeof obj[key] === 'object' && obj[key] !== null && !Array.isArray(obj[key])) { // 如果是对象
this.handlerPrefixWpml(obj[key]); // 递归处理嵌套对象
const newAttrs = {};
for (const attrName in obj[key] ) {
// 检查属性名是否首字母小写
if (/^[a-z]/.test(attrName) && attrName != 'outerBoundaryIs' && attrName != 'coordinates') {
newAttrs[`wpml:${attrName}`] = obj[key][attrName];
} else {
newAttrs[attrName] = obj[key][attrName];
}
}
obj[key] = newAttrs;
}else if(typeof obj[key] === 'object' && obj[key] !== null && Array.isArray(obj[key])){ // 如果是数组
this.handlerPrefixWpml(obj[key]); // 递归处理嵌套对象
const newAttrs = [];
for (const attrName in obj[key]) {
// 检查属性名是否首字母小写
if (/^[a-z]/.test(attrName)) {
newAttrs[`wpml:${attrName}`] = obj[key][attrName];
} else {
newAttrs[attrName] = obj[key][attrName];
}
}
obj[key] = newAttrs;
}
}
return obj;
}
/**
* 文件压缩
*/
async handlerCreateFile(templateXml,waylineXml){
const blob = await this.convertXmlToKmz(templateXml,waylineXml);
return blob;
}
/**
* xml文件转换为 kml、wpml文件
*/
async convertXmlToKmz(templateXml,waylineXml){
const zip = new JSZip();
// 1. 创建 "wmpz" 文件夹
const wmpzFolder = zip.folder("wpmz");
// 2. 向文件夹中添加文件
wmpzFolder.file("waylines.wpml", waylineXml);
wmpzFolder.file("template.kml", templateXml);
// 3. 生成 KMZ (ZIP) 文件
const kmzBlob = await zip.generateAsync({ type: "blob" });
// 下载航线文件
saveAs(kmzBlob, "output.kmz");
return kmzBlob;
}
}