import * as Cesium from 'cesium' import { analyzeKmzFile, removeTextKey, XMLToJSON } from '@/utils/cesium/kmz' import { camelToSnake } from '@/utils/util' import _, { cloneDeep, throttle } from 'lodash' import * as turf from '@turf/turf' /** * 判断action里面是否有key * @param action * @param key * @returns {{hasKey: boolean, val: *}|{hasKey: boolean, val: null}} */ export function actionHasKey (action, key) { const curActionParams = action?.action_actuator_func_param const val = curActionParams?.[key] if (val !== undefined) { return { hasKey: true, val } } else { return { hasKey: false, val: null } } } // 解析kmz文件的时候处理pointList 写在这里 export function handlePointListForKmz ({ placemark, startPoint, execute_height_mode, auto_flight_speed }) { if (!placemark?.length) return [] const isWGS84 = execute_height_mode === 'WGS84' const list = placemark.map(item => { const [longitude, latitude] = item.point.coordinates.trim().split(',').map(i => _.round(i, 6)) const [latitude1, longitude1] = (item?.waypoint_heading_param?.waypoint_poi_point?.trim()?.split(',') || []) .map(i => _.round(i, 6)) let action_modes = item?.action_group?.action || [] action_modes = Array.isArray(action_modes) ? action_modes : [action_modes] return { longitude, latitude, height: _.round(item.execute_height,2), waypoint_speed: item.waypoint_speed, waypoint_poi_point: longitude1 ? { longitude: longitude1, latitude: latitude1 } : undefined,//兴趣点 action_modes, } }) const pointStart = { ...startPoint, flyRotateYaw: 0, pointType: 'start', waypoint_speed: auto_flight_speed, fov: 19.5, // 这个是椎体的展示截面大小 } list.forEach(item => { item?.action_modes?.forEach(item1 => { let { hasKey: has_focal_length, val: focal_length } = actionHasKey(item1, 'focal_length') // 处理focalLength需要/24 focalLength可能是‘1,024’ if (has_focal_length && focal_length) { focal_length = typeof focal_length === 'string' ? focal_length.replace(/,/g, '') : focal_length item1.action_actuator_func_param.focal_length = Number(focal_length) / 24 } }) }) return [pointStart, ...list] } export async function analysisPointLineKmz (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 { mission_config: { take_off_ref_point, drone_info: { drone_enum_value, drone_sub_enum_value } = {} } = {}, folder: { payload_param: { image_format } = {}, placemark: { polygon, margin: buffer_distance_meters = 0 }, wayline_coordinate_sys_param:{height_mode} = {}, global_height, auto_flight_speed, template_type: templateType } = {}, } = templateXMLObj 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 { mission_config: { take_off_security_height } = {}, folder: polygonPointFolder } = waylinesXMLObj let execute_height_mode = '', pointPlacemark if (templateType === "mapping3d") { execute_height_mode = polygonPointFolder[0].execute_height_mode pointPlacemark = polygonPointFolder.map(i => i.placemark) } else { execute_height_mode = polygonPointFolder.execute_height_mode pointPlacemark = polygonPointFolder.placemark } // 取出点位 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() const templatePlacemark = templateXMLObj.folder.placemark // 点航线list let pointList = handlePointListForKmz({ placemark: polygonPointFolder.placemark, startPoint, execute_height_mode, auto_flight_speed }).map((i,index)=> { // 注入是否使用全局高度参数 return { ...i, use_global_height: index > 0 ? templatePlacemark[index-1]?.use_global_height : 0 } }) return { image_format, startPoint, global_height, auto_flight_speed, take_off_ref_point, drone_enum_value, drone_sub_enum_value, take_off_security_height,//起飞安全高度 execute_height_mode,//执行高度模式 height_mode,//高度模式 pointList,//航点航线 点list templateType, pointPlacemark, polygonList, buffer_distance_meters } } // 获取连接地面线 export function getPolyLine (viewer, pointList, index) { return { positions: new Cesium.CallbackProperty(() => { const point = pointList.value[index] const pointPosition = Cesium.Cartesian3.fromDegrees(point.longitude, point.latitude, point.height) if (!pointPosition) return [] // 获取点的位置 const cartographic = Cesium.Cartographic.fromCartesian(pointPosition) // 获取地形高度 const terrainHeight = viewer.scene.globe.getHeight(cartographic) || 0 // 创建地面点位置 const groundPosition = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, terrainHeight) return [pointPosition, groundPosition] }, false), width: 0.5, material: Cesium.Color.WHITE, } } 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] }