| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <el-button type="primary" @click="showGZ">主要按钮</el-button> |
| | | <el-button type="primary" @click="showGZ">显示视锥体</el-button> |
| | | <input @change="handleKMZUpload" type="file" id="kmzFile" accept=".kmz" class="block w-full text-sm text-gray-500 |
| | | file:mr-4 file:py-2 file:px-4 |
| | | file:rounded-md file:border-0 |
| | |
| | | // roll:0, |
| | | // speed: 10 // 速度(公里/小时) |
| | | // }, |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | // { |
| | | // time: '2025-04-01T13:01:00Z', // ISO 8601格式时间 |
| | | // position: { |
| | |
| | | |
| | | // // 更多点... |
| | | // ], |
| | | trajectoryData:[], |
| | | c3Position:Cesium.Cartesian3.fromDegrees(125.14349012556997, 46.55684464616254,33.157873665937274), |
| | | enableChange:true, |
| | | trajectoryData:[],//数据数组 |
| | | c3Position:Cesium.Cartesian3.fromDegrees(125.04159166971326, 46.63755601510411,33.13806141449017),//初始化位置 |
| | | camera: null, // Cesium Camera 实例 |
| | | frustumOutline: null, // 视锥体 |
| | | heading: 0, // 相机的 heading (朝向) |
| | | pitch: -90, // 相机的 pitch (俯仰) |
| | | heading: -90, // 相机的 heading (朝向) |
| | | pitch: 0, // 相机的 pitch (俯仰) |
| | | roll: 0, // 相机的 roll (滚转) |
| | | aspectRatio: 1.0, // 纵横比 |
| | | color: '#FF0000', // 视锥体颜色 |
| | | id: 'frustumOutline', |
| | | positionProperty : new Cesium.SampledPositionProperty(), |
| | | orientation : new Cesium.SampledProperty(Cesium.Quaternion) |
| | | orientation : new Cesium.SampledProperty(Cesium.Quaternion),//无人机朝向 |
| | | sztOrientation : new Cesium.SampledProperty(Cesium.Quaternion),//云台朝向 |
| | | } |
| | | }, |
| | | mounted() { |
| | | console.log(window.viewer) |
| | | console.log(viewer) |
| | | // this.showGZ() |
| | | }, |
| | | methods: { |
| | | async handleKMZUpload(event) { |
| | | const file = event.target.files[0]; |
| | | if (!file) return; |
| | | |
| | | try { |
| | | const arrayBuffer = await this.readFileAsArrayBuffer(file); |
| | | this.waypoints = await this.parseKMZ(arrayBuffer); |
| | | //加点逻辑 比如向第2-n-1中插入元素 经纬度为当前的 heading pitch roll 下一个的 |
| | | const dealArr = []; |
| | | // console.log(">> this.waypoints:", this.waypoints); |
| | | for (let i = 0; i < this.waypoints.length - 1; i++) { |
| | | dealArr.push(this.waypoints[i]); // Push the current element |
| | | const current = this.waypoints[i]; |
| | | const next = this.waypoints[i + 1]; |
| | | |
| | | // Create a new element with the current lng, lat and next heading, pitch, roll |
| | | dealArr.push({ |
| | | "lng": current.lng, |
| | | "lat": current.lat, |
| | | "alt": current.alt, |
| | | 'flyHeading':next.flyHeading, |
| | | "heading": next.heading, |
| | | "pitch": next.pitch, |
| | | "roll": next.roll |
| | | }); |
| | | } |
| | | |
| | | // Push the last element without any change |
| | | dealArr.push(this.waypoints[this.waypoints.length - 1]); |
| | | |
| | | console.log(dealArr) |
| | | this.waypoints = dealArr |
| | | console.log(">> this.waypoints:", this.waypoints); |
| | | |
| | | this.fileInfo = ` |
| | |
| | | const startDate = new Date("2025-04-01T13:00:00Z"); |
| | | const speeds = [10, 10, 20, 30, 80, 100, 60, 50, 40, 30, 20, 10]; // 自定义速度 |
| | | |
| | | const result = this.waypoints.map((item, index) => { |
| | | // const result = this.waypoints.map((item, index) => { |
| | | console.log(result) |
| | | const result = dealArr.map((item, index) => { |
| | | // const result = this.waypoints.map((item, index) => { |
| | | // 每次加一天 |
| | | const time = new Date(startDate.getTime() + index * 60 * 1000).toISOString(); |
| | | // const time = Cesium.JulianDate.addSeconds(startDate, 3600, new Cesium.JulianDate()); |
| | | return { |
| | | time, |
| | | position: { |
| | |
| | | heading:item.heading|| 0, |
| | | pitch:item.pitch|| 0, |
| | | roll:item.roll || 0, |
| | | speed: speeds[index] || 0 |
| | | speed: speeds[index] || 0, |
| | | // flyHeading:item.flyHeading |
| | | }; |
| | | }); |
| | | this.trajectoryData = result |
| | | console.log(result); |
| | | console.log(this.trajectoryData) |
| | | // console.log(result); |
| | | this.loadTimeLine() |
| | | } catch (error) { |
| | | console.error(error); |
| | |
| | | const kmlFile = Object.keys(zip.files).find(name => |
| | | name.endsWith(".kml") |
| | | ); |
| | | console.log(">> kmlFile:", kmlFile); |
| | | // console.log(">> kmlFile:", kmlFile); |
| | | if (!kmlFile) throw new Error("未找到KML文件"); |
| | | |
| | | const kmlContent = await zip.file(kmlFile).async("text"); |
| | |
| | | // 提取 action 里的参数 |
| | | let heading = null; |
| | | let gimbalPitch = null, gimbalRoll = null, gimbalYaw = null; |
| | | |
| | | // 初始化 Pitch, Roll 和 Heading |
| | | let totalPitch = 0; |
| | | let totalRoll = 0; |
| | | let totalHeading = 0; |
| | | let flyHeadingData = 0; |
| | | if (placemark["wpml:actionGroup"]?.[0]?.["wpml:action"]) { |
| | | placemark["wpml:actionGroup"][0]["wpml:action"].forEach(action => { |
| | | let params = action["wpml:actionActuatorFuncParam"]?.[0]; |
| | | // 处理 gimbalRotate 和 rotateYaw 函数 |
| | | if (action['wpml:actionActuatorFunc'].includes("gimbalRotate")) { |
| | | // 获取每个角度值 |
| | | const gimbalPitch = parseFloat(action['wpml:actionActuatorFuncParam'][0]["wpml:gimbalPitchRotateAngle"][0]); |
| | | const gimbalRoll = parseFloat(action['wpml:actionActuatorFuncParam'][0]["wpml:gimbalRollRotateAngle"][0]); |
| | | const gimbalYaw = parseFloat(action['wpml:actionActuatorFuncParam'][0]["wpml:gimbalYawRotateAngle"][0]); |
| | | |
| | | if (!params) return; |
| | | |
| | | // 飞机航向角 |
| | | if (action["wpml:actionActuatorFunc"]?.[0] === "rotateYaw" && |
| | | params["wpml:aircraftHeading"]) { |
| | | heading = Number(params["wpml:aircraftHeading"][0]); |
| | | // 累加 Pitch, Roll 和 Heading |
| | | totalPitch += gimbalPitch; |
| | | totalRoll += gimbalRoll; |
| | | totalHeading += gimbalYaw; |
| | | console.log('totalHeading里面循环' + totalHeading) |
| | | } |
| | | |
| | | // 云台角度 |
| | | if (action["wpml:actionActuatorFunc"]?.[0] === "gimbalRotate") { |
| | | if (params["wpml:gimbalPitchRotateAngle"]) |
| | | gimbalPitch = Number(params["wpml:gimbalPitchRotateAngle"][0]); |
| | | if (params["wpml:gimbalRollRotateAngle"]) |
| | | gimbalRoll = Number(params["wpml:gimbalRollRotateAngle"][0]); |
| | | if (params["wpml:gimbalYawRotateAngle"]) |
| | | gimbalYaw = Number(params["wpml:gimbalYawRotateAngle"][0]); |
| | | // 处理 rotateYaw 函数 |
| | | if (action['wpml:actionActuatorFunc'].includes("rotateYaw")) { |
| | | // 获取 aircraftHeading |
| | | const aircraftHeading = parseFloat(action['wpml:actionActuatorFuncParam'][0]["wpml:aircraftHeading"][0]); |
| | | console.log(aircraftHeading) |
| | | flyHeadingData = aircraftHeading |
| | | // 将 aircraftHeading 累加到 totalHeading |
| | | totalHeading += aircraftHeading; |
| | | console.log('totalHeading外层外层外层外层外层循环' + totalHeading) |
| | | } |
| | | }); |
| | | } |
| | | // 输出结果 |
| | | console.log("Total Pitch:", totalPitch); |
| | | console.log("Total Roll:", totalRoll); |
| | | console.log("Total Heading:", totalHeading); |
| | | if (coords) { |
| | | coords.trim().split(" ").forEach(coord => { |
| | | const [lng, lat] = coord.split(",").map(Number); |
| | | //,heading:gimbalYaw || 0,pitch:gimbalPitch|| 0,roll:gimbalRoll|| 0 |
| | | points.push({ lng, lat, alt: height,heading:gimbalYaw || 0,pitch:gimbalPitch|| 0,roll:gimbalRoll|| 0 }); |
| | | points.push({ lng, lat, alt: height,heading:totalHeading || 0,pitch:totalPitch || 0,roll:totalRoll|| 0 ,flyHeading:flyHeadingData}); |
| | | }); |
| | | } |
| | | }); |
| | |
| | | showFlightPath() { |
| | | console.log(">> this.waypoints:", this.waypoints); |
| | | if (this.waypoints.length === 0) return alert('请先上传KMZ文件'); |
| | | |
| | | // viewer.entities.removeAll(); |
| | | |
| | | // 转换坐标 |
| | | const positions = this.waypoints.map(wp => |
| | | Cesium.Cartesian3.fromDegrees(wp.lng, wp.lat, wp.alt) |
| | |
| | | //精度维度高度 |
| | | getScopeTower(lon,lat,distance).then(res=>{ |
| | | if(res.code == 200) { |
| | | console.log(res.rows) |
| | | res.rows.forEach((data) => { |
| | | this.createModel(data); |
| | | }); |
| | |
| | | }) |
| | | }, |
| | | createModel(data){ |
| | | console.log(data) |
| | | viewer.entities.add({ |
| | | id: data.id, |
| | | position: Cesium.Cartesian3.fromDegrees(data.longitude, data.latitude, data.altitude), |
| | |
| | | loadTimeLine(){ |
| | | // 设置时间范围 |
| | | const allTimes = this.trajectoryData.map(item => Cesium.JulianDate.fromIso8601(item.time)) |
| | | console.log(allTimes) |
| | | // 获取所有时间,并减去8小时 |
| | | // const allTimes = this.trajectoryData.map(item => { |
| | | // const time = Cesium.JulianDate.fromIso8601(item.time) |
| | | // return Cesium.JulianDate.addHours(time, +8, new Cesium.JulianDate()) |
| | | // }) |
| | | const startTime = allTimes[0] |
| | | const stopTime = allTimes[allTimes.length - 1] |
| | | // const startTime = Cesium.JulianDate.minimum(...allTimes) |
| | |
| | | this.positionProperty.addSample(time, position) |
| | | speedProperty.addSample(time, data.speed) |
| | | // 计算朝向四元数 |
| | | // const hpr = new Cesium.HeadingPitchRoll( |
| | | // Cesium.Math.toRadians(data.flyHeading), |
| | | // Cesium.Math.toRadians(data.pitch), |
| | | // Cesium.Math.toRadians(data.roll) |
| | | // ); |
| | | const hpr = new Cesium.HeadingPitchRoll( |
| | | Cesium.Math.toRadians(0), |
| | | Cesium.Math.toRadians(0), |
| | | Cesium.Math.toRadians(0) |
| | | ); |
| | | const quaternion = Cesium.Transforms.headingPitchRollQuaternion(position, hpr); |
| | | console.log(Cesium.JulianDate.toDate(time)) |
| | | // // 添加飞机朝向采样 |
| | | this.orientation.addSample(time, quaternion); |
| | | //云台 |
| | | const szthpr = new Cesium.HeadingPitchRoll( |
| | | Cesium.Math.toRadians(data.heading), |
| | | Cesium.Math.toRadians(data.pitch), |
| | | Cesium.Math.toRadians(data.roll) |
| | | ); |
| | | const quaternion = Cesium.Transforms.headingPitchRollQuaternion(position, hpr); |
| | | const sztquaternion = Cesium.Transforms.headingPitchRollQuaternion(position, szthpr); |
| | | |
| | | // // 添加朝向采样 |
| | | this.orientation.addSample(data.time, quaternion); |
| | | this.sztOrientation.addSample(time, sztquaternion); |
| | | }) |
| | | console.log(">> positionProperty:",this.positionProperty ); |
| | | // console.log(">> positionProperty:",this.positionProperty ); |
| | | |
| | | let entity = viewer.entities.add({ |
| | | show: true, |
| | | position: this.positionProperty, |
| | | id:'lineFly', |
| | | // label: { |
| | | // show: true, |
| | | // font: '18px 微软雅黑', |
| | | // style: Cesium.LabelStyle.FILL_AND_OUTLINE, |
| | | // showBackground: false, |
| | | // backgroundColor: Cesium.Color.fromCssColorString('#123456').withAlpha(0.5), |
| | | // outlineColor: Cesium.Color.fromCssColorString('#00ff00'), |
| | | // outlineWidth: 3, |
| | | // fillColor: Cesium.Color.fromCssColorString("#000000"), |
| | | // horizontalOrigin: Cesium.HorizontalOrigin.CENTER, |
| | | // verticalOrigin: Cesium.VerticalOrigin.TOP, |
| | | // text: '测试文字', |
| | | // // pixelOffset: new Cesium.Cartesian2(0, -1 * 100), |
| | | // pixelOffset: new Cesium.Cartesian2(0, -90) |
| | | // }, |
| | | model: { |
| | | uri: "/Model/M300.glb", // 注意entitits.add方式加载gltf文件时,这里是uri,不是url,并且这种方式只能加载.glb格式的文件 |
| | | scale: 10, // 缩放比例 |
| | | // minimumPixelSize: this.minSize, // 最小像素大小,可以避免太小看不见 |
| | | minimumPixelSize: 0, // 最小像素大小,可以避免太小看不见 |
| | | maximumScale: 20000, // 模型的最大比例尺大小。minimumPixelSize的上限 |
| | | incrementallyLoadTextures: true, // 加载模型后纹理是否可以继续流入 |
| | |
| | | leadTime: 60, |
| | | trailTime: 60 |
| | | }, |
| | | // orientation: Cesium.Quaternion.fromHeadingPitchRoll( |
| | | // new Cesium.HeadingPitchRoll( |
| | | // Cesium.Math.toRadians(45), // 航向角(正北为0,顺时针增加) |
| | | // Cesium.Math.toRadians(45), // 俯仰角 |
| | | // Cesium.Math.toRadians(0) // 翻滚角 |
| | | // ) |
| | | // ), |
| | | orientation:this.orientation |
| | | }) |
| | | }, |
| | | // 更新视锥体位置和朝向 |
| | | updateFrustum() { |
| | | console.log(this.c3Position) |
| | | console.log(this.pitch) |
| | | console.log(this.heading) |
| | | console.log(this.roll) |
| | | // 更新视锥体位置 |
| | | // this.c3Position = Cesium.Cartesian3.fromDegrees(114.169, 22.278, 500); // 动态更新位置 |
| | | if (this.frustumOutline) { |
| | | // 更新相机和视锥体位置 |
| | | this.camera.setView({ |
| | |
| | | } else { |
| | | console.warn('Frustum outline is not initialized'); |
| | | } |
| | | // 更新视锥体边框 |
| | | console.log(this.frustumOutline) |
| | | // this.frustumOutline.update(); |
| | | }, |
| | | listenChange() { |
| | | let viewer = window.viewer; |
| | |
| | | if (viewer.clock.shouldAnimate) { |
| | | this.getCurrentPosition() |
| | | // 执行动作 |
| | | console.log("Clock is running, performing action..."); |
| | | // 你的代码逻辑 |
| | | // console.log("Clock is running, performing action..."); |
| | | // 你的代码逻 |
| | | } else { |
| | | // 时钟暂停时不执行 |
| | | console.log("Clock is paused, no action performed."); |
| | | // console.log("Clock is paused, no action performed."); |
| | | } |
| | | }); |
| | | }, |
| | | getCurrentPosition() { |
| | | // 获取当前时间 |
| | | const currentTime = viewer.clock.currentTime; |
| | | console.log(Cesium.JulianDate.toDate(currentTime)) |
| | | console.log('start:', Cesium.JulianDate.toDate(this.positionProperty._property._times[0])); |
| | | console.log('stop:', Cesium.JulianDate.toDate(this.positionProperty._property._times.slice(-1)[0])); |
| | | // const currentTime = Cesium.JulianDate.addHours(currentTime, -8, new Cesium.JulianDate()); |
| | | |
| | | console.log(currentTime) |
| | | // 从 positionProperty 中获取当前位置 |
| | | const currentPosition = this.positionProperty.getValue(currentTime); |
| | | console.log('currentPosition>>>>>>>>>>>>>>>>>>>>>>>' + currentPosition) |
| | | |
| | | // console.log('currentPosition>>>>>>>>>>>>>>>>>>>>>>>' + currentPosition) |
| | | // 如果获取到位置 |
| | | if (currentPosition) { |
| | | // 将位置从 Cartesian 转换为 Cartographic |
| | |
| | | |
| | | // 将经纬度从弧度转换为度 |
| | | this.currentLongitude = Cesium.Math.toDegrees(cartographicPosition.longitude); |
| | | console.log(Cesium.Math.toDegrees(cartographicPosition.longitude)) |
| | | console.log(Cesium.Math.toDegrees(cartographicPosition.latitude)) |
| | | this.currentLatitude = Cesium.Math.toDegrees(cartographicPosition.latitude); |
| | | this.currentHeight = cartographicPosition.height; |
| | | this.c3Position = Cesium.Cartesian3.fromDegrees(this.currentLongitude, this.currentLatitude,this.currentHeight) |
| | | // console.log(`当前位置 - 经度: ${this.currentLongitude}, 纬度: ${this.currentLatitude}, 高度: ${this.currentHeight}`); |
| | | //相机变化 |
| | | const quaternion = this.orientation.getValue(currentTime) |
| | | if (quaternion) { |
| | | const hpr = Cesium.HeadingPitchRoll.fromQuaternion(quaternion) |
| | | // if(quaternion) { |
| | | // const hpr111 = Cesium.HeadingPitchRoll.fromQuaternion(quaternion) |
| | | // console.log('相机的 ' +Cesium.Math.toDegrees(hpr111.heading).toFixed(2)) |
| | | // } |
| | | //云台变化 |
| | | const sztquaternion = this.sztOrientation.getValue(currentTime) |
| | | console.log(sztquaternion) |
| | | if (sztquaternion) { |
| | | const hpr = Cesium.HeadingPitchRoll.fromQuaternion(sztquaternion) |
| | | console.log(hpr) |
| | | this.heading = Cesium.Math.toDegrees(hpr.heading).toFixed(2) |
| | | // this.heading = 180 |
| | | this.pitch = Cesium.Math.toDegrees(hpr.pitch).toFixed(2) |
| | | this.roll = Cesium.Math.toDegrees(hpr.roll).toFixed(2) |
| | | console.log(`当前位置 - heading: ${hpr.heading}, pitch: ${hpr.pitch}, roll: ${hpr.roll}`); |
| | | console.log('当前位置 - heading ' + this.heading) |
| | | console.log(`当前位置 - heading: ${this.heading}, pitch: ${this.pitch}, roll: ${this.roll}`); |
| | | } |
| | | |
| | | this.updateFrustum(); |
| | | } else { |
| | | console.log("无法获取当前位置"); |
| | |
| | | up: Cesium.Cartesian3.UNIT_Z, |
| | | destination: this.c3Position, |
| | | orientation: { |
| | | // heading: Cesium.Math.toRadians(this.heading), |
| | | // pitch: Cesium.Math.toRadians(this.pitch), |
| | | // roll: Cesium.Math.toRadians(this.roll), |
| | | heading: Cesium.Math.toRadians(this.heading), |
| | | pitch: Cesium.Math.toRadians(this.pitch), |
| | | roll: Cesium.Math.toRadians(this.roll), |
| | | }, |
| | | }) |
| | | this.frustumOutline = new Cesium.DebugCameraPrimitive({ |
| | | // id: this.id, |
| | | id: 111111, |
| | | camera: this.camera, |
| | | frustumSplits: [0.01, 10000], |
| | |
| | | // updateOnChange: false, |
| | | updateOnChange: true, |
| | | }) |
| | | console.log(this.frustumOutline) |
| | | viewer.scene.primitives.add(this.frustumOutline); |
| | | this.listenChange() |
| | | } |