import * as Cesium from 'cesium' import takeoffImg from '@/assets/images/routePlan/pointAirLine/takeoff.svg' import _, { cloneDeep, throttle } from 'lodash' import { cartesian3Convert } from '@/utils/cesium/mapUtil' import * as turf from '@turf/turf' import { ElMessage } from 'element-plus' import { analyzeKmzFile, removeTextKey, XMLToJSON } from '@/utils/cesium/kmz' import { camelToSnake } from '@/utils/util' import { boxTransformScale } from '@/utils/turfFunc' function _getMouseInfo (position, viewer) { let scene = viewer.scene let target = scene.pick(position) let cartesian = undefined let surfaceCartesian = undefined let wgs84Position = undefined let wgs84SurfacePosition = undefined if (scene.pickPositionSupported) { cartesian = scene.pickPosition(position) } if (cartesian) { let c = Cesium.Ellipsoid.WGS84.cartesianToCartographic(cartesian) if (c) { wgs84Position = { lng: Cesium.Math.toDegrees(c.longitude), lat: Cesium.Math.toDegrees(c.latitude), alt: c.height, } } } if (scene.mode === Cesium.SceneMode.SCENE3D && !(viewer.terrainProvider instanceof Cesium.EllipsoidTerrainProvider)) { let ray = scene.camera.getPickRay(position) surfaceCartesian = scene.globe.pick(ray, scene) } else { surfaceCartesian = scene.camera.pickEllipsoid(position, Cesium.Ellipsoid.WGS84) } if (surfaceCartesian) { let c = Cesium.Ellipsoid.WGS84.cartesianToCartographic(surfaceCartesian) if (c) { wgs84SurfacePosition = { lng: Cesium.Math.toDegrees(c.longitude), lat: Cesium.Math.toDegrees(c.latitude), alt: c.height, } } } return { target: target, windowPosition: position, position: cartesian, wgs84Position: wgs84Position, surfacePosition: surfaceCartesian, wgs84SurfacePosition: wgs84SurfacePosition, } } let startPointEntity = null // 生成起飞点 function generateStartPoint (movement, viewer) { // 1. 获取笛卡尔坐标 const cartesian = viewer.scene.pickPosition(movement.endPosition) if (!cartesian) return // 2. 笛卡尔转为弧度 const cartographic = Cesium.Cartographic.fromCartesian(cartesian) // 3. 精确获取地形高度(异步) Cesium.sampleTerrainMostDetailed(viewer.terrainProvider, [cartographic]) .then(updatedPositions => { const terrainHeight = updatedPositions[0].height const position = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, terrainHeight) // 4. 更新或创建点实体 if (startPointEntity) { startPointEntity.position = position } else { startPointEntity = viewer.entities.add({ position, id: 'wayline-point-start-init', billboard: { image: takeoffImg, outlineWidth: 0, width: 36, height: 36, scale: 1.0, }, }) } }) .catch(error => console.error("地形加载失败:", error)) } export const createStartThrottle = throttle(generateStartPoint, 20) // 获取起飞点位置 export function getStartPointLast (viewer) { const point = cartesian3Convert(startPointEntity.position.getValue(), viewer) //经纬度 startPointEntity && viewer.entities.remove(startPointEntity) return point } export function removeStartPoint (viewer) { if (startPointEntity) { viewer.entities.remove(startPointEntity) startPointEntity = null } } // 检查位置是否在合理范围内 export function isValidPosition (cartographic) { // 检查经纬度是否在合理范围内 return ( cartographic.longitude >= -Math.PI && cartographic.longitude <= Math.PI && cartographic.latitude >= -Math.PI / 2 && cartographic.latitude <= Math.PI / 2 ) } export class PolygonDrawer { /** * @param {Function} updatePosition - Position update callback function * @param {Object} idShowWaringTip - Warning tip visibility flag */ constructor(updatePosition, idShowWaringTip) { // Initialize properties this.viewer = null this.curPolygon = null this.drawingMode = false this.settingMode = false this.isDragging = false this.draggedEntity = null this.polygonEntity = null this.editPolygonPointDataSource = null this.handler = null this.updatePosition = updatePosition this.menuPopup = null this.delPolygonPoint = null this.idShowWaringTip = idShowWaringTip this.currentDragPointIsValid = false this.currentDragPointPosition = null // Bind methods to maintain context this.handleLeftDown = this.handleLeftDown.bind(this) this.handleLeftUp = this.handleLeftUp.bind(this) this.handleMouseMove = this.handleMouseMove.bind(this) this.handleLeftClick = this.handleLeftClick.bind(this) this.handleRightClick = this.handleRightClick.bind(this) this.delPolygon = this.delPolygon.bind(this) this.delPoint = this.delPoint.bind(this) } // Constants for entity names and IDs static ENTITY_NAMES = { POLYGON: '面状航线-面', POINT: '面状航线-端点', POLYGON_ID: 'planar-route-polygon', POINT_ID_PREFIX: 'planar-route-point-' }; // Constants for colors static COLORS = { DEFAULT_POLYGON: Cesium.Color.fromBytes(45, 140, 240, 99), DEFAULT_LINE: Cesium.Color.fromBytes(45, 140, 240, 255), ERROR_POLYGON: Cesium.Color.fromCssColorString('rgba(255, 0, 0, .3)'), ERROR_LINE: Cesium.Color.fromCssColorString('rgba(255, 0, 0, 1)') }; /** * Initialize polygon with existing positions * @param {Cesium.Viewer} viewer - Cesium viewer instance * @param {Array} positions - Array of position objects {lng, lat, height} */ initPolygon (viewer, positions) { this.initHandler(viewer) this.startDrawing() positions.forEach(item => { this.addPosition( Cesium.Cartesian3.fromDegrees(Number(item.lng), Number(item.lat), Number(item.height)), false ) }) const newBox = boxTransformScale(positions.map(item => [item.lng, item.lat]), 5) viewer.camera.flyTo({ destination: Cesium.Rectangle.fromDegrees(...newBox), offset: new Cesium.HeadingPitchRange(0, Cesium.Math.toRadians(-90), 0), duration: 0.5, }) this.drawingMode = false this.settingMode = true } /** * Start drawing a new polygon */ startDrawing () { this.drawingMode = true this.curPolygon = new Cesium.PolygonHierarchy() if (!this.editPolygonPointDataSource) { this.editPolygonPointDataSource = new Cesium.CustomDataSource('editPolygonPointDataSource') this.viewer?.dataSources.add(this.editPolygonPointDataSource) } this.editPolygonPointDataSource?.entities.removeAll() } /** * Add a position to the current polygon * @param {Cesium.Cartesian3} position - Position to add * @param {Boolean} isAdd - Whether this is an additional point (vs initial point) */ addPosition (position, isAdd = true) { if (this.curPolygon.positions.length === 0 && isAdd) { this.curPolygon.positions.push(position.clone()) } this.curPolygon.positions.push(position.clone()) if (!this.polygonEntity) { this.createPolygonEntity() } this.createPointEntity(position, isAdd) } /** * Create the main polygon entity */ createPolygonEntity () { this.polygonEntity = this.viewer.entities.add({ name: PolygonDrawer.ENTITY_NAMES.POLYGON, id: PolygonDrawer.ENTITY_NAMES.POLYGON_ID, polygon: { hierarchy: new Cesium.CallbackProperty(() => this.curPolygon, false), material: PolygonDrawer.COLORS.DEFAULT_POLYGON, outline: false, outlineWidth: 2, heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, }, polyline: { width: 2, material: PolygonDrawer.COLORS.DEFAULT_LINE, clampToGround: true, positions: new Cesium.CallbackProperty( () => [...this.curPolygon.positions, this.curPolygon.positions[0]], false ) }, }) } /** * Create a point entity for the polygon * @param {Cesium.Cartesian3} position - Position of the point * @param {Boolean} isAdd - Whether this is an additional point */ createPointEntity (position, isAdd) { const pointIndex = isAdd ? this.curPolygon.positions.length - 2 : this.curPolygon.positions.length - 1 this.editPolygonPointDataSource.entities.add({ name: PolygonDrawer.ENTITY_NAMES.POINT, id: `${PolygonDrawer.ENTITY_NAMES.POINT_ID_PREFIX}${pointIndex}`, position: position.clone(), point: { pixelSize: 14, color: Cesium.Color.WHITE, heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, disableDepthTestDistance: Number.POSITIVE_INFINITY, }, customData: { ind: pointIndex, }, }) } /** * Finish drawing the polygon */ finishDrawing () { this.curPolygon.positions.pop() if (this.curPolygon.positions.length >= 3) { this.drawingMode = false this.settingMode = true this.editPolygonPointDataSource.entities.show = true if (!this.curDragPointIsValid(this.curPolygon.positions)) { this.idShowWaringTip.value = true this.currentDragPointIsValid = true this.updatePolygonAppearance(PolygonDrawer.COLORS.ERROR_POLYGON, PolygonDrawer.COLORS.ERROR_LINE) } else { this.idShowWaringTip.value = false this.currentDragPointIsValid = false this.updatePolygonAppearance(PolygonDrawer.COLORS.DEFAULT_POLYGON, PolygonDrawer.COLORS.DEFAULT_LINE) } this.updatePosition(this.curPolygon.positions) } } /** * Delete the current polygon */ delPolygon () { this.removeEntities() this.removeMenuPopup() this.updatePosition([]) this.startDrawing() } /** * Delete a point from the polygon */ delPoint () { if (this.curPolygon.positions.length <= 3) { this.removeMenuPopup() return ElMessage.warning('端点不可少于3个') } if (!this.delPolygonPoint) return this.curPolygon.positions.splice(this.delPolygonPoint.customData.ind, 1) this.editPolygonPointDataSource.entities.remove(this.delPolygonPoint) this.removeMenuPopup() // Update indices of remaining points this.editPolygonPointDataSource.entities.values.forEach((item, index) => { item.customData.ind = index }) this.updatePosition(this.curPolygon.positions) } /** * Create a context menu popup * @param {String} type - Type of menu ('polygon' or 'edit-point') * @returns {HTMLElement} The created menu element */ createMenuPopup (type = 'polygon') { const menuPopupVBox = document.createElement('div') menuPopupVBox.id = 'planarPolygonEdit' menuPopupVBox.className = 'planar-polygon-edit-tooltip' const menuPopup = document.createElement('div') menuPopup.id = 'planarPolygonEditMenu' menuPopup.className = 'planar-polygon-edit-menu' const menuItems = type === 'polygon' ? [{ title: '删除测区', class: 'del-planar-polygon' }] : [{ title: '删除端点', class: 'del-planar-point' }] menuItems.forEach(item => { const titleDiv = document.createElement('div') titleDiv.innerText = item.title titleDiv.className = item.class menuPopup.appendChild(titleDiv) }) menuPopupVBox.appendChild(menuPopup) return menuPopupVBox } /** * Remove the context menu popup */ removeMenuPopup () { if (this.menuPopup) { this.menuPopup.removeEventListener('click', this.delPolygon) this.menuPopup.removeEventListener('click', this.delPoint) this.viewer.container.removeChild(this.menuPopup) this.menuPopup = null } this.delPolygonPoint = null } /** * Handle left mouse button down event * @param {Object} movement - Mouse movement event object */ handleLeftDown (movement) { if (!this.settingMode) return const pickedEntity = this.viewer.scene.pick(movement.position)?.id const isPoint = pickedEntity?.name === PolygonDrawer.ENTITY_NAMES.POINT if (pickedEntity && isPoint) { this.isDragging = true this.draggedEntity = pickedEntity this.currentDragPointPosition = this.curPolygon.positions[this.draggedEntity?.customData.ind] this.disableMapControl() } } /** * Handle left mouse button up event */ handleLeftUp () { if (!(this.settingMode && this.curPolygon?.positions && this.draggedEntity)) return if (this.currentDragPointIsValid && this.isDragging) { this.draggedEntity.position = this.currentDragPointPosition this.curPolygon.positions[this.draggedEntity?.customData.ind] = this.currentDragPointPosition if (!this.curDragPointIsValid(this.curPolygon.positions)) { this.idShowWaringTip.value = true this.currentDragPointIsValid = true this.updatePolygonAppearance(PolygonDrawer.COLORS.ERROR_POLYGON, PolygonDrawer.COLORS.ERROR_LINE) } else { this.idShowWaringTip.value = false this.currentDragPointIsValid = false this.updatePolygonAppearance(PolygonDrawer.COLORS.DEFAULT_POLYGON, PolygonDrawer.COLORS.DEFAULT_LINE) } } if (this.isDragging) { this.updatePosition(this.curPolygon.positions) this.isDragging = false this.draggedEntity = null this.enableMapControl() } } /** * Update polygon appearance * @param {Cesium.Color} polygonColor - Color for the polygon * @param {Cesium.Color} lineColor - Color for the outline */ updatePolygonAppearance (polygonColor, lineColor) { this.polygonEntity.polygon.material = polygonColor this.polygonEntity.polyline.material = lineColor } /** * Handle left mouse click event * @param {Object} click - Click event object */ handleLeftClick (click) { this.removeMenuPopup() const pickedAllEntity = this.viewer.scene.drillPick(click.position).filter(i => i.id) const isStartPoint = pickedAllEntity.find(i => i.id.name === '起飞点') const isPolygonPoint = pickedAllEntity.find(i => i.id.name === PolygonDrawer.ENTITY_NAMES.POINT) const isPolygon = pickedAllEntity.find(i => i.id.name === PolygonDrawer.ENTITY_NAMES.POLYGON) if (isStartPoint) return if (!this.drawingMode) { if (!isPolygon) { this.settingMode = false this.editPolygonPointDataSource.entities.show = false return } if (isPolygon) { this.settingMode = true this.editPolygonPointDataSource.entities.show = true } return } if (this.curPolygon.positions.length < 4 && isPolygonPoint) { return } if (this.curPolygon.positions.length >= 4 && isPolygonPoint) { if (!this.drawingMode) return this.finishDrawing() return } const cartesian = this.viewer.scene.pickPosition(click.position) if (!cartesian) return this.addPosition(cartesian) } /** * Handle right mouse click event * @param {Object} click - Click event object */ handleRightClick (click) { if (this.drawingMode) return this.removeMenuPopup() const pickedAllEntity = this.viewer.scene.drillPick(click.position).filter(i => i.id) const isPolygon = pickedAllEntity.find(i => i.id.name === PolygonDrawer.ENTITY_NAMES.POLYGON) const isEditPoint = pickedAllEntity.find(i => i.id.name === PolygonDrawer.ENTITY_NAMES.POINT) const { position: { x, y } } = click let pickedEntity, tooltipEvent, menuType if (isPolygon) { pickedEntity = isPolygon tooltipEvent = this.delPolygon menuType = 'polygon' } else if (isEditPoint) { pickedEntity = isEditPoint tooltipEvent = this.delPoint menuType = 'edit-point' } if (pickedEntity) { this.delPolygonPoint = pickedEntity.id this.menuPopup = this.createMenuPopup(menuType) this.menuPopup.style.transform = `translate3d(${x - 10}px, ${y - 10}px, 0)` this.viewer.container.appendChild(this.menuPopup) this.menuPopup.addEventListener('click', tooltipEvent) } } /** * Handle mouse move event * @param {Object} movement - Mouse movement event object */ handleMouseMove (movement) { if (!this.drawingMode && !this.settingMode) return const cartesian = this.viewer.scene.pickPosition(movement.endPosition) if (!cartesian) return if (this.settingMode && this.draggedEntity?.customData) { this.draggedEntity.position = cartesian this.curPolygon.positions[this.draggedEntity?.customData.ind] = cartesian } if (this.drawingMode && this.polygonEntity && this.curPolygon.positions.length >= 1) { this.curPolygon.positions.pop() this.curPolygon.positions.push(cartesian) } if ((this.settingMode && this.draggedEntity?.customData) || (this.drawingMode && this.polygonEntity && this.curPolygon.positions.length >= 3)) { if (!this.curDragPointIsValid(this.curPolygon.positions)) { this.idShowWaringTip.value = true this.currentDragPointIsValid = true this.updatePolygonAppearance(PolygonDrawer.COLORS.ERROR_POLYGON, PolygonDrawer.COLORS.ERROR_LINE) } else { this.idShowWaringTip.value = false this.currentDragPointIsValid = false this.updatePolygonAppearance(PolygonDrawer.COLORS.DEFAULT_POLYGON, PolygonDrawer.COLORS.DEFAULT_LINE) } } } /** * Check if the current dragged point position is valid * @param {Array} positions - Array of polygon positions * @returns {Boolean} True if the polygon is valid (no self-intersections) */ curDragPointIsValid (positions) { if (positions.length < 3) return true const cartographics = Cesium.Ellipsoid.WGS84.cartesianArrayToCartographicArray(positions) const latLngPoints = cartographics.map(cartographic => [ Cesium.Math.toDegrees(cartographic.longitude), Cesium.Math.toDegrees(cartographic.latitude) ]) const poly = turf.polygon([[...latLngPoints, latLngPoints[0]]]) const intersections = turf.kinks(poly) return intersections.features.length === 0 } /** * Disable map controls during interaction */ disableMapControl () { const controller = this.viewer.scene.screenSpaceCameraController controller.enableRotate = false controller.enableTranslate = false controller.enableZoom = false } /** * Enable map controls after interaction */ enableMapControl () { const controller = this.viewer.scene.screenSpaceCameraController controller.enableRotate = true controller.enableTranslate = true controller.enableZoom = true } /** * Remove all entities */ removeEntities () { // Remove main polygon entities const entitiesIDs = this.viewer.entities.values.map(i => i.id) entitiesIDs.forEach(item => { if (item.includes('planar-route-')) { this.viewer.entities.removeById(item) } }) this.settingMode = false this.polygonEntity = null this.curPolygon = null // Remove edit points if (this.editPolygonPointDataSource) { this.editPolygonPointDataSource.entities.removeAll() this.editPolygonPointDataSource = null } } /** * Initialize event handlers * @param {Cesium.Viewer} viewer - Cesium viewer instance */ initHandler (viewer) { this.viewer = viewer this.startDrawing() if (!this.handler) { this.handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas) // Set up event handlers const events = [ [Cesium.ScreenSpaceEventType.LEFT_DOWN, this.handleLeftDown], [Cesium.ScreenSpaceEventType.LEFT_UP, this.handleLeftUp], [Cesium.ScreenSpaceEventType.MOUSE_MOVE, this.handleMouseMove], [Cesium.ScreenSpaceEventType.LEFT_CLICK, this.handleLeftClick], [Cesium.ScreenSpaceEventType.RIGHT_CLICK, this.handleRightClick] ] events.forEach(([type, handler]) => { this.handler.setInputAction(handler, type) }) } } /** * Remove event handlers */ removeHandler () { if (this.handler) { const eventTypes = [ Cesium.ScreenSpaceEventType.LEFT_DOWN, Cesium.ScreenSpaceEventType.LEFT_UP, Cesium.ScreenSpaceEventType.MOUSE_MOVE, Cesium.ScreenSpaceEventType.LEFT_CLICK, Cesium.ScreenSpaceEventType.RIGHT_CLICK ] eventTypes.forEach(type => { this.handler.removeInputAction(type) }) this.handler = null } } /** * Clean up and destroy the instance */ destroy () { if (!this.viewer) return this.removeMenuPopup() this.removeEntities() this.removeHandler() this.enableMapControl() } } export function disposeData (curPolygonPosition, polylinePoints, rthAltitudePoint) { let data = [...curPolygonPosition] data.push(curPolygonPosition[0]) let disposePolylinePoints = [...polylinePoints] if (polylinePoints.length === 1) { ElMessage.warning('当前高度过高,无法生成有效航线,请调整!') disposePolylinePoints = [...polylinePoints, ...polylinePoints] } const polygon = turf.polygon([data.map(item => [item.lng, item.lat])]) const polygonArea = turf.area(polygon) var line = turf.lineString(disposePolylinePoints.map(item => [item.longitude, item.latitude])) var length = turf.length(line, { units: 'kilometers' }) const newPolylinePoints = disposePolylinePoints.map((item, index) => { return Cesium.Cartesian3.fromDegrees(Number(item.longitude), Number(item.latitude), Number(item.height)) }) let polylineLength = 0 newPolylinePoints.forEach((item, index) => { if (index == newPolylinePoints.length - 1) return let point1 = item let point2 = newPolylinePoints[index + 1] polylineLength += Cesium.Cartesian3.distance(point1, point2) }) const newRthAltitudePoint = rthAltitudePoint.map((item, index) => { return Cesium.Cartesian3.fromDegrees(Number(item.longitude), Number(item.latitude), Number(item.height)) }) let rthLineLength = 0 newRthAltitudePoint.forEach((item, index) => { if (index == newRthAltitudePoint.length - 1) return let point1 = item let point2 = newRthAltitudePoint[index + 1] rthLineLength += Cesium.Cartesian3.distance(point1, point2) }) return { polygonArea, polylineLength, rthLineLength, photoNum: polylinePoints.length * 3 } } export const getGsd = (globalSettings, gsdInfo) => { if (_.isEmpty(gsdInfo) || !gsdInfo.image_height) { ElMessage.warning('相机参数获取异常,请联系管理员!') return } let w = gsdW( globalSettings.relTerrainHeight, gsdInfo.sensor_width, gsdInfo.focal_length, gsdInfo.image_width ) let h = gsdH( globalSettings.relTerrainHeight, gsdInfo.sensor_height, gsdInfo.focal_length, gsdInfo.image_height ) return w > h ? w : h } export const getGsdByH = (globalSettings, gsdInfo) => { if (!gsdInfo && !gsdInfo.image_height) { ElMessage.warning('相机参数获取异常,请联系管理员!') return } let w = gsdW( globalSettings.relTerrainHeight, gsdInfo.sensor_width, gsdInfo.focal_length, gsdInfo.image_width ) let h = gsdH( globalSettings.relTerrainHeight, gsdInfo.sensor_height, gsdInfo.focal_length, gsdInfo.image_height ) if (w > h) { return getHbyHW( globalSettings.gsd, gsdInfo.sensor_width, gsdInfo.focal_length, gsdInfo.image_width ) } else { return getHbyH( globalSettings.gsd, gsdInfo.sensor_height, gsdInfo.focal_length, gsdInfo.image_height ) } } // 解析kmz文件的时候处理pointList 写在这里 export function handlePointListForKmz (placemark, templateType) { if (!placemark?.length) return [] let list = [] if (templateType === "mapping2d") { list = placemark.map(item => { const [longitude, latitude] = item.point.coordinates.trim().split(',') return { longitude: longitude, latitude: latitude, height: 0, speed: item.waypoint_speed } }) } else { list = placemark.map(i => i.map(item => { const [longitude, latitude] = item.point.coordinates.trim().split(',') return { longitude: longitude, latitude: latitude, height: 0, speed: item.waypoint_speed } })) } return list } export async function analysisPlanarRouteKmz (kmzUrl) { const res = await analyzeKmzFile(`${kmzUrl}?_t=${new Date().getTime()}`) const templateXML = await res.fileInfoObj['wpmz/template.kml'] const waylinesXML = await res.fileInfoObj['wpmz/waylines.wpml'] const templateXMLJSON = XMLToJSON(templateXML)?.['Document'] const waylinesXMLJSON = XMLToJSON(waylinesXML)?.['Document'] const templateXMLObj = camelToSnake(removeTextKey(templateXMLJSON)) const waylinesXMLObj = camelToSnake(removeTextKey(waylinesXMLJSON)) const { folder: { auto_flight_speed, payload_param: { image_format } = {}, placemark: { direction: waylineAngle, inclined_gimbal_pitch: inclined_gimbal_pitch = -45, overlap: { inclined_camera_overlap_h: inclined_camera_overlap_h, inclined_camera_overlap_w: inclined_camera_overlap_w, ortho_camera_overlap_w: side_ratio, ortho_camera_overlap_h: course_ratio, }, polygon, margin: buffer_distance_meters = 0 }, template_type: templateType, wayline_coordinate_sys_param: { global_shoot_height } } = {}, mission_config: { take_off_ref_point, // 参考起飞点 drone_info: { drone_enum_value, drone_sub_enum_value } = {}, payload_info: { payload_position_index, payload_enum_value, payload_sub_enum_value } } = {}, } = templateXMLObj const { mission_config: { // 安全起飞高 take_off_security_height: rth_altitude } = {}, folder: polygonPointFolder } = waylinesXMLObj let execute_height_mode = '' let pointPlacemark if (templateType === "mapping2d") { execute_height_mode = polygonPointFolder.execute_height_mode pointPlacemark = polygonPointFolder.placemark } else { execute_height_mode = polygonPointFolder[0].execute_height_mode pointPlacemark = polygonPointFolder.map(i => i.placemark) } const [latitude, longitude, height] = take_off_ref_point.split(',').map(item => _.round(item, 6)) let startPoint = { latitude, longitude, height: Number.isNaN(height) ? 0 : height } // 取出点位 const coordinates = polygon?.outer_boundary_is.linear_ring .coordinates?.split('\n') || [] // 数组转换 let polygonList = coordinates.map((coordinate) => coordinate .replace(/\s+/g, '') .split(',') .map((v) => Number(v)), ) polygonList.pop() let pointList = handlePointListForKmz(pointPlacemark, templateType) return { take_off_ref_point, startPoint, image_format, templateType, global_shoot_height, rth_altitude, auto_flight_speed, waylineAngle, side_ratio, course_ratio, inclined_camera_overlap_h, inclined_camera_overlap_w, inclined_gimbal_pitch, drone_enum_value, drone_sub_enum_value, payload_position_index, payload_enum_value, payload_sub_enum_value, execute_height_mode, pointList, polygonList, buffer_distance_meters } } // 计算gsd-H function gsdH (height, ch, jj, ih) { let one = Number((height * ch).toFixed(2)) let two = Number((jj * ih).toFixed(2)) let three = Number((one / two).toFixed(5)) let four = Number((three * 100).toFixed(2)) return four } function gsdW (height, cw, jj, iw) { let one = Number((height * cw).toFixed(2)) let two = Number((jj * iw).toFixed(2)) let three = Number((one / two).toFixed(5)) let four = Number((three * 100).toFixed(2)) return four } // 计算gsd-H function getHbyH (gsd, ch, jj, ih) { let one = Number((jj * ih).toFixed(2)) let two = Number((gsd / 100).toFixed(4)) let three = Number((two * one).toFixed(4)) let four = Number((three / ch).toFixed(2)) return four } function getHbyHW (gsd, cw, jj, iw) { let one = Number((jj * iw).toFixed(2)) let two = Number((gsd / 100).toFixed(4)) let three = Number((two * one).toFixed(4)) let four = Number((three / cw).toFixed(2)) return four } export function getNewPolygonData (data) { const polygonData = data.reduce((pre, cur) => { let arr = cur.data.map(i => { if ('point' in i) return i.point.coordinates.split(',') if ('Point' in i) { if (_.isObject(i.Point.coordinates) && '#text' in i.Point.coordinates) return i.Point.coordinates['#text'].split(',') return i.Point.coordinates.split(',') } }).map(i => turf.point([Number(i[0]), Number(i[1])])) return pre.push(...arr), pre }, []) const hull = turf.convex(turf.featureCollection(polygonData)) return hull.geometry.coordinates[0] } export function getApiNewPolygonData (data) { const polygonData = data.reduce((pre, cur) => { let arr = cur.data.map(i => turf.point([Number(i.x), Number(i.y)])) return pre.push(...arr), pre }, []) const hull = turf.convex(turf.featureCollection(polygonData)) return hull.geometry.coordinates[0] } export function getBufferPolygonData (data, meters = 0) { const turfPolygonData = data.map(i => [i.lng, i.lat]) const polygon = turf.polygon([[...turfPolygonData, turfPolygonData[0]]]) const buffered = turf.buffer(polygon, meters, { units: 'meters', steps: 16 }) return buffered.geometry.coordinates[0] }