<!--
|
* @Author : yuan
|
* @Date : 2025-08-13 15:46:27
|
* @LastEditors : yuan
|
* @LastEditTime : 2025-11-19 13:56:20
|
* @FilePath : \video.html
|
* @Description :
|
* Copyright 2025 OBKoro1, All Rights Reserved.
|
* 2025-08-13 15:46:27
|
-->
|
<!DOCTYPE html>
|
<!-- 指定HTML文档类型 -->
|
<html lang="en">
|
<!-- HTML根元素,语言设置为英语 -->
|
|
<head>
|
<!-- 文档头部,包含元数据和引用的资源 -->
|
<meta charset="UTF-8">
|
<!-- 指定字符编码为UTF-8 -->
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<!-- 设置视口,用于响应式设计 -->
|
<title>Document</title>
|
<!-- 设置文档标题 -->
|
|
<script src="./Build/Cesium.js"></script>
|
<!-- 引入Cesium.js库,用于3D地球和地图可视化 -->
|
|
<!-- 引入 Vue 3 -->
|
<!-- 通过CDN引入Vue 3框架 -->
|
<script src="https://cdn.jsdelivr.net/npm/vue@3.2.45/dist/vue.global.prod.js"></script>
|
|
<!-- 引入 Element Plus CSS -->
|
<!-- 通过CDN引入Element Plus UI库的CSS样式 -->
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/element-plus@2.9.11/dist/index.css">
|
|
<!-- 引入 Element Plus JS -->
|
<!-- 通过CDN引入Element Plus UI库的完整JavaScript文件 -->
|
<script src="https://cdn.jsdelivr.net/npm/element-plus@2.9.11/dist/index.full.js"></script>
|
|
<!-- <script src="./ZLMRTCClient.js"></script> -->
|
<!-- 注释掉的脚本,可能用于WebRTC相关的客户端功能 -->
|
|
<!-- <link href="https://cdn.bootcdn.net/ajax/libs/video.js/5.15.0/video-js.css" rel="stylesheet"> -->
|
<!-- 注释掉的video.js CSS链接,用于视频播放器样式 -->
|
<!-- <script src="https://cdn.bootcdn.net/ajax/libs/video.js/5.15.0/video.min.js"></script> -->
|
<!-- 注释掉的video.js库,用于视频播放 -->
|
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/videojs-contrib-hls/5.15.0/videojs-contrib-hls.min.js"
|
type="text/javascript"></script> -->
|
<!-- 注释掉的video.js HLS插件,用于播放HLS流媒体 -->
|
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/sass.js/0.10.0/sass.min.js"></script>
|
<!-- 引入Sass.js,用于在浏览器端编译Sass -->
|
<style id="sass-style">
|
/* 定义一个style标签,其内容将被Sass.js编译 */
|
@import url(./Build/Widgets/widgets.css);
|
/* 导入Cesium的部件样式 */
|
|
|
* {
|
/* 通配符选择器,重置所有元素的内外边距 */
|
padding: 0;
|
margin: 0;
|
}
|
|
html,
|
body {
|
/* 设置html和body元素高度为100% */
|
height: 100%;
|
}
|
|
#app {
|
/* Vue应用的根元素样式 */
|
position: relative;
|
/* 相对定位 */
|
width: 100%;
|
/* 宽度100% */
|
height: 100%;
|
/* 高度100% */
|
}
|
|
#cesiumContainer {
|
/* Cesium容器的样式 */
|
width: 100%;
|
/* 宽度100% */
|
height: 100%;
|
/* 高度100% */
|
}
|
|
.control-panel {
|
/* 控制面板的样式 */
|
position: absolute;
|
/* 绝对定位 */
|
top: 10px;
|
/* 距离顶部10px */
|
left: 10px;
|
/* 距离左侧10px */
|
background-color: rgba(255, 255, 255, 0.8);
|
/* 半透明白色背景 */
|
padding: 10px;
|
/* 内边距10px */
|
border-radius: 5px;
|
/* 边框圆角5px */
|
z-index: 1000;
|
/* 设置堆叠顺序,确保在顶层 */
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
/* 添加阴影效果 */
|
|
&>div {
|
/* 控制面板内直接子div元素的样式(Sass嵌套语法) */
|
display: flex;
|
/* 使用flex布局 */
|
justify-content: space-between;
|
/* 子元素之间平均分布 */
|
align-items: center;
|
/* 垂直居中对齐 */
|
height: 36px;
|
/* 高度36px */
|
}
|
}
|
|
/* 在此处添加 Sass 代码,Sass.js 将会编译 */
|
/* Sass编译提示 */
|
</style>
|
</head>
|
|
<body>
|
<!-- Vue应用的根容器 -->
|
<div id="app">
|
<!-- 控制面板 -->
|
<div class="control-panel">
|
<!-- 拍照/视频镜头选择 -->
|
<div>
|
<div>拍照/视频镜头(多选)</div>
|
<div>
|
<el-radio-group v-model="lensVal" size="small">
|
<el-radio :value="1" border>可见光</el-radio>
|
<el-radio :value="2" border>红外</el-radio>
|
</el-radio-group>
|
</div>
|
</div>
|
<!-- GSD可见光设置 -->
|
<div>
|
<div>GSD可见光</div>
|
<div>
|
<el-input-number v-model="gsdVal" :min="5" :max="30" @change="handleGSDChange" size="small" />
|
</div>
|
</div>
|
<!-- 相对被射面距离设置 -->
|
<div>
|
<div>相对被射面距离</div>
|
<div>
|
<el-input-number v-model="relDistanceVal" :min="10" :max="100" @change="handleRelDistanceChange"
|
size="small" />
|
</div>
|
</div>
|
<!-- 安全起飞高度设置 -->
|
<div>
|
<div>安全起飞高度(相对起飞高度)</div>
|
<div>
|
<el-input-number v-model="takeOffVal" :min="2" :max="3000" @change="handleTakeOffChange"
|
size="small" />
|
</div>
|
</div>
|
<!-- 测区方向设置 -->
|
<div>
|
<div>测区方向</div>
|
<div>
|
<el-checkbox v-model="isOverturn" label="翻转测区" size="small" border />
|
</div>
|
</div>
|
<!-- 航线方向设置 -->
|
<div>
|
<div>航线方向</div>
|
<div>
|
<el-radio-group v-model="routeDirection" size="small">
|
<el-radio :value="1" border>水平方向</el-radio>
|
<el-radio :value="2" border>垂直方向</el-radio>
|
</el-radio-group>
|
</div>
|
</div>
|
<!-- 完成动作设置 -->
|
<div>
|
<div>
|
完成动作
|
</div>
|
<div>
|
<el-radio-group v-model="completeTheAction" size="small">
|
<el-radio :value="1" border>自动返航</el-radio>
|
</el-radio-group>
|
</div>
|
</div>
|
|
<!-- 拍照方式设置 -->
|
<div>
|
<div>
|
拍照方式
|
</div>
|
<div>
|
<el-radio-group v-model="takeAPicture" size="small">
|
<el-radio :value="1" border>等时间拍照</el-radio>
|
<el-radio :value="2" border>等间距拍照</el-radio>
|
</el-radio-group>
|
</div>
|
</div>
|
|
<!-- 旁向重叠率设置 -->
|
<div>
|
<div>旁向重叠率</div>
|
<div>
|
<el-input-number v-model="lateralVal" :min="10" :max="90" @change="handleLateralChange"
|
size="small" />
|
</div>
|
</div>
|
|
<!-- 航向重叠率设置 -->
|
<div>
|
<div>航向重叠率</div>
|
<div>
|
<el-input-number v-model="headingVal" :min="10" :max="90" @change="handleHeadingChange"
|
size="small" />
|
</div>
|
</div>
|
|
<!-- 提交按钮 -->
|
<el-button type="primary" @click="submitBevelRoute">确定</el-button>
|
</div>
|
|
<!-- Cesium 3D地球容器 -->
|
<div id="cesiumContainer"></div>
|
</div>
|
</body>
|
|
<script src="https://cdn.bootcdn.net/ajax/libs/Turf.js/6.5.0/turf.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjs/10.0.0/math.min.js"></script>
|
<script>
|
// 从Vue全局对象中解构出createApp方法
|
const { createApp } = Vue
|
|
// 创建Vue应用实例
|
createApp({
|
// data()函数返回一个对象,包含应用的状态数据
|
data () {
|
return {
|
lensVal: 1, // 镜头类型值,1-可见光,2-红外
|
gsdVal: 10, // GSD可见光值
|
relDistanceVal: 10, // 相对被射面距离值
|
takeOffVal: 10, // 安全起飞高度值
|
|
isOverturn: false, // 是否翻转测区
|
routeDirection: 2, // 航线方向,1-水平,2-垂直
|
completeTheAction: 1, // 完成动作,1-自动返航
|
takeAPicture: 1, // 拍照方式,1-等时间,2-等间距
|
lateralVal: 70, // 旁向重叠率
|
headingVal: 70 // 航向重叠率
|
}
|
},
|
// methods对象包含应用的方法
|
methods: {
|
// GSD值变化时的处理函数
|
handleGSDChange (value) {
|
console.log('GSD changed to:', value)
|
},
|
|
// 相对被射面距离变化时的处理函数
|
handleRelDistanceChange (value) {
|
console.log('handleRelDistanceChange:', value)
|
},
|
|
// 安全起飞高度变化时的处理函数
|
handleTakeOffChange (value) {
|
console.log('handleTakeOffChange:', value)
|
},
|
|
// 旁向重叠率变化时的处理函数
|
handleLateralChange (value) {
|
console.log('handleLateralChange:', value)
|
},
|
|
// 航向重叠率变化时的处理函数
|
handleHeadingChange (value) {
|
console.log('handleHeadingChange:', value)
|
},
|
|
// 提交倾斜航线设置的函数
|
submitBevelRoute () {
|
|
}
|
},
|
|
// mounted是Vue的生命周期钩子,在组件挂载到DOM后执行
|
mounted () {
|
|
// 定义相机类型常量
|
const CmaeraType = {
|
M3D: 'M3D', //m3d机型
|
M3TD: 'M3TD', //m3td机型
|
M30: 'M30', //一代(M30,M30T
|
M3E: 'Mavic 3E',
|
M3T: 'Mavic 3T',
|
M350: 'Matrice 350 RTK', //草莓机场
|
M4D: 'Matrice 4D', //三代机场
|
M4TD: 'Matrice 4TD'
|
}
|
// 设置Cesium Ion的默认访问令牌
|
Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIzNjYzOTI5NC0yM2QyLTQyOTgtYWM5OS1lM2MwNTYwMGEzMjciLCJpZCI6ODQ1MjYsImlhdCI6MTY0NjM1ODM5OX0.BzsVR7Lt9RhsCia-R7E64KunaAME0HGD7Sv2-xF-RIQ'
|
|
//按名字移除entity
|
// 根据名称模糊查找实体
|
function getEntityLikeName (viewer, name) {
|
if (name) {
|
var entities = viewer.entities.values
|
var findEntities = []
|
for (var i = 0; i < entities.length; i++) {
|
var entity = entities[i]
|
if (entity.name && entity.name.indexOf(name) !== -1) {
|
findEntities.push(entity)
|
}
|
}
|
return findEntities
|
} else {
|
return []
|
}
|
}
|
// 根据名称模糊移除实体
|
function removeEntityLikeName (viewer, name) {
|
if (name) {
|
var cleanEntities = getEntityLikeName(viewer, name)
|
// 清除
|
cleanEntities.map((res) => {
|
viewer.entities.removeById(res.id)
|
})
|
} else {
|
viewer.entities.removeAll()
|
}
|
}
|
|
|
async function CalcCourseSlopeLineLine (viewer, positions, angle, space, relativeHeight, isActivateEdit) {
|
const entity = viewer.entities.getById('flightLine')
|
if (entity) {
|
viewer.entities.remove(entity)
|
}
|
|
if (!Array.isArray(positions) || positions.length < 4 || !(space > 0)) {
|
return []
|
}
|
|
function computeNormal (positions) {
|
const v13 = Cesium.Cartesian3.subtract(positions[0], positions[2], new Cesium.Cartesian3())
|
const v24 = Cesium.Cartesian3.subtract(positions[1], positions[3], new Cesium.Cartesian3())
|
const n = Cesium.Cartesian3.cross(v13, v24, new Cesium.Cartesian3())
|
return Cesium.Cartesian3.normalize(n, new Cesium.Cartesian3())
|
}
|
|
function computeOffsetPositions (positions, relativeHeight) {
|
const normal = computeNormal(positions)
|
const offset = Cesium.Cartesian3.multiplyByScalar(normal, relativeHeight, new Cesium.Cartesian3())
|
const out = new Array(positions.length)
|
for (let i = 0; i < positions.length; i++) {
|
out[i] = Cesium.Cartesian3.add(positions[i], offset, new Cesium.Cartesian3())
|
}
|
return out
|
}
|
|
function splitSegment (point1, point2, s, reverse) {
|
const distance = Cesium.Cartesian3.distance(point1, point2)
|
const segments = Math.max(1, Math.ceil(distance / s))
|
const points = new Array(segments + 1)
|
if (reverse) {
|
for (let i = segments; i >= 0; i--) {
|
const fraction = i / segments
|
const pt = new Cesium.Cartesian3()
|
Cesium.Cartesian3.lerp(point1, point2, fraction, pt)
|
points[segments - i] = pt
|
}
|
} else {
|
for (let i = 0; i <= segments; i++) {
|
const fraction = i / segments
|
const pt = new Cesium.Cartesian3()
|
Cesium.Cartesian3.lerp(point1, point2, fraction, pt)
|
points[i] = pt
|
}
|
}
|
return points
|
}
|
|
function projectPointOnSegment (pointA, pointB, pointC) {
|
const vectorBC = Cesium.Cartesian3.subtract(pointC, pointB, new Cesium.Cartesian3())
|
const vectorBA = Cesium.Cartesian3.subtract(pointA, pointB, new Cesium.Cartesian3())
|
const projection = new Cesium.Cartesian3()
|
Cesium.Cartesian3.projectVector(vectorBA, vectorBC, projection)
|
return Cesium.Cartesian3.add(pointB, projection, new Cesium.Cartesian3())
|
}
|
|
function adjustCornersByProjection (positionOffset, distance01) {
|
const projectionPoint2 = projectPointOnSegment(positionOffset[2], positionOffset[1], positionOffset[0])
|
const projectionPoint3 = projectPointOnSegment(positionOffset[3], positionOffset[0], positionOffset[1])
|
const distanceP2 = Cesium.Cartesian3.distance(projectionPoint2, positionOffset[2])
|
const distanceP3 = Cesium.Cartesian3.distance(projectionPoint3, positionOffset[3])
|
const distanceP30 = Cesium.Cartesian3.distance(projectionPoint3, positionOffset[0])
|
const distanceP31 = Cesium.Cartesian3.distance(projectionPoint3, positionOffset[1])
|
const newPoint0 = distanceP30 + distanceP31 > distance01 ? projectionPoint3 : positionOffset[0]
|
const distanceP20 = Cesium.Cartesian3.distance(projectionPoint2, positionOffset[0])
|
const distanceP21 = Cesium.Cartesian3.distance(projectionPoint2, positionOffset[1])
|
const newPoint1 = distanceP20 + distanceP21 > distance01 ? projectionPoint2 : positionOffset[1]
|
let newPoint2, newPoint3
|
if (distanceP2 > distanceP3) {
|
if (distanceP20 + distanceP21 > distance01) {
|
newPoint2 = positionOffset[2]
|
} else {
|
const vector = Cesium.Cartesian3.subtract(positionOffset[1], projectionPoint2, new Cesium.Cartesian3())
|
newPoint2 = Cesium.Cartesian3.add(positionOffset[2], vector, new Cesium.Cartesian3())
|
}
|
const vector01 = Cesium.Cartesian3.subtract(newPoint0, newPoint1, new Cesium.Cartesian3())
|
newPoint3 = Cesium.Cartesian3.add(newPoint2, vector01, new Cesium.Cartesian3())
|
} else {
|
if (distanceP30 + distanceP31 > distance01) {
|
newPoint3 = positionOffset[3]
|
} else {
|
const vector = Cesium.Cartesian3.subtract(positionOffset[0], projectionPoint3, new Cesium.Cartesian3())
|
newPoint3 = Cesium.Cartesian3.add(positionOffset[3], vector, new Cesium.Cartesian3())
|
}
|
const vector01 = Cesium.Cartesian3.subtract(newPoint1, newPoint0, new Cesium.Cartesian3())
|
newPoint2 = Cesium.Cartesian3.add(newPoint3, vector01, new Cesium.Cartesian3())
|
}
|
return { newPointList: [newPoint0, newPoint1, newPoint2, newPoint3, newPoint0], distanceP2, distanceP3, distanceP20, distanceP21, distanceP30, distanceP31 }
|
}
|
|
function handleSplitLinePosition (arr1, arr2, out) {
|
arr1.forEach((item, i) => {
|
if (i % 2 === 0) {
|
out.push(arr2[i], item)
|
} else {
|
out.push(item, arr2[i])
|
}
|
})
|
}
|
|
const positionOffset = computeOffsetPositions(positions, relativeHeight)
|
|
const distance01 = Cesium.Cartesian3.distance(positionOffset[0], positionOffset[1])
|
const distance12 = Cesium.Cartesian3.distance(positionOffset[1], positionOffset[2])
|
const distance23 = Cesium.Cartesian3.distance(positionOffset[2], positionOffset[3])
|
const distance30 = Cesium.Cartesian3.distance(positionOffset[3], positionOffset[0])
|
|
const splitLinePosition = []
|
|
if (angle === 0) {
|
if (!isActivateEdit) {
|
const split12 = splitSegment(positionOffset[1], positionOffset[2], space, false)
|
const newSplit03 = splitSegment(positionOffset[3], positionOffset[0], space, true)
|
for (let i = 0; i < split12.length; i++) {
|
if (i % 2 === 0) {
|
splitLinePosition.push(newSplit03[i], split12[i])
|
} else {
|
splitLinePosition.push(split12[i], newSplit03[i])
|
}
|
}
|
} else {
|
const adj = adjustCornersByProjection(positionOffset, distance01)
|
const newPointList = adj.newPointList
|
const distanceNew12 = Cesium.Cartesian3.distance(positionOffset[1], positionOffset[2])
|
const distanceNew23 = Cesium.Cartesian3.distance(positionOffset[2], positionOffset[3])
|
const distanceNew30 = Cesium.Cartesian3.distance(positionOffset[3], positionOffset[0])
|
|
const newSplit12 = splitSegment(newPointList[1], newPointList[2], space, false)
|
const newSplit03 = splitSegment(newPointList[3], newPointList[0], space, true)
|
|
const newSplitLinePosition03 = []
|
const newSplitLinePosition12 = []
|
const newSplitLinePosition23 = []
|
|
for (let i = 0; i < newSplit12.length; i++) {
|
const newLinePoint1 = [newSplit12[i].x, newSplit12[i].y, newSplit12[i].z]
|
const newLinePoint2 = [newSplit03[i].x, newSplit03[i].y, newSplit03[i].z]
|
|
const linePoint1 = [positionOffset[1].x, positionOffset[1].y, positionOffset[1].z]
|
const linePoint2 = [positionOffset[2].x, positionOffset[2].y, positionOffset[2].z]
|
const intersectPoint12 = math.intersect(newLinePoint1, newLinePoint2, linePoint1, linePoint2)
|
if (intersectPoint12 && intersectPoint12.length > 0) {
|
const cartesian3 = new Cesium.Cartesian3(intersectPoint12[0], intersectPoint12[1], intersectPoint12[2])
|
const distanceLine12 = Cesium.Cartesian3.distance(cartesian3, positionOffset[1])
|
if (distanceLine12 <= distanceNew12) {
|
newSplitLinePosition12.push(cartesian3)
|
}
|
}
|
|
const linePoint3 = [positionOffset[3].x, positionOffset[3].y, positionOffset[3].z]
|
const linePoint0 = [positionOffset[0].x, positionOffset[0].y, positionOffset[0].z]
|
const intersectPoint03 = math.intersect(newLinePoint1, newLinePoint2, linePoint3, linePoint0)
|
if (intersectPoint03 && intersectPoint03.length > 0) {
|
const cartesian3 = new Cesium.Cartesian3(intersectPoint03[0], intersectPoint03[1], intersectPoint03[2])
|
const distanceLine30 = Cesium.Cartesian3.distance(cartesian3, positionOffset[0])
|
if (distanceLine30 <= distanceNew30) {
|
newSplitLinePosition03.push(cartesian3)
|
}
|
}
|
|
const intersectPoint23 = math.intersect(newLinePoint1, newLinePoint2, linePoint3, linePoint2)
|
if (intersectPoint23 && intersectPoint23.length > 0) {
|
const cartesian3 = new Cesium.Cartesian3(intersectPoint23[0], intersectPoint23[1], intersectPoint23[2])
|
const distanceLine23 = Cesium.Cartesian3.distance(cartesian3, adj.distanceP2 > adj.distanceP3 ? positionOffset[2] : positionOffset[3])
|
if (distanceLine23 < distanceNew23) {
|
newSplitLinePosition23.push(cartesian3)
|
}
|
}
|
}
|
|
if (adj.distanceP2 > adj.distanceP3) {
|
const reNewSplitLinePosition0323 = [...newSplitLinePosition03, ...newSplitLinePosition23]
|
for (let i = 0; i < newSplitLinePosition12.length; i++) {
|
if (i % 2 === 0) {
|
splitLinePosition.push(reNewSplitLinePosition0323[i], newSplitLinePosition12[i])
|
} else {
|
splitLinePosition.push(newSplitLinePosition12[i], reNewSplitLinePosition0323[i])
|
}
|
}
|
} else {
|
const reNewSplitLinePosition1223 = [...newSplitLinePosition12, ...newSplitLinePosition23]
|
for (let i = 0; i < newSplitLinePosition03.length; i++) {
|
if (i % 2 === 0) {
|
splitLinePosition.push(newSplitLinePosition03[i], reNewSplitLinePosition1223[i])
|
} else {
|
splitLinePosition.push(reNewSplitLinePosition1223[i], newSplitLinePosition03[i])
|
}
|
}
|
}
|
}
|
} else {
|
if (distance12 === distance30) {
|
const split01 = splitSegment(positionOffset[0], positionOffset[1], space, false)
|
const newSplit23 = splitSegment(positionOffset[2], positionOffset[3], space, true)
|
for (let i = 0; i < split01.length; i++) {
|
if (i % 2 === 0) {
|
splitLinePosition.push(split01[i], newSplit23[i])
|
} else {
|
splitLinePosition.push(newSplit23[i], split01[i])
|
}
|
}
|
} else {
|
const adj = adjustCornersByProjection(positionOffset, distance01)
|
const newPointList = adj.newPointList
|
|
const distanceNew12 = Cesium.Cartesian3.distance(positionOffset[1], positionOffset[2])
|
const distanceNew23 = Cesium.Cartesian3.distance(positionOffset[2], positionOffset[3])
|
const distanceNew30 = Cesium.Cartesian3.distance(positionOffset[3], positionOffset[0])
|
const distanceNew01 = Cesium.Cartesian3.distance(positionOffset[1], positionOffset[0])
|
|
const newSplit01 = splitSegment(newPointList[0], newPointList[1], space, false)
|
const newSplit32 = splitSegment(newPointList[3], newPointList[2], space, false)
|
|
const newSplitLinePosition01 = []
|
const newSplitLinePosition12 = []
|
const newSplitLinePosition23 = []
|
const newSplitLinePosition03 = []
|
|
for (let i = 0; i < newSplit01.length; i++) {
|
const newLinePoint1 = [newSplit01[i].x, newSplit01[i].y, newSplit01[i].z]
|
const newLinePoint2 = [newSplit32[i].x, newSplit32[i].y, newSplit32[i].z]
|
|
const linePoint1 = [positionOffset[1].x, positionOffset[1].y, positionOffset[1].z]
|
const linePoint2 = [positionOffset[2].x, positionOffset[2].y, positionOffset[2].z]
|
const intersectPoint12 = math.intersect(newLinePoint1, newLinePoint2, linePoint1, linePoint2)
|
if (intersectPoint12 && intersectPoint12.length > 0) {
|
const cartesian3 = new Cesium.Cartesian3(intersectPoint12[0], intersectPoint12[1], intersectPoint12[2])
|
const distanceLine12 = Cesium.Cartesian3.distance(cartesian3, positionOffset[1])
|
const Cartographic1 = viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian3)
|
const Cartographic2 = viewer.scene.globe.ellipsoid.cartesianToCartographic(positionOffset[1])
|
if (distanceLine12 <= distanceNew12 && Cartographic1.height >= Cartographic2.height) {
|
newSplitLinePosition12.push(cartesian3)
|
}
|
}
|
|
const linePoint3 = [positionOffset[3].x, positionOffset[3].y, positionOffset[3].z]
|
const linePoint0 = [positionOffset[0].x, positionOffset[0].y, positionOffset[0].z]
|
const intersectPoint03 = math.intersect(newLinePoint1, newLinePoint2, linePoint3, linePoint0)
|
if (intersectPoint03 && intersectPoint03.length > 0) {
|
const cartesian3 = new Cesium.Cartesian3(intersectPoint03[0], intersectPoint03[1], intersectPoint03[2])
|
const distanceLine30 = Cesium.Cartesian3.distance(cartesian3, positionOffset[0])
|
const Cartographic1 = viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian3)
|
const Cartographic2 = viewer.scene.globe.ellipsoid.cartesianToCartographic(positionOffset[0])
|
if (distanceLine30 <= distanceNew30 && Cartographic1.height >= Cartographic2.height) {
|
newSplitLinePosition03.push(cartesian3)
|
}
|
}
|
|
const intersectPoint23 = math.intersect(newLinePoint1, newLinePoint2, linePoint3, linePoint2)
|
if (intersectPoint23 && intersectPoint23.length > 0) {
|
const cartesian3 = new Cesium.Cartesian3(intersectPoint23[0], intersectPoint23[1], intersectPoint23[2])
|
const distanceLine03 = Cesium.Cartesian3.distance(cartesian3, positionOffset[2])
|
const distanceLine04 = Cesium.Cartesian3.distance(cartesian3, positionOffset[3])
|
const distanceLine233 = Cesium.Cartesian3.distance(positionOffset[2], positionOffset[3])
|
const distance = distanceLine04 > distanceLine03 ? distanceLine04 : distanceLine03
|
if (distance < distanceLine233) {
|
newSplitLinePosition23.push(cartesian3)
|
}
|
}
|
|
const intersectPoint01 = math.intersect(newLinePoint1, newLinePoint2, linePoint0, linePoint1)
|
if (intersectPoint01 && intersectPoint01.length > 0) {
|
const cartesian3 = new Cesium.Cartesian3(intersectPoint01[0], intersectPoint01[1], intersectPoint01[2])
|
const distanceLine01 = Cesium.Cartesian3.distance(cartesian3, positionOffset[0])
|
const distanceLine02 = Cesium.Cartesian3.distance(cartesian3, positionOffset[1])
|
const distanceLine012 = Cesium.Cartesian3.distance(positionOffset[0], positionOffset[1])
|
const distance = distanceLine02 > distanceLine01 ? distanceLine02 : distanceLine01
|
if (distance < distanceLine012) {
|
newSplitLinePosition01.push(cartesian3)
|
}
|
}
|
}
|
|
if (adj.distanceP2 > adj.distanceP3) {
|
let arr, brr, startPoint, endPoint
|
if (adj.distanceP20 + adj.distanceP21 > distance01) {
|
if (adj.distanceP30 + adj.distanceP31 > distance01) {
|
arr = [...newSplitLinePosition23].reverse()
|
brr = [...newSplitLinePosition12].reverse().concat([...newSplitLinePosition01].reverse(), [...newSplitLinePosition03].reverse())
|
startPoint = brr.shift()
|
endPoint = arr.pop()
|
} else {
|
arr = [...newSplitLinePosition23].reverse().concat([...newSplitLinePosition03].reverse())
|
brr = [...newSplitLinePosition12].reverse().concat([...newSplitLinePosition01].reverse())
|
startPoint = brr.shift()
|
endPoint = arr.pop()
|
}
|
} else {
|
if (adj.distanceP30 + adj.distanceP31 > distance01) {
|
arr = [...newSplitLinePosition12].reverse().concat([...newSplitLinePosition23].reverse())
|
brr = [...newSplitLinePosition01].reverse().concat([...newSplitLinePosition03].reverse())
|
startPoint = arr.shift()
|
endPoint = brr.pop()
|
} else {
|
arr = [...newSplitLinePosition01].reverse()
|
brr = [...newSplitLinePosition12].reverse().concat([...newSplitLinePosition23].reverse(), [...newSplitLinePosition03].reverse())
|
startPoint = brr.shift()
|
endPoint = arr.pop()
|
}
|
}
|
splitLinePosition.push(startPoint)
|
handleSplitLinePosition(arr, brr, splitLinePosition)
|
splitLinePosition.push(endPoint)
|
} else {
|
let arr, brr
|
if (adj.distanceP20 + adj.distanceP21 > distance01) {
|
if (adj.distanceP30 + adj.distanceP31 > distance01) {
|
arr = [...newSplitLinePosition23].reverse()
|
brr = [...newSplitLinePosition12].reverse().concat([...newSplitLinePosition01].reverse(), [...newSplitLinePosition03].reverse())
|
} else {
|
arr = [...newSplitLinePosition23].reverse().concat([...newSplitLinePosition03].reverse())
|
brr = [...newSplitLinePosition12].reverse().concat([...newSplitLinePosition01].reverse())
|
}
|
} else {
|
if (adj.distanceP30 + adj.distanceP31 > distance01) {
|
arr = [...newSplitLinePosition12].reverse().concat([...newSplitLinePosition23].reverse())
|
brr = [...newSplitLinePosition01].reverse().concat([...newSplitLinePosition03].reverse())
|
} else {
|
arr = [...newSplitLinePosition01].reverse()
|
brr = [...newSplitLinePosition12].reverse().concat([...newSplitLinePosition23].reverse(), [...newSplitLinePosition03].reverse())
|
}
|
}
|
handleSplitLinePosition(arr, brr, splitLinePosition)
|
}
|
}
|
}
|
|
return splitLinePosition
|
}
|
|
// 初始化Cesium Viewer
|
var viewer = new Cesium.Viewer('cesiumContainer', {
|
|
|
// 使用ArcGIS在线世界影像服务
|
imageryProvider: new Cesium.ArcGisMapServerImageryProvider({
|
url: "https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer",
|
maximumLevel: 18,
|
}),
|
|
// // 使用Cesium官方世界地形服务
|
// terrainProvider: Cesium.createWorldTerrain({
|
// requestVertexNormals: true, // 请求顶点法线,用于光照
|
// requestWaterMask: true // 请求水面遮罩
|
// }),
|
shouldAnimate: true, // 开启动画
|
selectionIndicator: false, // 禁用选择指示器
|
infoBox: false, // 禁用信息框
|
geocoder: false, // 禁用地理编码器(位置查找工具)
|
baseLayerPicker: false,// 禁用底图选择器
|
timeline: false, // 禁用时间线
|
homeButton: false,// 禁用主页按钮
|
fullscreenButton: false, // 禁用全屏按钮
|
animation: false, // 禁用动画小部件
|
sceneModePicker: false,// 禁用场景模式选择器
|
navigationHelpButton: false, // 禁用导航帮助按钮
|
})
|
//viewer.scene.debugShowFramesPerSecond = true; // 显示帧率
|
viewer?.cesiumWidget.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK) // 禁用双击
|
|
viewer.cesiumWidget.creditContainer.style.display = "none" // 隐藏版权信息
|
var towerJson
|
|
// viewer.flyTo(tileset);
|
var position = Cesium.Cartesian3.fromDegrees(117.903458, 28.452275, 5000)//定义一个初始飞行位置
|
// 相机飞行到指定位置
|
viewer.camera.flyTo({
|
destination: position, // 目标位置
|
orientation: { // 相机姿态
|
heading: Cesium.Math.toRadians(0), // 航向角
|
pitch: Cesium.Math.toRadians(-90), // 俯仰角
|
roll: 0.0, // 翻滚角
|
},
|
duration: 1, // 飞行持续时间(秒)
|
complete: function () { // 飞行完成后的回调
|
},
|
})
|
|
// viewer.scene.globe.depthTestAgainstTerrain = true // 开启深度检测
|
|
// 异步加载地形
|
async function loadTerrain () {
|
let worldTerrain
|
try {
|
// 异步创建世界地形
|
worldTerrain = await Cesium.createWorldTerrainAsync()
|
viewer.scene.terrainProvider = worldTerrain // 将加载的地形赋给场景
|
} catch (error) {
|
console.error('地形加载失败:', error)
|
}
|
}
|
|
loadTerrain() // 调用加载地形函数
|
|
// 添加天地图矢量图层
|
const imageryProvider_stand = new Cesium.UrlTemplateImageryProvider({
|
url: `https://t{s}.tianditu.gov.cn/DataServer?T=vec_w&x={x}&y={y}&l={z}&tk=e110584a27d506da2740edca951683f4`, // 天地图矢量服务地址
|
subdomains: ['0', '1', '2', '3', '4', '5', '6', '7'], // 子域
|
maximumLevel: 18, // 最大缩放级别
|
credit: 'stand_tc', // 版权信息
|
})
|
|
// 添加天地图注记图层
|
const imageryProvider_standd = new Cesium.UrlTemplateImageryProvider({
|
url: `https://t{s}.tianditu.gov.cn/DataServer?T=cva_w&x={x}&y={y}&l={z}&tk=e110584a27d506da2740edca951683f4`, // 天地图注记服务地址
|
subdomains: ['0', '1', '2', '3', '4', '5', '6', '7'],
|
maximumLevel: 18,
|
credit: 'stand_zj',
|
})
|
|
viewer?.imageryLayers.addImageryProvider(imageryProvider_stand) // 添加矢量图层到viewer
|
viewer?.imageryLayers.addImageryProvider(imageryProvider_standd) // 添加注记图层到viewer
|
|
function formatDistance (distanceInMeters) {
|
if (distanceInMeters < 1000) {
|
return `${(distanceInMeters).toFixed(2)} m`
|
} else {
|
return `${(distanceInMeters / 1000).toFixed(2)} km`
|
}
|
}
|
|
// 创建无人机航道面相关功能
|
const createUAVChannelPlane = () => {
|
// 创建一个点实体
|
function createPoint (position) {
|
return viewer.entities.add({
|
position: position,
|
point: {
|
color: new Cesium.Color(0, 1, 1, 0.9),
|
pixelSize: 10
|
}
|
})
|
}
|
|
// 初始化绘制线实体
|
function drawLine (positions) {
|
return viewer.entities.add({
|
polyline: {
|
positions: positions,
|
width: 2,
|
material: Cesium.Color.fromCssColorString('#2987f0'),
|
arcType: Cesium.ArcType.RHUMB, // 航路类型为恒向线
|
clampToGround: false // 不贴地
|
}
|
})
|
}
|
// 绘制虚线实体
|
function drawDashLine (positions, id) {
|
return viewer.entities.add({
|
name: 'dashLine',
|
id,
|
show: false, // 默认不显示
|
polyline: {
|
positions: positions,
|
width: 1,
|
material: new Cesium.PolylineDashMaterialProperty({ // 虚线材质
|
color: new Cesium.Color(1, 1, 1, 1),
|
}),
|
arcType: Cesium.ArcType.RHUMB,
|
clampToGround: false
|
}
|
})
|
}
|
|
// 绘制矩形多边形实体
|
function drawShape (positions) {
|
return viewer.entities.add({
|
id: 'polygon',
|
polygon: {
|
hierarchy: positions, // 多边形顶点
|
fill: true,
|
material: Cesium.Color.fromCssColorString('#2987f0').withAlpha(0.2), // 填充材质和透明度
|
outline: true,
|
outlineColor: Cesium.Color.fromCssColorString('#2987f0'), // 轮廓线颜色
|
perPositionHeight: true, // 每个顶点使用自己的高度
|
},
|
})
|
}
|
|
// 根据ID前缀删除实体
|
function removeEntity (entyId) {
|
const entyAll = viewer.entities.values
|
if (entyAll.length > 0) {
|
for (let i = entyAll.length - 1; i >= 0; i--) {
|
const entyOne = entyAll[i].id
|
if (entyOne.slice(0, entyId.length) === entyId) {
|
viewer.entities.remove(entyAll[i])
|
}
|
}
|
}
|
}
|
|
// 将一个点A围绕另一个点B旋转指定角度
|
function rotatedPointByAngle (position_A, position_B, angle) {
|
var localToWorld_Matrix = Cesium.Transforms.eastNorthUpToFixedFrame(position_B) // 获取B点的局部到世界坐标系的变换矩阵
|
var worldToLocal_Matrix = Cesium.Matrix4.inverse(localToWorld_Matrix, new Cesium.Matrix4()) // 求逆矩阵,即世界到局部
|
var localPosition_B = Cesium.Matrix4.multiplyByPoint(worldToLocal_Matrix, position_B, new Cesium.Cartesian3()) // B点的局部坐标
|
var localPosition_A = Cesium.Matrix4.multiplyByPoint(worldToLocal_Matrix, position_A, new Cesium.Cartesian3()) // A点的局部坐标
|
// 在局部坐标系下进行2D旋转
|
var new_x = localPosition_A.x * Math.cos(Cesium.Math.toRadians(angle)) + localPosition_A.y * Math.sin(Cesium.Math.toRadians(angle))
|
var new_y = localPosition_A.y * Math.cos(Cesium.Math.toRadians(angle)) - localPosition_A.x * Math.sin(Cesium.Math.toRadians(angle))
|
var new_z = localPosition_A.z
|
// 将旋转后的局部坐标转换回世界坐标
|
return Cesium.Matrix4.multiplyByPoint(localToWorld_Matrix, new Cesium.Cartesian3(new_x, new_y, new_z), new Cesium.Cartesian3())
|
}
|
|
// 创建角度刻度尺
|
function createAngleRuler (p0, p1) {
|
const vector01 = Cesium.Cartesian3.subtract(p1, p0, new Cesium.Cartesian3()) // 计算向量
|
const normalize = Cesium.Cartesian3.normalize(vector01, new Cesium.Cartesian3()) // 归一化向量
|
const radius = Cesium.Cartesian3.distance(p0, p1) / 4 // 计算半径
|
const centerVectorZ = Cesium.Cartesian3.add(Cesium.Cartesian3.multiplyByScalar(normalize, radius, new Cesium.Cartesian3()), p1, new Cesium.Cartesian3())
|
const rotate = rotatedPointByAngle(centerVectorZ, p1, -90) // 旋转点以确定刻度尺的初始位置
|
// 刻度尺长短
|
const radius1 = Cesium.Cartesian3.distance(p0, p1) / 4.3
|
const centerVectorZ1 = Cesium.Cartesian3.add(Cesium.Cartesian3.multiplyByScalar(normalize, radius1, new Cesium.Cartesian3()), p1, new Cesium.Cartesian3())
|
const rotate1 = rotatedPointByAngle(centerVectorZ1, p1, -90)
|
const radius2 = Cesium.Cartesian3.distance(p0, p1) / 4 / 3.5 * 2.5
|
const centerVectorZ2 = Cesium.Cartesian3.add(Cesium.Cartesian3.multiplyByScalar(normalize, radius2, new Cesium.Cartesian3()), p1, new Cesium.Cartesian3())
|
const rotate2 = rotatedPointByAngle(centerVectorZ2, p1, -90)
|
|
// 围绕法线旋转点
|
function panSpinZoom (normal, angle, rotater) {
|
const axis = Cesium.Quaternion.fromAxisAngle(normal, Cesium.Math.toRadians(angle)) // 创建旋转四元数
|
const quater = Cesium.Matrix3.fromQuaternion(axis) // 从四元数创建旋转矩阵
|
const fromRotater = Cesium.Matrix4.fromRotationTranslation(quater) // 创建旋转变换矩阵
|
const subtract = Cesium.Cartesian3.subtract(p1, rotater, new Cesium.Cartesian3())
|
const matrix4 = Cesium.Matrix4.multiplyByPoint(fromRotater, subtract, new Cesium.Cartesian3())
|
const matrixPoint = Cesium.Cartesian3.add(matrix4, p1, new Cesium.Cartesian3())
|
return matrixPoint
|
}
|
|
// 绘制圆尺外边
|
let angleList = []
|
for (let angle = 180; angle <= 360; angle += 5) {
|
angleList.push(panSpinZoom(normalize, angle, rotate))
|
}
|
viewer.entities.add({
|
id: 'ruler1',
|
polyline: {
|
positions: angleList,
|
width: 1,
|
arcType: Cesium.ArcType.NONE,
|
material: Cesium.Color.fromCssColorString('#aeff00'),
|
},
|
})
|
|
// 绘制刻度线
|
for (let angle = 180; angle <= 360; angle += 15) {
|
const tick = (angle - 180) / 5
|
viewer.entities.add({
|
id: 'tick' + tick,
|
polyline: {
|
positions: [panSpinZoom(normalize, angle, rotate1), angleList[tick]],
|
width: 1,
|
arcType: Cesium.ArcType.NONE,
|
material: Cesium.Color.fromCssColorString('#aeff00'),
|
},
|
})
|
}
|
|
const vector02 = Cesium.Cartesian3.subtract(angleList[0], angleList[angleList.length - 1], new Cesium.Cartesian3())
|
const cross = Cesium.Cartesian3.cross(vector01, vector02, new Cesium.Cartesian3()) // 计算法向量
|
const normali = Cesium.Cartesian3.normalize(cross, new Cesium.Cartesian3())
|
const plane = Cesium.Plane.fromPointNormal(p1, normali) // 创建平面
|
// 绘制右侧半弧
|
let angleList1 = []
|
for (let angle = 180; angle <= 260; angle += 5) {
|
angleList1.push(panSpinZoom(normalize, angle, rotate2))
|
}
|
|
const projectedPoint = Cesium.Plane.projectPointOntoPlane(plane, angleList1[angleList1.length - 1], new Cesium.Cartesian3()) // 投影点到平面
|
angleList1.push(projectedPoint)
|
viewer.entities.add({
|
id: 'ruler2',
|
polyline: {
|
positions: angleList1,
|
width: 1,
|
arcType: Cesium.ArcType.NONE,
|
material: Cesium.Color.fromCssColorString('#aeff00'),
|
},
|
})
|
|
// 绘制左侧半弧
|
let angleList2 = []
|
for (let angle = 280; angle <= 360; angle += 5) {
|
angleList2.push(panSpinZoom(normalize, angle, rotate2))
|
}
|
const projectedPoint1 = Cesium.Plane.projectPointOntoPlane(plane, angleList2[0], new Cesium.Cartesian3())
|
angleList2.unshift(projectedPoint1)
|
viewer.entities.add({
|
id: 'ruler3',
|
polyline: {
|
positions: angleList2,
|
width: 1,
|
arcType: Cesium.ArcType.NONE,
|
material: Cesium.Color.fromCssColorString('#aeff00'),
|
},
|
})
|
}
|
|
// 求两点的中点
|
function getMidpoint (p1, p2) {
|
return Cesium.Cartesian3.midpoint(p1, p2, new Cesium.Cartesian3())
|
}
|
|
// 创建label标签
|
function createLabel (position, text, isAngle = false, id) {
|
return viewer.entities.add({
|
id,
|
position: new Cesium.CallbackProperty(() => { // 使用CallbackProperty使标签位置动态更新
|
return position
|
}, false),
|
label: {
|
text: text,
|
font: isAngle ? '18px sans-serif' : '14px sans-serif',
|
fillColor: Cesium.Color.WHITE,
|
verticalOrigin: isAngle ? Cesium.VerticalOrigin.TOP : Cesium.VerticalOrigin.BOTTOM, // 垂直原点
|
pixelOffset: new Cesium.Cartesian2(0, isAngle ? 20 : -10), // 像素偏移
|
fillColor: isAngle ? Cesium.Color.fromCssColorString('#b8e065') : Cesium.Color.WHITE,
|
backgroundColor: isAngle ? Cesium.Color.WHITE.withAlpha(0) : Cesium.Color.fromCssColorString('#171719'),
|
showBackground: !isAngle // 是否显示背景
|
}
|
})
|
}
|
|
// 清理label
|
function clearLabels () {
|
[distanceLabel01, distanceLabel12, angleLabel].forEach(label => {
|
if (label) viewer.entities.remove(label)
|
})
|
distanceLabel01 = distanceLabel12 = angleLabel = null
|
}
|
|
// 根据四个顶点计算中心点和法向量
|
function computeCenter (positions) {
|
const centerPosition = new Cesium.Cartesian3()
|
Cesium.Cartesian3.add(positions[0], positions[1], centerPosition)
|
Cesium.Cartesian3.add(positions[2], centerPosition, centerPosition)
|
Cesium.Cartesian3.add(positions[3], centerPosition, centerPosition)
|
const center = Cesium.Cartesian3.multiplyByScalar(centerPosition, 0.25, new Cesium.Cartesian3()) // 计算几何中心
|
const centerPoint1423 = Cesium.Cartesian3.subtract(positions[0], positions[2], new Cesium.Cartesian3())
|
const centerPoint1234 = Cesium.Cartesian3.subtract(positions[1], positions[3], new Cesium.Cartesian3())
|
const centerVector = Cesium.Cartesian3.cross(centerPoint1423, centerPoint1234, new Cesium.Cartesian3()) // 计算法向量
|
return { center, centerVector }
|
}
|
//点围绕中心轴旋转,形成一个圆形轨迹
|
function axisAngleSphere (normalize, centerVector, centerPoint) {
|
let angleList = []
|
for (let i = 0; i < 360; i += 10) {
|
const axis = Cesium.Quaternion.fromAxisAngle(normalize, Cesium.Math.toRadians(i)) // 创建绕法线旋转的四元数
|
const quater = Cesium.Matrix3.fromQuaternion(axis) // 从四元数创建旋转矩阵
|
const fromRotater = Cesium.Matrix4.fromRotationTranslation(quater) // 创建旋转变换矩阵
|
const subtract = Cesium.Cartesian3.subtract(centerVector, centerPoint, new Cesium.Cartesian3()) // 计算从中心点到向量的差值
|
const matrix4 = Cesium.Matrix4.multiplyByPoint(fromRotater, subtract, new Cesium.Cartesian3()) // 应用旋转
|
const matrixPoint = Cesium.Cartesian3.add(matrix4, centerPoint, new Cesium.Cartesian3()) // 将旋转后的向量加回中心点,得到新的点
|
angleList.push(matrixPoint)
|
}
|
angleList.push(angleList[0]) // 闭合圆形
|
return angleList
|
}
|
|
// 旋转一个由四个点定义的平面
|
function axisAnglePlane (positionList) {
|
const subtract = Cesium.Cartesian3.subtract(positionList[0], positionList[1], new Cesium.Cartesian3()) // 计算一条边的向量
|
const normal = Cesium.Cartesian3.normalize(subtract, new Cesium.Cartesian3()) // 归一化该向量作为旋转轴
|
const fromAxisAngle = Cesium.Quaternion.fromAxisAngle(normal, Cesium.Math.toRadians(angletext)) // 创建旋转四元数
|
const fromQuaternion = Cesium.Matrix3.fromQuaternion(fromAxisAngle) // 创建旋转矩阵
|
const fromRotationTranslation = Cesium.Matrix4.fromRotationTranslation(fromQuaternion) // 创建旋转变换矩阵
|
var centerVector1 = Cesium.Cartesian3.subtract(positionList[2], positionList[1], new Cesium.Cartesian3()) // 计算另一条边的向量
|
const multiplyByPoint1 = Cesium.Matrix4.multiplyByPoint(fromRotationTranslation, centerVector1, new Cesium.Cartesian3()) // 旋转该向量
|
var centerVector2 = Cesium.Cartesian3.subtract(positionList[3], positionList[0], new Cesium.Cartesian3()) // 计算对角线向量
|
const multiplyByPoint2 = Cesium.Matrix4.multiplyByPoint(fromRotationTranslation, centerVector2, new Cesium.Cartesian3()) // 旋转该向量
|
const lineList = [positionList[0], positionList[1], Cesium.Cartesian3.add(multiplyByPoint1, positionList[1], new Cesium.Cartesian3()), Cesium.Cartesian3.add(multiplyByPoint2, positionList[0], new Cesium.Cartesian3())] // 返回旋转后的四个顶点
|
return lineList
|
}
|
|
// 交互绘制时使用的变量
|
var activeShapePoints = [] // 激活形状的顶点
|
var floatingPoint // 鼠标移动时的浮动点
|
var activeShape // 激活的形状实体
|
var distanceLabel01, distanceLabel12, angleLabel, distanceLabel23, distanceLabel34 // 距离和角度标签
|
let activePoints = [] // 激活的点
|
let polygonPosition // 多边形位置
|
let polylineEntity // 折线实体
|
let polygonPositionList = [] // 多边形顶点列表
|
let axisPosition = {} // 坐标轴位置
|
let centerPoint // 中心点
|
let axisEntyX, axisEntyY, axisEntyZ, sphereEntyX, sphereEntyY, sphereEntyZ // 坐标轴和球体实体
|
let axisArrowX, axisArrowY, axisArrowZ, axisDashX, axisDashY, axisDashZ, axisSphereX, axisSphereY, axisSphereZ, position, centerVectorZC, centerVectorYC, centerVectorXC // 坐标轴箭头、虚线、球体等实体
|
let dashLineList = [] // 虚线列表
|
let moveDashLine = false // 是否移动虚线标志
|
|
let isDraw = true // 是否处理绘制模式
|
let isEdit = false // 是否处于编辑模式标志
|
let isActivateEdit = false // 是否激活编辑模式
|
let angletext // 角度文本
|
var handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas) // 创建屏幕空间事件处理器
|
|
// 点位创建相关事件
|
handler.setInputAction(function (event) {
|
if (!isDraw) return
|
|
const earthPosition = viewer.scene.pickPosition(event.position) // 获取鼠标点击处的笛卡尔坐标
|
if (!Cesium.defined(earthPosition)) return // 如果未获取到坐标则返回
|
if (activeShapePoints.length === 0) { // 如果是第一个点
|
floatingPoint = earthPosition // 设置浮动点
|
polylineEntity = drawLine(new Cesium.CallbackProperty(() => { // 绘制动态的折线
|
if (!Cesium.defined(floatingPoint)) return [] // 防御代码:确保浮动点有效
|
const activePoints = [...activeShapePoints, floatingPoint]
|
if (activePoints.length >= 3) { // 如果有三个点,则绘制平行四边形
|
const [p0, p1, p2] = activePoints
|
if (!p0 || !p1 || !p2) return [] // 防御代码:确保所有点都有效
|
const vector21 = Cesium.Cartesian3.subtract(p2, p1, new Cesium.Cartesian3())
|
const p3 = Cesium.Cartesian3.add(p0, vector21, new Cesium.Cartesian3())
|
return [p0, p1, p2, p3, p0] // 返回闭合的平行四边形顶点
|
}
|
return activePoints
|
}, false))
|
}
|
const activePoints = [...activeShapePoints, floatingPoint]
|
if (activePoints.length === 2) { // 如果有两个点,创建角度刻度尺
|
const [p0, p1, p2] = activePoints
|
createAngleRuler(p0, p1)
|
}
|
if (activePoints.length >= 3) { // 如果有三个点,则完成绘制
|
const [p0, p1, p2] = activePoints
|
const vector21 = Cesium.Cartesian3.subtract(p2, p1, new Cesium.Cartesian3())
|
const p3 = Cesium.Cartesian3.add(p0, vector21, new Cesium.Cartesian3())
|
createAxisEntity(p0, p1, p2, p3) // 创建坐标轴实体
|
viewer.entities.remove(polylineEntity) // 移除动态折线
|
polygonPosition = [p0, p1, p2, p3] // 保存多边形顶点
|
movePoint() // 初始化移动点的交互
|
removeEntity('ruler') // 移除刻度尺
|
removeEntity('tick') // 移除刻度
|
handler.destroy() // 销毁当前事件处理器
|
polygonPositionList = polygonPosition
|
activeShape = drawShape(polygonPosition) // 绘制最终的形状
|
}
|
activeShapePoints.push(earthPosition) // 将当前点添加到激活点列表
|
updateLabels() // 更新标签
|
if (activePoints.length >= 3) {
|
viewer.entities.remove(viewer.entities.getById('angleLabel')) // 移除角度标签
|
// 计算航线
|
|
faceAirLineTool.setPositionData(polygonPositionList, isActivateEdit, true) // 调用航线计算工具
|
|
isDraw = false
|
|
// isEdit = true
|
}
|
}, Cesium.ScreenSpaceEventType.LEFT_CLICK) // 监听鼠标左键点击事件
|
|
// 清理实体和缓存
|
function clearEntity () {
|
viewer.entities.remove(activeShape) // 移除形状实体
|
activeShapePoints = [] // 清空激活点
|
floatingPoint = null // 清空浮动点
|
}
|
|
handler.setInputAction(function (event) { // 监听鼠标移动事件
|
if (!floatingPoint) return // 如果没有浮动点则返回
|
const newPosition = viewer.scene.pickPosition(event.endPosition) // 获取新的鼠标位置
|
if (!Cesium.defined(newPosition)) return
|
floatingPoint = newPosition // 更新浮动点位置
|
if (activeShapePoints.length >= 2) { // 如果已经有两个点,则在定义的平面上移动
|
const ray = viewer.camera.getPickRay(event.endPosition) // 获取拾取射线
|
if (ray) {
|
const [p0, p1] = activeShapePoints
|
const planeNormal = Cesium.Cartesian3.subtract(p1, p0, new Cesium.Cartesian3()) // 计算平面法线
|
const plane = Cesium.Plane.fromPointNormal(p1, Cesium.Cartesian3.normalize(planeNormal, new Cesium.Cartesian3())) // 创建平面
|
const intersection = Cesium.IntersectionTests.rayPlane(ray, plane) // 计算射线与平面的交点
|
if (intersection) {
|
floatingPoint = intersection // 更新浮动点为交点
|
}
|
}
|
}
|
updateLabels() // 更新标签
|
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
|
|
// 更新label
|
function updateLabels () {
|
clearLabels() // 先清除所有标签
|
const activePoints = [...activeShapePoints, floatingPoint]
|
// 第一点和第二点距离标签
|
if (activePoints.length >= 2) {
|
const middle01 = Cesium.Cartesian3.midpoint(activePoints[0], activePoints[1], new Cesium.Cartesian3()) // 计算中点
|
const distance01 = Cesium.Cartesian3.distance(activePoints[0], activePoints[1]) // 计算距离
|
distanceLabel01 = createLabel(middle01, `${formatDistance(distance01)}`, false, 'distanceLabel01') // 创建距离标签
|
}
|
if (activePoints.length >= 3) {
|
// 第二点和第三点距离标签
|
const middle12 = Cesium.Cartesian3.midpoint(activePoints[1], activePoints[2], new Cesium.Cartesian3())
|
const distance12 = Cesium.Cartesian3.distance(activePoints[1], activePoints[2])
|
distanceLabel12 = createLabel(middle12, `${formatDistance(distance12)}`, false, 'distanceLabel12')
|
// 第三点的角度
|
const rotate = rotatedPointByAngle(activePoints[0], activePoints[1], 90) // 获取一个旋转90度的参考点
|
const vector21 = Cesium.Cartesian3.subtract(activePoints[2], activePoints[1], new Cesium.Cartesian3()) // 计算向量
|
const vectorRotate1 = Cesium.Cartesian3.subtract(rotate, activePoints[1], new Cesium.Cartesian3())
|
const angle = Cesium.Math.toDegrees(Cesium.Cartesian3.angleBetween(vectorRotate1, vector21)) // 计算两个向量之间的角度
|
var cartographic1 = Cesium.Cartographic.fromCartesian(activePoints[1]) // 将笛卡尔坐标转换为地理坐标
|
var cartographic2 = Cesium.Cartographic.fromCartesian(activePoints[2])
|
|
if (cartographic1.height < cartographic2.height) { // 根据高度判断角度的正负
|
angletext = angle
|
polylineEntity.polyline.material = Cesium.Color.fromCssColorString('#2987f0') // 实线
|
} else {
|
polylineEntity.polyline.material = new Cesium.PolylineDashMaterialProperty({ // 虚线
|
color: Cesium.Color.fromCssColorString('#2987f0'),
|
})
|
angletext = 360 - angle
|
}
|
angleLabel = createLabel(activePoints[2], `${angletext.toFixed(1)}°`, true, 'angleLabel') // 创建角度标签
|
}
|
if (activePoints.length >= 4) {
|
// 第三个和第四个点的距离标签
|
const middle23 = Cesium.Cartesian3.midpoint(polygonPosition[2], polygonPosition[3], new Cesium.Cartesian3())
|
const distance23 = Cesium.Cartesian3.distance(polygonPosition[2], polygonPosition[3])
|
distanceLabel23 = createLabel(middle23, `${formatDistance(distance23)}`, false, 'distanceLabel23')
|
const middle34 = Cesium.Cartesian3.midpoint(polygonPosition[3], polygonPosition[0], new Cesium.Cartesian3())
|
const distance34 = Cesium.Cartesian3.distance(polygonPosition[3], polygonPosition[0])
|
distanceLabel34 = createLabel(middle34, `${formatDistance(distance34)}`, false, 'distanceLabel34')
|
}
|
}
|
|
// 创建坐标轴实体(X, Y, Z轴)
|
function createAxisEntity (point1, point2, point3, point4) {
|
removeEntityLikeName(viewer, 'controller')
|
removeEntityLikeName(viewer, 'dashLine')
|
|
const centerPoint14 = getMidpoint(point1, point4)
|
const centerPoint23 = getMidpoint(point2, point3)
|
const centerPoint12 = getMidpoint(point1, point2)
|
const centerPoint34 = getMidpoint(point3, point4)
|
centerPoint = getMidpoint(point1, point3) // 计算中心点
|
|
const distance12 = Cesium.Cartesian3.distance(point2, point3, new Cesium.Cartesian3())
|
const centerPoint1423 = Cesium.Cartesian3.subtract(centerPoint14, centerPoint23, new Cesium.Cartesian3())
|
const centerPoint1234 = Cesium.Cartesian3.subtract(centerPoint12, centerPoint34, new Cesium.Cartesian3())
|
// Z轴
|
const centerVector = Cesium.Cartesian3.cross(centerPoint1423, centerPoint1234, new Cesium.Cartesian3()) // 计算法向量作为Z轴方向
|
const normalizeZ = Cesium.Cartesian3.normalize(centerVector, new Cesium.Cartesian3())
|
const centerVectorZ = Cesium.Cartesian3.add(Cesium.Cartesian3.multiplyByScalar(normalizeZ, distance12 / 2, new Cesium.Cartesian3()), centerPoint, new Cesium.Cartesian3())
|
// X轴
|
const normalizeX = Cesium.Cartesian3.normalize(centerPoint1423, new Cesium.Cartesian3())
|
const centerVectorX = Cesium.Cartesian3.add(centerPoint, Cesium.Cartesian3.multiplyByScalar(normalizeX, -distance12 / 2, new Cesium.Cartesian3()), new Cesium.Cartesian3())
|
// Y轴
|
const normalizeY = Cesium.Cartesian3.normalize(centerPoint1234, new Cesium.Cartesian3())
|
const centerVectorY = Cesium.Cartesian3.add(centerPoint, Cesium.Cartesian3.multiplyByScalar(normalizeY, -distance12 / 2, new Cesium.Cartesian3()), new Cesium.Cartesian3())
|
/////////横轴平移\\\\\\\\\\
|
axisEntyX = viewer.entities.add({
|
name: 'controller',
|
id: 'axisX',
|
polyline: {
|
positions: [centerPoint, centerVectorX],
|
width: 10,
|
arcType: Cesium.ArcType.NONE,
|
material: new Cesium.PolylineArrowMaterialProperty(Cesium.Color.fromCssColorString('#9ed81c')), // 箭头材质
|
},
|
})
|
|
axisEntyY = viewer.entities.add({
|
name: 'controller',
|
id: 'axisY',
|
polyline: {
|
positions: [centerPoint, centerVectorY],
|
width: 10,
|
arcType: Cesium.ArcType.NONE,
|
material: new Cesium.PolylineArrowMaterialProperty(Cesium.Color.fromCssColorString('#ec4346')),
|
},
|
})
|
|
axisEntyZ = viewer.entities.add({
|
name: 'controller',
|
id: 'axisZ',
|
polyline: {
|
positions: [centerPoint, centerVectorZ],
|
width: 10,
|
arcType: Cesium.ArcType.NONE,
|
material: new Cesium.PolylineArrowMaterialProperty(Cesium.Color.fromCssColorString('#47dce4')),
|
},
|
})
|
|
axisPosition['axisX'] = [centerPoint, centerVectorX]
|
axisPosition['axisY'] = [centerPoint, centerVectorY]
|
axisPosition['axisZ'] = [centerPoint, centerVectorZ]
|
|
///////// 虚线
|
const distanceAxis = Cesium.Cartesian3.distance(centerPoint, centerVectorX, new Cesium.Cartesian3())
|
// X轴
|
const multiplyByScalarX = Cesium.Cartesian3.multiplyByScalar(normalizeX, distanceAxis * 2, new Cesium.Cartesian3())
|
const dashLineEndPointX = Cesium.Cartesian3.add(centerPoint, multiplyByScalarX, new Cesium.Cartesian3())
|
const multiplyByScalarX1 = Cesium.Cartesian3.multiplyByScalar(normalizeX, -distanceAxis * 2, new Cesium.Cartesian3())
|
const dashLineEndPointX1 = Cesium.Cartesian3.add(centerPoint, multiplyByScalarX1, new Cesium.Cartesian3())
|
// y轴
|
const multiplyByScalarY = Cesium.Cartesian3.multiplyByScalar(normalizeY, distanceAxis * 2, new Cesium.Cartesian3())
|
const dashLineEndPointY = Cesium.Cartesian3.add(centerPoint, multiplyByScalarY, new Cesium.Cartesian3())
|
const multiplyByScalarY1 = Cesium.Cartesian3.multiplyByScalar(normalizeY, -distanceAxis * 2, new Cesium.Cartesian3())
|
const dashLineEndPointY1 = Cesium.Cartesian3.add(centerPoint, multiplyByScalarY1, new Cesium.Cartesian3())
|
// z轴
|
const multiplyByScalarZ = Cesium.Cartesian3.multiplyByScalar(normalizeZ, distanceAxis * 2, new Cesium.Cartesian3())
|
const dashLineEndPointZ = Cesium.Cartesian3.add(centerPoint, multiplyByScalarZ, new Cesium.Cartesian3())
|
const multiplyByScalarZ1 = Cesium.Cartesian3.multiplyByScalar(normalizeZ, -distanceAxis * 2, new Cesium.Cartesian3())
|
const dashLineEndPointZ1 = Cesium.Cartesian3.add(centerPoint, multiplyByScalarZ1, new Cesium.Cartesian3())
|
|
const dashX = drawDashLine([dashLineEndPointX1, dashLineEndPointX], 'dashX')
|
const dashY = drawDashLine([dashLineEndPointY1, dashLineEndPointY], 'dashY')
|
const dashZ = drawDashLine([dashLineEndPointZ1, dashLineEndPointZ], 'dashZ')
|
dashLineList.push(dashX)
|
dashLineList.push(dashY)
|
dashLineList.push(dashZ)
|
axisPosition['dashX'] = [dashLineEndPointX1, dashLineEndPointX]
|
axisPosition['dashY'] = [dashLineEndPointY1, dashLineEndPointY]
|
axisPosition['dashZ'] = [dashLineEndPointZ1, dashLineEndPointZ]
|
/////////圆轴旋转\\\\\\\\\\
|
// Z圆弧
|
centerVectorZC = Cesium.Cartesian3.subtract(centerVectorZ, centerPoint, new Cesium.Cartesian3())
|
const normalizeZC = Cesium.Cartesian3.normalize(centerVectorZC, new Cesium.Cartesian3())
|
const centerVectorZ1 = Cesium.Cartesian3.add(centerPoint, Cesium.Cartesian3.multiplyByScalar(normalizeX, -distance12 / 3, new Cesium.Cartesian3()), new Cesium.Cartesian3())
|
|
const axisSphereZ = axisAngleSphere(normalizeZC, centerVectorZ1, centerPoint)
|
|
sphereEntyZ = viewer.entities.add({
|
name: 'controller',
|
id: 'sphereZ',
|
polyline: {
|
positions: axisSphereZ,
|
width: 3,
|
arcType: Cesium.ArcType.NONE,
|
material: Cesium.Color.fromCssColorString('#47dce4')
|
},
|
})
|
|
// X圆弧
|
centerVectorXC = Cesium.Cartesian3.subtract(centerPoint14, centerPoint, new Cesium.Cartesian3())
|
var normalize14C = Cesium.Cartesian3.normalize(centerVectorXC, new Cesium.Cartesian3())
|
const centerVectorX1 = Cesium.Cartesian3.add(centerPoint, Cesium.Cartesian3.multiplyByScalar(normalizeY, -distance12 / 3, new Cesium.Cartesian3()), new Cesium.Cartesian3())
|
const axisSphereX = axisAngleSphere(normalize14C, centerVectorX1, centerPoint)
|
|
sphereEntyX = viewer.entities.add({
|
name: 'controller',
|
id: 'sphereX',
|
polyline: {
|
positions: axisSphereX,
|
width: 3,
|
arcType: Cesium.ArcType.NONE,
|
material: Cesium.Color.fromCssColorString('#9ed81c')
|
},
|
})
|
|
// Y圆弧
|
centerVectorYC = Cesium.Cartesian3.subtract(centerPoint12, centerPoint, new Cesium.Cartesian3())
|
var normalize12C = Cesium.Cartesian3.normalize(centerVectorYC, new Cesium.Cartesian3())
|
const centerVectorZZC = Cesium.Cartesian3.add(centerPoint, Cesium.Cartesian3.multiplyByScalar(normalizeZ, -distance12 / 3, new Cesium.Cartesian3()), new Cesium.Cartesian3())
|
const axisSphereY = axisAngleSphere(normalize12C, centerVectorZZC, centerPoint)
|
|
sphereEntyY = viewer.entities.add({
|
name: 'controller',
|
id: 'sphereY',
|
polyline: {
|
positions: axisSphereY,
|
width: 3,
|
arcType: Cesium.ArcType.NONE,
|
material: Cesium.Color.fromCssColorString('#ec4346')
|
},
|
})
|
|
axisPosition['sphereX'] = axisSphereX
|
axisPosition['sphereY'] = axisSphereY
|
axisPosition['sphereZ'] = axisSphereZ
|
// 创建轴实体
|
changeAxisEntity()
|
}
|
|
|
class RotationController {
|
constructor() {
|
this.state = {
|
isRotating: false,
|
currentAxis: null,
|
rotationPlane: null,
|
lastProjectedPoint: null,
|
accumulatedAngle: 0
|
}
|
|
// 绑定方法以确保正确的this上下文
|
this.startRotation = this.startRotation.bind(this)
|
this.updateRotation = this.updateRotation.bind(this)
|
this.endRotation = this.endRotation.bind(this)
|
}
|
|
// 开始旋转
|
startRotation (pick, centerPoint) {
|
const axis = this.getAxisFromPick(pick)
|
|
if (!axis) {
|
return false
|
}
|
|
this.state.isRotating = true
|
this.state.currentAxis = axis
|
this.state.rotationPlane = this.createRotationPlane(centerPoint, axis)
|
this.state.accumulatedAngle = 0
|
this.state.lastProjectedPoint = null
|
|
return true
|
}
|
// 根据pick确定旋转轴
|
getAxisFromPick (pick) {
|
if (!pick || !pick.id) {
|
return null
|
}
|
|
const id = pick.id.id
|
|
if (id === 'sphereX') return 'x'
|
if (id === 'sphereY') return 'y'
|
if (id === 'sphereZ') return 'z'
|
|
return null
|
}
|
|
// 创建旋转平面(垂直于旋转轴)
|
createRotationPlane (centerPoint, axis) {
|
let normal
|
|
try {
|
switch (axis) {
|
case 'x':
|
if (!centerVectorXC) {
|
return null
|
}
|
normal = Cesium.Cartesian3.normalize(centerVectorXC, new Cesium.Cartesian3())
|
break
|
case 'y':
|
if (!centerVectorYC) {
|
return null
|
}
|
normal = Cesium.Cartesian3.normalize(centerVectorYC, new Cesium.Cartesian3())
|
break
|
case 'z':
|
if (!centerVectorZC) {
|
return null
|
}
|
normal = Cesium.Cartesian3.normalize(centerVectorZC, new Cesium.Cartesian3())
|
break
|
default:
|
console.error('Unknown axis:', axis)
|
return null
|
}
|
|
// 确保法向量是单位向量
|
Cesium.Cartesian3.normalize(normal, normal)
|
|
const plane = Cesium.Plane.fromPointNormal(centerPoint, normal)
|
|
return plane
|
|
} catch (error) {
|
return null
|
}
|
}
|
|
// 在RotationController中添加调试方法
|
updateRotation (mousePosition, centerPoint) {
|
if (!this.state.isRotating || !this.state.rotationPlane) {
|
return 0
|
}
|
|
// 将鼠标位置投影到旋转平面
|
const projectedPoint = this.projectMouseToPlane(mousePosition, this.state.rotationPlane)
|
|
if (!projectedPoint) {
|
return 0
|
}
|
|
// 如果是第一次投影,只记录位置不计算角度
|
if (!this.state.lastProjectedPoint) {
|
this.state.lastProjectedPoint = projectedPoint
|
return 0
|
}
|
|
// 计算角度变化
|
const angleDelta = this.calculateAngleDelta(
|
this.state.lastProjectedPoint,
|
projectedPoint,
|
centerPoint,
|
this.state.currentAxis
|
)
|
|
this.state.accumulatedAngle += angleDelta
|
this.state.lastProjectedPoint = projectedPoint
|
|
return angleDelta
|
}
|
|
// 增强投影方法的调试
|
projectMouseToPlane (mousePosition, plane) {
|
const ray = viewer.camera.getPickRay(mousePosition)
|
if (!ray) {
|
return null
|
}
|
|
const intersection = Cesium.IntersectionTests.rayPlane(ray, plane)
|
|
return intersection
|
}
|
|
// 计算两点相对于中心点的角度变化
|
calculateAngleDelta (pointA, pointB, centerPoint, axis) {
|
// 检查点是否有效
|
if (!pointA || !pointB || !centerPoint) {
|
return 0
|
}
|
|
// 创建从中心点到两点的向量
|
const vectorA = Cesium.Cartesian3.subtract(pointA, centerPoint, new Cesium.Cartesian3())
|
const vectorB = Cesium.Cartesian3.subtract(pointB, centerPoint, new Cesium.Cartesian3())
|
|
// 检查向量长度,避免除零
|
const lengthA = Cesium.Cartesian3.magnitude(vectorA)
|
const lengthB = Cesium.Cartesian3.magnitude(vectorB)
|
|
if (lengthA < 1e-10 || lengthB < 1e-10) {
|
return 0
|
}
|
|
// 归一化向量
|
Cesium.Cartesian3.normalize(vectorA, vectorA)
|
Cesium.Cartesian3.normalize(vectorB, vectorB)
|
|
// 计算点积
|
const dot = Cesium.Cartesian3.dot(vectorA, vectorB)
|
|
// 处理浮点精度问题
|
const clampedDot = Cesium.Math.clamp(dot, -1.0, 1.0)
|
const angle = Math.acos(clampedDot)
|
|
// 如果角度很小,直接返回0避免抖动
|
if (angle < 1e-5) {
|
return 0
|
}
|
|
// 确定旋转方向
|
const cross = Cesium.Cartesian3.cross(vectorA, vectorB, new Cesium.Cartesian3())
|
const axisVector = this.getAxisVector(axis)
|
|
// 归一化轴向量
|
Cesium.Cartesian3.normalize(axisVector, axisVector)
|
|
const direction = Cesium.Cartesian3.dot(cross, axisVector) >= 0 ? 1 : -1
|
|
const degrees = Cesium.Math.toDegrees(angle) * direction
|
|
return degrees
|
}
|
|
// 获取轴的方向向量
|
getAxisVector (axis) {
|
switch (axis) {
|
case 'x': return Cesium.Cartesian3.normalize(centerVectorXC, new Cesium.Cartesian3())
|
case 'y': return Cesium.Cartesian3.normalize(centerVectorYC, new Cesium.Cartesian3())
|
case 'z': return Cesium.Cartesian3.normalize(centerVectorZC, new Cesium.Cartesian3())
|
default: return new Cesium.Cartesian3(0, 0, 1)
|
}
|
}
|
|
endRotation () {
|
const finalAngle = this.state.accumulatedAngle
|
this.state.isRotating = false
|
this.state.lastProjectedPoint = null
|
this.state.rotationPlane = null
|
this.state.currentAxis = null
|
this.state.accumulatedAngle = 0
|
|
return finalAngle
|
}
|
}
|
|
// 绕指定轴旋转平面
|
function rotatePlaneByAxis (angle, axis) {
|
let normal
|
switch (axis) {
|
case 'x': normal = Cesium.Cartesian3.normalize(centerVectorXC, new Cesium.Cartesian3()); break
|
case 'y': normal = Cesium.Cartesian3.normalize(centerVectorYC, new Cesium.Cartesian3()); break
|
case 'z': normal = Cesium.Cartesian3.normalize(centerVectorZC, new Cesium.Cartesian3()); break
|
}
|
|
const quaternion = Cesium.Quaternion.fromAxisAngle(normal, Cesium.Math.toRadians(angle))
|
const rotationMatrix = Cesium.Matrix3.fromQuaternion(quaternion)
|
const transformMatrix = Cesium.Matrix4.fromRotationTranslation(rotationMatrix)
|
|
// 旋转所有顶点
|
polygonPositionList = polygonPositionList.map(point => {
|
const translated = Cesium.Cartesian3.subtract(point, centerPoint, new Cesium.Cartesian3())
|
const rotated = Cesium.Matrix4.multiplyByPoint(transformMatrix, translated, new Cesium.Cartesian3())
|
return Cesium.Cartesian3.add(rotated, centerPoint, new Cesium.Cartesian3())
|
})
|
|
// 更新形状
|
activeShape.polygon.hierarchy = new Cesium.CallbackProperty(() => {
|
return new Cesium.PolygonHierarchy(polygonPositionList)
|
}, false)
|
}
|
|
// 创建旋转控制器实例
|
const rotationController = new RotationController()
|
|
class TranslationController {
|
constructor() {
|
this.state = {
|
isTranslating: false,
|
currentAxis: null,
|
translationLine: null,
|
lastProjectedPoint: null,
|
accumulatedDistance: 0,
|
startPoint: null
|
}
|
|
this.startTranslation = this.startTranslation.bind(this)
|
this.updateTranslation = this.updateTranslation.bind(this)
|
this.endTranslation = this.endTranslation.bind(this)
|
}
|
|
// 开始平移
|
startTranslation (pick, centerPoint) {
|
const axis = this.getAxisFromPick(pick)
|
if (!axis) {
|
return false
|
}
|
|
this.state.startProjectedPoint = null
|
this.state.isTranslating = true
|
this.state.currentAxis = axis
|
this.state.translationLine = this.createTranslationLine(centerPoint, axis)
|
this.state.accumulatedDistance = 0
|
this.state.lastProjectedPoint = null
|
this.state.startPoint = centerPoint
|
|
return true
|
}
|
|
// 根据pick确定平移轴
|
getAxisFromPick (pick) {
|
if (!pick || !pick.id) {
|
return null
|
}
|
|
const id = pick.id.id
|
if (id === 'axisX') return 'x'
|
if (id === 'axisY') return 'y'
|
if (id === 'axisZ') return 'z'
|
|
return null
|
}
|
|
// 创建平移线(而不是平面)
|
createTranslationLine (centerPoint, axis) {
|
let axisVector
|
let lineEndPoint
|
|
// 获取轴的方向向量和端点
|
switch (axis) {
|
case 'x':
|
axisVector = Cesium.Cartesian3.normalize(centerVectorXC, new Cesium.Cartesian3())
|
lineEndPoint = axisPosition['axisX'][1] // 使用轴箭头的端点
|
break
|
case 'y':
|
axisVector = Cesium.Cartesian3.normalize(centerVectorYC, new Cesium.Cartesian3())
|
lineEndPoint = axisPosition['axisY'][1]
|
break
|
case 'z':
|
axisVector = Cesium.Cartesian3.normalize(centerVectorZC, new Cesium.Cartesian3())
|
lineEndPoint = axisPosition['axisZ'][1]
|
break
|
default:
|
return null
|
}
|
|
return {
|
axisVector: axisVector,
|
lineEndPoint: lineEndPoint,
|
centerPoint: centerPoint
|
}
|
}
|
|
// 更新平移 - 使用更直接的方法
|
updateTranslation (mousePosition, centerPoint) {
|
if (!this.state.isTranslating || !this.state.translationLine) {
|
return 0
|
}
|
|
const { axisVector } = this.state.translationLine
|
|
// 创建一个包含平移轴的平面,法向量垂直于轴和相机方向
|
const cameraDirection = viewer.camera.direction
|
let planeNormal = Cesium.Cartesian3.cross(axisVector, cameraDirection, new Cesium.Cartesian3())
|
|
// 如果叉积接近零,使用备用法向量
|
if (Cesium.Cartesian3.magnitude(planeNormal) < 1e-10) {
|
// 找一个与轴垂直的向量
|
if (Math.abs(axisVector.x) > 0.9) {
|
planeNormal = Cesium.Cartesian3.UNIT_Y
|
} else {
|
planeNormal = Cesium.Cartesian3.UNIT_X
|
}
|
}
|
|
Cesium.Cartesian3.normalize(planeNormal, planeNormal)
|
const plane = Cesium.Plane.fromPointNormal(centerPoint, planeNormal)
|
|
// 将鼠标位置投影到平面
|
const projectedPoint = this.projectMouseToPlane(mousePosition, plane)
|
if (!projectedPoint) {
|
return 0
|
}
|
|
// 如果是第一次投影,记录初始位置
|
if (!this.state.startProjectedPoint) {
|
this.state.startProjectedPoint = projectedPoint
|
this.state.lastProjectedPoint = projectedPoint
|
return 0
|
}
|
|
// 计算当前投影点和上一个投影点相对于轴的位置
|
const vectorToCurrent = Cesium.Cartesian3.subtract(projectedPoint, centerPoint, new Cesium.Cartesian3())
|
const vectorToLast = Cesium.Cartesian3.subtract(this.state.lastProjectedPoint, centerPoint, new Cesium.Cartesian3())
|
|
// 计算这两个向量在轴方向上的投影长度
|
const currentDistance = Cesium.Cartesian3.dot(vectorToCurrent, axisVector)
|
const lastDistance = Cesium.Cartesian3.dot(vectorToLast, axisVector)
|
|
// 距离变化量
|
const distanceDelta = currentDistance - lastDistance
|
|
this.state.accumulatedDistance += distanceDelta
|
this.state.lastProjectedPoint = projectedPoint
|
|
console.log('Translation delta:', distanceDelta, 'Accumulated:', this.state.accumulatedDistance)
|
|
return distanceDelta
|
}
|
|
// 获取轴的方向向量
|
getAxisVector (axis) {
|
switch (axis) {
|
case 'x':
|
return Cesium.Cartesian3.normalize(centerVectorXC, new Cesium.Cartesian3())
|
case 'y':
|
return Cesium.Cartesian3.normalize(centerVectorYC, new Cesium.Cartesian3())
|
case 'z':
|
return Cesium.Cartesian3.normalize(centerVectorZC, new Cesium.Cartesian3())
|
default:
|
return new Cesium.Cartesian3(0, 0, 1)
|
}
|
}
|
|
// 投影鼠标位置到平面
|
projectMouseToPlane (mousePosition, plane) {
|
const ray = viewer.camera.getPickRay(mousePosition)
|
if (!ray) {
|
return null
|
}
|
|
const intersection = Cesium.IntersectionTests.rayPlane(ray, plane)
|
return intersection
|
}
|
|
// 结束平移
|
endTranslation () {
|
const finalDistance = this.state.accumulatedDistance
|
this.state.startProjectedPoint = null
|
this.state.isTranslating = false
|
this.state.lastProjectedPoint = null
|
this.state.translationLine = null
|
this.state.currentAxis = null
|
this.state.accumulatedDistance = 0
|
this.state.startPoint = null
|
this.state.lastMousePosition = null
|
|
return finalDistance
|
}
|
}
|
|
// 平移平面
|
function translatePlaneByAxis (distance, axis) {
|
let translationVector
|
let axisVector
|
|
// 根据轴选择平移方向和向量
|
switch (axis) {
|
case 'x':
|
axisVector = Cesium.Cartesian3.normalize(centerVectorXC, new Cesium.Cartesian3())
|
break
|
case 'y':
|
axisVector = Cesium.Cartesian3.normalize(centerVectorYC, new Cesium.Cartesian3())
|
break
|
case 'z':
|
axisVector = Cesium.Cartesian3.normalize(centerVectorZC, new Cesium.Cartesian3())
|
break
|
default:
|
console.error("Unknown axis for translation:", axis)
|
return
|
}
|
|
// 添加距离缩放,使移动更加明显
|
const scaledDistance = distance // 调整这个系数来改变移动灵敏度
|
|
// 创建平移向量
|
translationVector = Cesium.Cartesian3.multiplyByScalar(axisVector, scaledDistance, new Cesium.Cartesian3())
|
|
// 更新所有相关实体的位置
|
polygonPositionList = polygonPositionList.map((point) => {
|
return Cesium.Cartesian3.add(point, translationVector, new Cesium.Cartesian3())
|
})
|
|
// 更新中心点
|
centerPoint = Cesium.Cartesian3.add(centerPoint, translationVector, new Cesium.Cartesian3())
|
|
// 更新形状的位置
|
activeShape.polygon.hierarchy = new Cesium.CallbackProperty(() => {
|
return new Cesium.PolygonHierarchy(polygonPositionList)
|
}, false)
|
}
|
// 创建旋转控制器实例
|
const translationController = new TranslationController()
|
|
|
const handler2 = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
|
const handler3 = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
|
let masterController = null
|
// 平移旋转XYZ轴
|
function changeAxisEntity () {
|
let moveHandler, upHandler
|
let isHandling = false
|
|
masterController && masterController.destroy()
|
masterController = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
|
|
masterController.setInputAction((e) => {
|
if (isHandling) return
|
|
const pick = viewer.scene.pick(e.position)
|
if (!Cesium.defined(pick) || !pick.id) return
|
|
const id = pick.id.id
|
if (id === 'polygon' || !axisPosition[id]) return
|
|
// 鼠标按下开始的位置坐标信息
|
const pickStartX = e.position.x
|
const pickStartY = e.position.y
|
|
moveDashLine = true
|
viewer.scene.screenSpaceCameraController.enableRotate = false
|
polygonPosition = polygonPositionList
|
|
let isRotation = false
|
let isTranslation = false
|
|
// 旋转处理
|
if (id.slice(0, 6) === 'sphere') {
|
if (rotationController.startRotation(pick, centerPoint)) {
|
isRotation = true
|
isHandling = true
|
}
|
}
|
// 平移处理
|
else if (id.slice(0, 4) === 'axis') {
|
if (translationController.startTranslation(pick, centerPoint)) {
|
isHandling = true
|
isTranslation = true
|
|
// 记录初始鼠标位置
|
translationController.state.lastMousePosition = new Cesium.Cartesian2(e.position.x, e.position.y)
|
}
|
}
|
|
if (!isRotation && !isTranslation) return
|
|
// 设置鼠标移动事件
|
moveHandler = viewer.screenSpaceEventHandler.setInputAction((movement) => {
|
const mousePosition = new Cesium.Cartesian2(movement.endPosition.x, movement.endPosition.y)
|
|
if (isRotation) {
|
const angleDelta = rotationController.updateRotation(mousePosition, centerPoint)
|
console.log('Rotation angleDelta:', angleDelta)
|
|
if (Math.abs(angleDelta) > 0.1) {
|
rotatePlaneByAxis(angleDelta, rotationController.state.currentAxis)
|
}
|
}
|
else if (isTranslation) {
|
const distanceDelta = translationController.updateTranslation(mousePosition, centerPoint)
|
console.log('Translation distanceDelta:', distanceDelta)
|
|
// 降低阈值,使移动更敏感
|
if (Math.abs(distanceDelta) > 0.01) {
|
translatePlaneByAxis(distanceDelta, translationController.state.currentAxis)
|
}
|
}
|
|
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
|
|
// 设置鼠标抬起事件
|
upHandler = viewer.screenSpaceEventHandler.setInputAction((upEvent) => {
|
cleanup()
|
}, Cesium.ScreenSpaceEventType.LEFT_UP)
|
|
// 清理函数
|
const cleanup = () => {
|
if (moveHandler) {
|
viewer.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE)
|
moveHandler = null
|
}
|
if (upHandler) {
|
viewer.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_UP)
|
upHandler = null
|
}
|
|
// 显示所有轴实体
|
axisEntyX.show = true
|
axisEntyY.show = true
|
axisEntyZ.show = true
|
sphereEntyX.show = true
|
sphereEntyY.show = true
|
sphereEntyZ.show = true
|
|
moveDashLine = false
|
viewer.scene.screenSpaceCameraController.enableRotate = true
|
|
// 结束控制器操作
|
if (isRotation) {
|
rotationController.endRotation()
|
}
|
if (isTranslation) {
|
translationController.endTranslation()
|
}
|
|
// 更新数据
|
faceAirLineTool.setPositionData(polygonPositionList, isActivateEdit, true)
|
createAxisEntity(...polygonPositionList)
|
|
isHandling = false
|
isRotation = false
|
isTranslation = false
|
}
|
|
}, Cesium.ScreenSpaceEventType.LEFT_DOWN)
|
}
|
|
// 双击激活面编辑,可以进行点位拖拽
|
handler2.setInputAction((click) => {
|
const pickC = viewer.scene.pick(click.position)
|
|
removeEntityLikeName(viewer, 'polygonEditPoint')
|
|
if (Cesium.defined(pickC) && pickC.id) {
|
// isEdit = true
|
} else {
|
isEdit = false
|
}
|
|
if (!isEdit) return
|
|
const positions = polygonPositionList
|
positions.forEach((ele, index) => {
|
const entity = viewer.entities.add({
|
name: 'polygonEditPoint',
|
id: "point" + index,
|
position: ele,
|
point: {
|
color: new Cesium.Color(0, 1, 1, 0.9),
|
pixelSize: 10
|
},
|
})
|
})
|
isActivateEdit = true
|
|
handler3.setInputAction((e) => {
|
let center, centerVector
|
const pick = viewer.scene.pick(e.position)
|
if (Cesium.defined(pick)) {
|
if (!pick.id) return
|
if (pick?.id?.id.slice(0, 5) === 'point') {
|
let pointEntity = pick.id
|
let indexx = pick?.id?.id.slice(5)
|
viewer.scene.screenSpaceCameraController.enableRotate = false
|
viewer.screenSpaceEventHandler.setInputAction((arg) => {
|
const ray = viewer.camera.getPickRay(arg.endPosition)
|
|
if (ray) {
|
const point = computeCenter(positions)
|
center = point.center
|
centerVector = point.centerVector
|
const plane = Cesium.Plane.fromPointNormal(center, Cesium.Cartesian3.normalize(centerVector, new Cesium.Cartesian3()))
|
const intersection = Cesium.IntersectionTests.rayPlane(ray, plane)
|
positions[Number(indexx)] = intersection
|
pointEntity.position = new Cesium.CallbackProperty(() => {
|
return intersection
|
}, false)
|
|
if (Number(indexx) === 0) {
|
distanceLabel01.position = new Cesium.CallbackProperty(() => {
|
return Cesium.Cartesian3.midpoint(positions[Number(indexx) + 1], positions[Number(indexx)], new Cesium.Cartesian3())
|
}, false)
|
distanceLabel01.label.text = new Cesium.CallbackProperty(() => {
|
const distance12 = Cesium.Cartesian3.distance(positions[Number(indexx) + 1], positions[Number(indexx)], new Cesium.Cartesian3())
|
return `${formatDistance(distance12)}`
|
}, false)
|
distanceLabel34.position = new Cesium.CallbackProperty(() => {
|
return Cesium.Cartesian3.midpoint(positions[Number(indexx) + 3], positions[Number(indexx)], new Cesium.Cartesian3())
|
}, false)
|
distanceLabel34.label.text = new Cesium.CallbackProperty(() => {
|
const distance12 = Cesium.Cartesian3.distance(positions[Number(indexx) + 3], positions[Number(indexx)], new Cesium.Cartesian3())
|
return `${formatDistance(distance12)}`
|
}, false)
|
}
|
|
if (Number(indexx) === 1) {
|
distanceLabel01.position = new Cesium.CallbackProperty(() => {
|
return Cesium.Cartesian3.midpoint(positions[Number(indexx) + 1], positions[Number(indexx)], new Cesium.Cartesian3())
|
}, false)
|
distanceLabel01.label.text = new Cesium.CallbackProperty(() => {
|
const distance12 = Cesium.Cartesian3.distance(positions[Number(indexx) + 1], positions[Number(indexx)], new Cesium.Cartesian3())
|
return `${formatDistance(distance12)}`
|
}, false)
|
distanceLabel12.position = new Cesium.CallbackProperty(() => {
|
return Cesium.Cartesian3.midpoint(positions[Number(indexx) - 1], positions[Number(indexx)], new Cesium.Cartesian3())
|
}, false)
|
distanceLabel12.label.text = new Cesium.CallbackProperty(() => {
|
const distance12 = Cesium.Cartesian3.distance(positions[Number(indexx) - 1], positions[Number(indexx)], new Cesium.Cartesian3())
|
return `${formatDistance(distance12)}`
|
}, false)
|
}
|
|
if (Number(indexx) === 2) {
|
distanceLabel12.position = new Cesium.CallbackProperty(() => {
|
return Cesium.Cartesian3.midpoint(positions[Number(indexx) - 1], positions[Number(indexx)], new Cesium.Cartesian3())
|
}, false)
|
distanceLabel12.label.text = new Cesium.CallbackProperty(() => {
|
const distance12 = Cesium.Cartesian3.distance(positions[Number(indexx) - 1], positions[Number(indexx)], new Cesium.Cartesian3())
|
return `${formatDistance(distance12)}`
|
}, false)
|
distanceLabel23.position = new Cesium.CallbackProperty(() => {
|
return Cesium.Cartesian3.midpoint(positions[Number(indexx) + 1], positions[Number(indexx)], new Cesium.Cartesian3())
|
}, false)
|
distanceLabel23.label.text = new Cesium.CallbackProperty(() => {
|
const distance12 = Cesium.Cartesian3.distance(positions[Number(indexx) + 1], positions[Number(indexx)], new Cesium.Cartesian3())
|
return `${formatDistance(distance12)}`
|
}, false)
|
}
|
|
if (Number(indexx) === 3) {
|
distanceLabel34.position = new Cesium.CallbackProperty(() => {
|
return Cesium.Cartesian3.midpoint(positions[Number(indexx) - 3], positions[Number(indexx)], new Cesium.Cartesian3())
|
}, false)
|
distanceLabel34.label.text = new Cesium.CallbackProperty(() => {
|
const distance12 = Cesium.Cartesian3.distance(positions[Number(indexx) - 3], positions[Number(indexx)], new Cesium.Cartesian3())
|
return `${formatDistance(distance12)}`
|
}, false)
|
distanceLabel23.position = new Cesium.CallbackProperty(() => {
|
return Cesium.Cartesian3.midpoint(positions[Number(indexx) - 1], positions[Number(indexx)], new Cesium.Cartesian3())
|
}, false)
|
distanceLabel23.label.text = new Cesium.CallbackProperty(() => {
|
const distance12 = Cesium.Cartesian3.distance(positions[Number(indexx) - 1], positions[Number(indexx)], new Cesium.Cartesian3())
|
return `${formatDistance(distance12)}`
|
}, false)
|
}
|
|
activeShape.polygon.hierarchy = new Cesium.CallbackProperty(() => {
|
return new Cesium.PolygonHierarchy(positions)
|
}, false)
|
|
const distance = Cesium.Cartesian3.distance(center, centerPoint, new Cesium.Cartesian3())
|
const lineAxis = Cesium.Cartesian3.subtract(center, centerPoint, new Cesium.Cartesian3())
|
const normalize = Cesium.Cartesian3.normalize(lineAxis, new Cesium.Cartesian3())
|
const multiplyByScalar = Cesium.Cartesian3.multiplyByScalar(normalize, distance, new Cesium.Cartesian3())
|
|
// XYZ轴平移
|
axisArrowX = axisPosition['axisX'].map(ele => {
|
return Cesium.Cartesian3.add(ele, multiplyByScalar, new Cesium.Cartesian3())
|
})
|
|
axisArrowY = axisPosition['axisY'].map(ele => {
|
return Cesium.Cartesian3.add(ele, multiplyByScalar, new Cesium.Cartesian3())
|
})
|
|
axisArrowZ = axisPosition['axisZ'].map(ele => {
|
return Cesium.Cartesian3.add(ele, multiplyByScalar, new Cesium.Cartesian3())
|
})
|
|
axisEntyX.polyline.positions = new Cesium.CallbackProperty(() => {
|
return axisArrowX
|
}, false)
|
|
axisEntyY.polyline.positions = new Cesium.CallbackProperty(() => {
|
return axisArrowY
|
}, false)
|
|
axisEntyZ.polyline.positions = new Cesium.CallbackProperty(() => {
|
return axisArrowZ
|
}, false)
|
|
// XYZ轴旋转
|
axisSphereX = axisPosition['sphereX'].map(ele => {
|
return Cesium.Cartesian3.add(ele, multiplyByScalar, new Cesium.Cartesian3())
|
})
|
|
axisSphereY = axisPosition['sphereY'].map(ele => {
|
return Cesium.Cartesian3.add(ele, multiplyByScalar, new Cesium.Cartesian3())
|
})
|
|
axisSphereZ = axisPosition['sphereZ'].map(ele => {
|
return Cesium.Cartesian3.add(ele, multiplyByScalar, new Cesium.Cartesian3())
|
})
|
|
sphereEntyX.polyline.positions = new Cesium.CallbackProperty(() => {
|
return axisSphereX
|
}, false)
|
|
sphereEntyY.polyline.positions = new Cesium.CallbackProperty(() => {
|
return axisSphereY
|
}, false)
|
|
sphereEntyZ.polyline.positions = new Cesium.CallbackProperty(() => {
|
return axisSphereZ
|
}, false)
|
|
// XYZ虚线平移
|
axisDashX = axisPosition['dashX'].map(ele => {
|
return Cesium.Cartesian3.add(ele, multiplyByScalar, new Cesium.Cartesian3())
|
})
|
|
axisDashY = axisPosition['dashY'].map(ele => {
|
return Cesium.Cartesian3.add(ele, multiplyByScalar, new Cesium.Cartesian3())
|
})
|
|
axisDashZ = axisPosition['dashZ'].map(ele => {
|
return Cesium.Cartesian3.add(ele, multiplyByScalar, new Cesium.Cartesian3())
|
})
|
|
dashLineList[0].polyline.positions = new Cesium.CallbackProperty(() => {
|
return axisDashX
|
}, false)
|
|
dashLineList[1].polyline.positions = new Cesium.CallbackProperty(() => {
|
return axisDashY
|
}, false)
|
|
dashLineList[2].polyline.positions = new Cesium.CallbackProperty(() => {
|
return axisDashZ
|
}, false)
|
}
|
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
|
|
viewer.screenSpaceEventHandler.setInputAction(({ position }) => {
|
viewer.scene.screenSpaceCameraController.enableRotate = true
|
axisPosition['axisX'] = axisArrowX
|
axisPosition['axisY'] = axisArrowY
|
axisPosition['axisZ'] = axisArrowZ
|
axisPosition['sphereX'] = axisSphereX
|
axisPosition['sphereY'] = axisSphereY
|
axisPosition['sphereZ'] = axisSphereZ
|
axisPosition['dashX'] = axisDashX
|
axisPosition['dashY'] = axisDashY
|
axisPosition['dashZ'] = axisDashZ
|
centerVectorXC = Cesium.Cartesian3.subtract(axisArrowX[1], axisArrowX[0], new Cesium.Cartesian3())
|
centerVectorYC = Cesium.Cartesian3.subtract(axisArrowY[1], axisArrowY[0], new Cesium.Cartesian3())
|
centerVectorZC = Cesium.Cartesian3.subtract(axisArrowZ[1], axisArrowZ[0], new Cesium.Cartesian3())
|
centerPoint = center
|
polygonPosition = positions
|
faceAirLineTool.setPositionData(polygonPosition, isActivateEdit, true)
|
viewer.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE)
|
}, Cesium.ScreenSpaceEventType.LEFT_UP)
|
}
|
};
|
}, Cesium.ScreenSpaceEventType.LEFT_DOWN)
|
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
|
|
// 移动到轴上后发亮变大
|
function movePoint () {
|
const handler4 = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
|
handler4.setInputAction((arg) => {
|
const pick = viewer.scene.pick(arg.endPosition)
|
if (pick && !moveDashLine) {
|
if (pick.id && pick?.id?.id !== 'polygon' && pick?.id?.id.slice(0, 5) !== 'point' && pick?.id?.id.slice(0, 4) !== 'dash') {
|
moveLight(pick)
|
} else {
|
dashLineList.forEach(ele => {
|
ele.show = false
|
})
|
}
|
}
|
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
|
// handler4.setInputAction(() => {
|
// viewer.entities.removeAll()
|
// masterController.destroy()
|
// handler2.destroy()
|
// handler3.destroy()
|
// handler4.destroy()
|
// createUAVChannelPlane()
|
// }, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
|
}
|
|
function moveLight (pick) {
|
// 变大
|
axisEntyZ.polyline.width = new Cesium.CallbackProperty(() => {
|
return pick ? pick?.id?.id === 'axisZ' ? 15 : 10 : 10
|
}, false)
|
|
axisEntyX.polyline.width = new Cesium.CallbackProperty(() => {
|
return pick ? pick?.id?.id === 'axisX' ? 15 : 10 : 10
|
}, false)
|
|
axisEntyY.polyline.width = new Cesium.CallbackProperty(() => {
|
return pick ? pick?.id?.id === 'axisY' ? 15 : 10 : 10
|
}, false)
|
|
sphereEntyX.polyline.width = new Cesium.CallbackProperty(() => {
|
return pick ? pick?.id?.id === 'sphereX' ? 6 : 3 : 3
|
}, false)
|
|
sphereEntyY.polyline.width = new Cesium.CallbackProperty(() => {
|
return pick ? pick?.id?.id === 'sphereY' ? 6 : 3 : 3
|
}, false)
|
|
sphereEntyZ.polyline.width = new Cesium.CallbackProperty(() => {
|
return pick ? pick?.id?.id === 'sphereZ' ? 6 : 3 : 3
|
}, false)
|
|
let entityId = pick?.id?.id
|
let lineAxis
|
dashLineList.forEach(ele => {
|
if (entityId === 'axisZ') {
|
ele.show = ele.id === 'dashZ'
|
} else if (entityId === 'axisX') {
|
ele.show = ele.id === 'dashX'
|
} else if (entityId === 'axisY') {
|
ele.show = ele.id === 'dashY'
|
}
|
})
|
}
|
|
}
|
|
const drawing = () => {
|
createUAVChannelPlane()
|
}
|
|
function getCameraParams (type) {
|
if (!type) return
|
if (type.length == 0) return
|
let params = {}
|
if (type == CmaeraType.M3D) {
|
//M3D没有红外相机
|
params = {
|
pitchAngle: { // 云台俯仰角
|
min: -120,
|
max: 45,
|
default: 0
|
},
|
zoom: { // 变焦
|
max: 200,
|
min: 2,
|
default: 5
|
},
|
wide: {
|
//广角相机
|
fov: 84, //视角°
|
foc: 10.3, //焦距 mm (等效焦距24,实际焦距10.3)
|
width: 17.3, //传感器物理尺寸宽度 mm
|
halo: '2.8-11', //光圈
|
imgWidth: 5280, //图像尺寸
|
imgHeight: 3956, //图像尺寸
|
maxSize: '5280x3956' //最大图片尺寸
|
},
|
longFocus: {
|
//长焦相机
|
fov: 15, //视角°
|
foc: 162, //焦距mm
|
width: 6.4, //传感器物理尺寸宽度 mm
|
halo: '4.4', //光圈
|
imgWidth: 4000, //图像尺寸
|
imgHeight: 3000, //图像尺寸
|
maxSize: '4000x3000' //最大图片尺寸
|
}
|
}
|
} else if (type == CmaeraType.M3TD) {
|
params = {
|
pitchAngle: {
|
min: -90,
|
max: 30,
|
default: 0
|
},
|
zoom: {
|
max: 56,
|
min: 1,
|
default: 7
|
},
|
// wide: {
|
// //广角相机
|
// fov: 82, //视角°
|
// foc: 10.3, //焦距 mm (等效焦距24,实际焦距10.3)
|
// width: 9.6, //传感器物理尺寸宽度 mm
|
// halo: '1.7', //光圈
|
// imgWidth: 8064, //图像尺寸
|
// maxSize: '8064x6048' //最大图片尺寸
|
// },
|
// longFocus: {
|
// //长焦相机
|
// fov: 15, //视角
|
// foc: 162, //焦距
|
// width: 6.4, //传感器物理尺寸宽度 mm
|
// halo: '4.4', //光圈
|
// imgWidth: 4000, //图像尺寸
|
// maxSize: '4000x3000' //最大图片尺寸
|
// },
|
// infrared: {
|
// //红外相机
|
// space: 12, //像元间距
|
// fps: 30, //帧率
|
// fov: 61, //视角
|
// foc: 40, //焦距
|
// halo: '1.0', //光圈
|
// maxSize: '' //最大图片尺寸
|
// }
|
wide: {
|
//广角相机
|
fov: 84, //视角°
|
foc: 10.3, //焦距 mm (等效焦距24,实际焦距10.3)
|
width: 17.3, //传感器物理尺寸宽度 mm
|
halo: '2.8-11', //光圈
|
imgWidth: 5280, //图像尺寸
|
imgHeight: 3956, //图像尺寸
|
maxSize: '5280x3956' //最大图片尺寸
|
},
|
longFocus: {
|
//长焦相机
|
fov: 15, //视角°
|
foc: 162, //焦距mm
|
width: 6.4, //传感器物理尺寸宽度 mm
|
halo: '4.4', //光圈
|
imgWidth: 4000, //图像尺寸
|
imgHeight: 3000, //图像尺寸
|
maxSize: '4000x3000' //最大图片尺寸
|
},
|
infrared: {
|
//红外相机
|
space: 12, //像元间距
|
fps: 30, //帧率
|
width: 7.68, //传感器物理尺寸宽度 mm
|
fov: 61, //视角
|
foc: 40, //焦距
|
halo: 1.0, //光圈
|
maxSize: 640, //最大图片尺寸
|
maxHeight: 512 //最大图片尺寸
|
}
|
}
|
} else if (type == CmaeraType.M4D) {
|
//M4D没有红外相机
|
params = {
|
pitchAngle: {
|
min: -90,
|
max: 35,
|
default: 0
|
},
|
zoom: {
|
max: 112,
|
min: 1,
|
default: 7
|
},
|
wide: {
|
//广角相机
|
fov: 84, //视角°
|
foc: 10.3, //焦距 mm (等效焦距24,实际焦距10.3)
|
width: 17.3, //传感器物理尺寸宽度 mm
|
halo: '2.8-11', //光圈
|
imgWidth: 5280, //图像尺寸
|
imgHeight: 3956, //图像尺寸
|
maxSize: '5280x3956' //最大图片尺寸
|
},
|
longFocus: {
|
//长焦相机
|
fov: 15, //视角°
|
foc: 168, //焦距mm
|
width: 6.4, //传感器物理尺寸宽度 mm
|
halo: '2.8', //光圈
|
imgWidth: 8192, //图像尺寸
|
imgHeight: 6144, //图像尺寸
|
maxSize: '8192x6144' //最大图片尺寸
|
}
|
}
|
} else if (type == CmaeraType.M4TD) {
|
params = {
|
pitchAngle: {
|
min: -90,
|
max: 35,
|
default: 0
|
},
|
zoom: {
|
max: 112,
|
min: 1,
|
default: 7
|
},
|
wide: {
|
//广角相机
|
fov: 82, //视角°
|
foc: 10.3, //焦距 mm (等效焦距24,实际焦距10.3)
|
width: 9.6, //传感器物理尺寸宽度 mm
|
halo: '1.7', //光圈
|
imgWidth: 8064, //图像尺寸
|
imgHeight: 6048, //图像尺寸
|
maxSize: '8064x6048' //最大图片尺寸
|
},
|
longFocus: {
|
//长焦相机
|
fov: 15, //视角
|
foc: 168, //焦距
|
width: 6.4, //传感器物理尺寸宽度 mm
|
halo: '2.8', //光圈
|
imgWidth: 8192, //图像尺寸
|
imgHeight: 6144, //图像尺寸
|
maxSize: '8192×6144' //最大图片尺寸
|
},
|
infrared: {
|
//红外相机
|
space: 12, //像元间距
|
fps: 30, //帧率
|
width: 7.68, //传感器物理尺寸宽度 mm
|
fov: 45, //视角
|
foc: 53, //焦距
|
halo: 1.0, //光圈
|
maxSize: 640, //最大图片尺寸
|
maxHeight: 512 //最大图片尺寸
|
}
|
}
|
} else if (type == CmaeraType.M30) {
|
params = {
|
pitchAngle: {
|
min: -120,
|
max: 45,
|
default: 0
|
},
|
zoom: {
|
max: 200,
|
min: 2,
|
default: 5
|
},
|
wide: {
|
//广角相机
|
fov: 84, //视角°
|
foc: 4.5, //焦距 mm (等效焦距24,实际焦距10.3)
|
width: 6.4, //传感器物理尺寸宽度 mm
|
halo: '2.8', //光圈
|
imgWidth: 4000, //图像尺寸
|
imgHeight: 3000, //图像尺寸
|
maxSize: '4000x3000' //最大图片尺寸
|
},
|
longFocus: {
|
//长焦相机
|
fov: 30, //视角
|
foc: 200, //焦距
|
width: 6.4, //传感器物理尺寸宽度 mm
|
halo: '2.8', //光圈
|
imgWidth: 8000, //图像尺寸
|
imgHeight: 6000, //图像尺寸
|
maxSize: '8000x6000' //最大图片尺寸
|
},
|
infrared: {
|
//红外相机
|
space: 12, //像元间距
|
fps: 30, //帧率
|
width: 7.68, //传感器物理尺寸宽度 mm
|
fov: 61, //视角
|
foc: 40, //焦距
|
halo: 1.0, //光圈
|
maxSize: 1280, //最大图片尺寸
|
maxHeight: 1024 //最大图片尺寸
|
}
|
}
|
} else if (type == CmaeraType.M350) {
|
params = {
|
pitchAngle: {
|
min: -90,
|
max: 30,
|
default: 0
|
},
|
zoom: {
|
max: 56,
|
min: 1,
|
default: 7
|
},
|
wide: {
|
//广角相机 - 修正为H30系列参数
|
fov: 82.1, // 视角°
|
foc: 6.72, // 焦距 mm (等效焦距24)
|
width: 9.6, // 传感器物理尺寸宽度 mm
|
halo: '1.7', // 光圈
|
imgWidth: 8064, // 图像尺寸
|
imgHeight: 6048, // 图像尺寸
|
maxSize: '8064x6048' // 最大图片尺寸
|
},
|
longFocus: {
|
//长焦相机 - 修正为H30系列参数
|
fov: 2.9, // 视角° (最大变焦时)
|
foc: 172, // 焦距mm (最大变焦时)
|
width: 6.4, // 传感器物理尺寸宽度 mm
|
halo: '5.2', // 光圈 (最大变焦时)
|
imgWidth: 7328, // 图像尺寸
|
imgHeight: 5496, // 图像尺寸
|
maxSize: '7328x5496' // 最大图片尺寸
|
},
|
infrared: {
|
//红外相机
|
space: 12, //像元间距
|
fps: 30, //帧率
|
width: 7.68, //传感器物理尺寸宽度 mm
|
fov: 61, //视角
|
foc: 40, //焦距
|
halo: 1.0, //光圈
|
maxSize: 640, //最大图片尺寸
|
maxHeight: 512 //最大图片尺寸
|
}
|
}
|
} else if (type == CmaeraType.M3E) {
|
//没有红外相机
|
params = {
|
pitchAngle: {
|
min: -90,
|
max: 35,
|
default: 0
|
},
|
zoom: {
|
max: 56,
|
min: 1,
|
default: 7
|
},
|
wide: {
|
//广角相机
|
fov: 84, //视角°
|
foc: 10.3, //焦距 mm (等效焦距24,实际焦距10.3)
|
width: 17.3, //传感器物理尺寸宽度 mm
|
halo: '2.8-11', //光圈
|
imgWidth: 5280, //图像尺寸
|
imgHeight: 3956, //图像尺寸
|
maxSize: '5280x3956' //最大图片尺寸
|
},
|
longFocus: {
|
//长焦相机
|
fov: 15, //视角°
|
foc: 162, //焦距mm
|
width: 6.4, //传感器物理尺寸宽度 mm
|
halo: '4.4', //光圈
|
imgWidth: 4000, //图像尺寸
|
imgHeight: 3000, //图像尺寸
|
maxSize: '4000x3000' //最大图片尺寸
|
}
|
}
|
} else if (type == CmaeraType.M3T) {
|
params = {
|
pitchAngle: {
|
min: -90,
|
max: 35,
|
default: 0
|
},
|
zoom: {
|
max: 56,
|
min: 1,
|
default: 7
|
},
|
wide: {
|
//广角相机
|
fov: 84, //视角°
|
foc: 10.3, //焦距 mm (等效焦距24,实际焦距10.3)
|
width: 9.6, //传感器物理尺寸宽度 mm
|
halo: '1.7', //光圈
|
imgWidth: 8000, //图像尺寸
|
imgHeight: 6000, //图像尺寸
|
maxSize: '8000x6000' //最大图片尺寸
|
},
|
longFocus: {
|
//长焦相机
|
fov: 15, //视角
|
foc: 162, //焦距
|
width: 6.4, //传感器物理尺寸宽度 mm
|
halo: '4.4', //光圈
|
imgWidth: 4000, //图像尺寸
|
imgHeight: 3000, //图像尺寸
|
maxSize: '4000x3000' //最大图片尺寸
|
},
|
infrared: {
|
//红外相机
|
space: 12, //像元间距
|
fps: 30, //帧率
|
width: 7.68, //传感器物理尺寸宽度 mm
|
fov: 61, //视角
|
foc: 40, //焦距
|
halo: 1.0, //光圈
|
maxSize: 640, //最大图片尺寸
|
maxHeight: 512 //最大图片尺寸
|
}
|
}
|
}
|
return params
|
}
|
|
class SideFaceAirLine {
|
constructor(viewer, options) {
|
this.viewer = viewer
|
this.dock = options.dock || undefined //机场对象
|
this.jdArrs = [] //面数据(多边形的顶点数据)
|
this.polyArr = [] //交点集合
|
this.allLinePoint = [] //存储所有的航点
|
this.startFlyPoint = options.startFlyPoint || 0 //机场的高程
|
this.heightModel = options.heightModel //0:相对起飞点(relativeToStartPoint) ,1:相对地形(aboveGroundLevel) , 2:海拔高度(EGM96)
|
this.NOR_H = 30 //航线高度
|
this.HIS_NOR_H = 30 //航线高度
|
this.hfSpace = 2 //间距
|
this.pxSpace = 70 //旁向重叠率
|
this.camera = null
|
this.angle = 0 //航线角度
|
this.areaPoints = [] //面坐标
|
this.oldArray = []
|
this.inclineArray = [] //存放正射其他四条航线数据
|
this.isOrtho = true //是否是正射
|
this.tabRightArr = [] //保存倾斜航线数据
|
this.droneMode = '' //机型
|
this.roateAngle = 45
|
this.hisroateAngle = 25
|
this.reversalModel = 0
|
this.pointA = null
|
this.pointB = null
|
this.positions = null
|
this.avHeight = 0
|
this.isRight = true
|
this.init()
|
}
|
|
init () {
|
if (this.dock && this.dock.childrenVo.length > 0) {
|
this.camera = getCameraParams(this.dock?.childrenVo[0]?.deviceModel)
|
//预留以后多个额机型
|
this.droneMode = this.dock?.childrenVo[0]?.deviceModel // this.dock?.childrenVo[0]?.deviceModel == 'M3TD';
|
}
|
}
|
|
//开始绘制cleanEntity
|
startDrawRegion () {
|
//先清空
|
getArea([
|
{
|
areaList: [],
|
line: [],
|
points: []
|
}
|
])
|
|
this.areaPoints = []
|
let that = this
|
document.body.style.cursor = 'crosshair'
|
//1.清除entity
|
this.cleanEntity()
|
var handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas)
|
//handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene._imageryLayerCollection);
|
this.polyArr = [] //将面数据数组清空
|
this.oldArray = []
|
var positions = []
|
var polygon = null
|
//获取鼠标滑动时候提示的标签
|
var tooltip = document.getElementById('toolTip')
|
var cartesian = null
|
//3.鼠标移动事件(控制tooltip标签的位置显示)
|
|
handler.setInputAction(function (movement) {
|
if (tooltip) {
|
tooltip.style.left = movement.endPosition.x + 300 + 'px'
|
tooltip.style.top = movement.endPosition.y - 25 + 'px'
|
tooltip.innerHTML = '<p>单击开始,右击结束</p>'
|
}
|
//获取鼠标移动时候射线
|
const ray = that.viewer.camera.getPickRay(movement.endPosition)
|
cartesian = that.viewer.scene.globe.pick(ray, that.viewer.scene)
|
if (positions.length >= 2) {
|
if (!Cesium.defined(polygon)) {
|
polygon = new PolygonPrimitive(that.viewer, positions)
|
} else {
|
positions.pop()
|
positions.push(cartesian)
|
}
|
}
|
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
|
// 4.左击鼠标事件
|
handler.setInputAction(function (movement) {
|
if (tooltip) {
|
tooltip.style.display = 'block'
|
tooltip.style.left = movement.position.x + 300 + 'px'
|
tooltip.style.top = movement.position.y - 25 + 'px'
|
tooltip.innerHTML = '<p>单击开始,右击结束</p>'
|
}
|
const ray = that.viewer.camera.getPickRay(movement.position)
|
cartesian = that.viewer.scene.globe.pick(ray, that.viewer.scene)
|
|
// if (Cesium.defined(cartesian)) {
|
// var cartographic = Cesium.Cartographic.fromCartesian(cartesian); // 转换为地理坐标
|
// var longitude = Cesium.Math.toDegrees(cartographic.longitude); // 经度
|
// var latitude = Cesium.Math.toDegrees(cartographic.latitude); // 纬度
|
// // 获取地形高程
|
// let height = that.viewer.scene.globe.getHeight(cartographic);
|
// that.viewer.entities.add({
|
// name: 'uav-point',
|
// position: Cesium.Cartesian3.fromDegrees(longitude, latitude, height), // 点的位置(经度, 纬度)
|
// point: {
|
// pixelSize: 10, // 点的大小(以像素为单位)
|
// color: Cesium.Color.WHITE // 点的颜色
|
// // outlineColor: Cesium.Color.WHITE, // 点的轮廓颜色
|
// // outlineWidth: 2 // 点的轮廓宽度
|
// }
|
// });
|
// }
|
|
if (positions.length === 0) {
|
positions.push(cartesian.clone())
|
}
|
// positions.pop();
|
positions.push(cartesian)
|
// 在三维场景中添加点
|
var cartographic = Cesium.Cartographic.fromCartesian(positions[positions.length - 1])
|
var longitudeString = Cesium.Math.toDegrees(cartographic.longitude)
|
var latitudeString = Cesium.Math.toDegrees(cartographic.latitude)
|
var heightString = cartographic.height
|
that.areaPoints.push({
|
longitude: longitudeString,
|
latitude: latitudeString,
|
altitude: heightString
|
})
|
//计算两点之间的距离
|
that.viewer.entities.add({
|
name: 'uav-point',
|
position: Cesium.Cartesian3.fromDegrees(longitudeString, latitudeString, heightString), // 点的位置(经度, 纬度)
|
point: {
|
pixelSize: 10, // 点的大小(以像素为单位)
|
color: Cesium.Color.WHITE // 点的颜色
|
// outlineColor: Cesium.Color.WHITE, // 点的轮廓颜色
|
// outlineWidth: 2 // 点的轮廓宽度
|
}
|
})
|
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
|
//5.右击鼠标事件
|
handler.setInputAction(function () {
|
document.body.style.cursor = 'default'
|
//销毁注册的时间对象
|
handler.destroy()
|
if (tooltip) {
|
tooltip.style.display = 'none'
|
}
|
positions.pop()
|
that.polyArr = positions
|
that.oldArray.push(...that.polyArr)
|
//计算旁向间距
|
that.updataOverLap({
|
crossLap: 70 //在LeftBox.vue中给的默认值是70
|
})
|
//开始计算航点
|
// that.beginCalc();
|
//计算每个线段长度
|
that.calculateLineLength(positions)
|
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
|
}
|
|
/**
|
* 开始计算按钮
|
*/
|
async beginCalc () {
|
let that = this
|
if (that.polyArr.length === 0) {
|
// alert('未检测到航飞区域');
|
return
|
}
|
//let loadingInstance = ElLoading.service({ text: '航线生成中...', background: 'rgba(0,0,0,0.2)', customClass: 'custom-loading' });
|
//倾斜还是正射
|
// let lineArr = await CalcCourseLine(that.viewer, that.polyArr, that.angle, that.hfSpace);
|
|
let roatePositionArr, slopeLinePositions, lineArr
|
if (that.heightModel == 'relativeToStartPoint') {
|
slopeLinePositions = await CalcCourseSlopeLineLine(
|
that.viewer,
|
that.polyArr,
|
that.angle,
|
that.hfSpace,
|
this.reversalModel == 0 ? that.NOR_H : that.HIS_NOR_H,
|
this.roateAngle
|
)
|
|
slopeLinePositions = slopeLinePositions.filter(item => item !== undefined)
|
} else {
|
|
lineArr = await CalcCourseLine(that.viewer, that.polyArr, that.angle, that.hfSpace)
|
// 线数据
|
var linesArrs = []
|
//如果是相对地形则处理航线数据(插值)
|
if (that.heightModel == 'aboveGroundLevel') {
|
let tempAray = []
|
for (let index = 0; index < lineArr.length; index++) {
|
const startPoint = lineArr[index]
|
tempAray.push(startPoint) //临时保存
|
if (index < lineArr.length - 1) {
|
const next = lineArr[index + 1]
|
let sp = Cesium.Cartesian3.fromDegrees(...startPoint)
|
let ep = Cesium.Cartesian3.fromDegrees(...next)
|
//一下算法保留
|
//计算每两个点之间的长度(1米 == 0.000621英里)
|
// let len = getDistance(sp, ep);
|
// 如果距离超过20m,则需要插值n个(n=(len * 0.000621) / 20)
|
let result = await interpolation(that.viewer, sp, ep, 5)
|
tempAray.push(...result)
|
}
|
}
|
|
lineArr = tempAray
|
}
|
|
//求各种航线高度模式下的高程
|
for (let index = 0; index < lineArr.length; index++) {
|
const res = lineArr[index]
|
// 存储线数据
|
linesArrs.push(res[0])
|
linesArrs.push(res[1])
|
//aboveGroundLevel relativeToStartPoint
|
//高度模式
|
if (that.heightModel == 'aboveGroundLevel') {
|
//想对起飞点(起飞点默认是机场高度都为startFlyPoint)
|
linesArrs.push(that.avHeight + (this.reversalModel == 0 ? that.NOR_H : that.HIS_NOR_H))
|
} else if (that.heightModel == 'relativeToStartPoint') {
|
//相对地形高
|
// let height = getRelativeHeight(that.viewer, res[0], res[1]);
|
// let height = getRelativeHeight(that.viewer, lineArr[0][0], lineArr[0][1]);
|
// linesArrs.push(height + (this.reversalModel == 0 ? that.NOR_H : that.HIS_NOR_H));
|
} else if (that.heightModel == 'EGM96') {
|
//海拔高(观察司空2上海拔参考点是起飞点的海拔)
|
linesArrs.push(that.startFlyPoint + (this.reversalModel == 0 ? that.NOR_H : that.HIS_NOR_H))
|
}
|
//标记第一个点S点
|
if (index == 0) {
|
that.addStartPoint(linesArrs)
|
}
|
}
|
let rLineArr = Cesium.Cartesian3.fromDegreesArrayHeights(linesArrs)
|
roatePositionArr = this.roatePositionAngle(rLineArr, this.reversalModel == 0 ? this.roateAngle : this.hisroateAngle)
|
|
}
|
|
//let roatePositionArr = rLineArr
|
// 画方向线
|
console.log(slopeLinePositions, roatePositionArr, 'uav-tmp-line')
|
that.viewer.entities.add({
|
name: 'uav-tmp-line',
|
id: 'flightLine',
|
// corridor polyline
|
polyline: {
|
// positions: Cesium.Cartesian3.fromDegreesArray(lineArr.flat()),
|
positions: that.heightModel === 'relativeToStartPoint' ? slopeLinePositions : roatePositionArr,
|
material: new Cesium.PolylineArrowMaterialProperty(Cesium.Color.fromCssColorString('#0aed8a')), //箭头
|
arcType: Cesium.ArcType.GEODESIC, //RHUMB
|
followSurface: true,
|
clampToGround: false,
|
width: 10
|
}
|
})
|
|
// if (that.heightModel == 'relativeToStartPoint') {
|
// getArea([
|
// {
|
// areaList: that.areaPoints,
|
// line: lineArr,
|
// points: points
|
// }
|
// ])
|
// }
|
|
//通知
|
if (this.isOrtho) {
|
if (roatePositionArr && lineArr) {
|
that.areaPoints = []
|
this.positions.forEach((item) => {
|
var cartographic = Cesium.Cartographic.fromCartesian(item)
|
var longitudeString = Cesium.Math.toDegrees(cartographic.longitude)
|
var latitudeString = Cesium.Math.toDegrees(cartographic.latitude)
|
var heightString = cartographic.height
|
that.areaPoints.push({
|
longitude: longitudeString,
|
latitude: latitudeString,
|
altitude: heightString
|
})
|
})
|
let points = []
|
|
roatePositionArr.forEach((item) => {
|
var cartographic = Cesium.Cartographic.fromCartesian(item)
|
var longitudeString = Cesium.Math.toDegrees(cartographic.longitude)
|
var latitudeString = Cesium.Math.toDegrees(cartographic.latitude)
|
var heightString = cartographic.height
|
points.push(longitudeString)
|
points.push(latitudeString)
|
points.push(heightString)
|
})
|
|
//正射
|
getArea([
|
{
|
areaList: that.areaPoints,
|
line: lineArr,
|
points: points
|
}
|
])
|
}
|
|
if (slopeLinePositions) {
|
//正射
|
getArea([
|
{
|
areaList: that.polyArr,
|
line: '',
|
points: slopeLinePositions
|
}
|
])
|
}
|
} else {
|
//倾斜
|
this.tabRightArr.push({
|
areaList: that.areaPoints,
|
line: lineArr,
|
points: linesArrs
|
})
|
if (this.droneMode == 'M3TD') {
|
//5条航线
|
if (this.tabRightArr.length == 5) {
|
getArea(this.tabRightArr)
|
}
|
} else {
|
//2条航线
|
if (this.tabRightArr.length == 2) {
|
getArea(this.tabRightArr)
|
}
|
}
|
}
|
//loadingInstance.close();
|
}
|
/**
|
* 更新航线
|
*/
|
updata (args) {
|
//航线高度模式或者值变化
|
if (args.type == 'heightModel') {
|
this.updataHeihgtModel({
|
model: args.model,
|
height: args.globalHeight
|
})
|
} else if (args.type == 'speed') {
|
//全局航线速度
|
this.updataSpeed({
|
speed: args.speed
|
})
|
} else if (args.type == 'overLap') {
|
//重叠率
|
this.updataOverLap({
|
crossLap: args.crossLap
|
})
|
} else if (args.type == 'mainAngle') {
|
//主航线角度
|
this.updataMainAngle({
|
angle: args.angle
|
})
|
} else if (args.type == 'margin') {
|
//边距
|
this.updataMargin({
|
margin: args.margin
|
})
|
} else if (args.type.startsWith('gsd_')) {
|
//gsd调节
|
this.updataGsd(args)
|
} else if (args.type == 'gatherModel') {
|
//正射or倾斜
|
if (args.model == 'ortho') {
|
this.isOrtho = true
|
//正射
|
this.calculateOrthoRoute()
|
} else {
|
//倾斜
|
this.isOrtho = false
|
this.calculateInclinedRoute()
|
}
|
} else if (args.type.startsWith('altitudeHeight')) {
|
//相对被摄面距离
|
this.updataAltitudeHeight(args)
|
} else if (args.type == 'ReversalModel') {
|
this.updataReversal(args)
|
}
|
}
|
|
updataAltitudeHeight (args) {
|
this.NOR_H = args.altitudeHeight
|
this.HIS_NOR_H = -this.NOR_H
|
//更新gsd
|
this.updataGsdForHeight()
|
//重新计算旁向重叠率
|
let space = this.sideOverlap()
|
this.hfSpace = space
|
this.beginCalc()
|
}
|
|
updataReversal (args) {
|
this.reversalModel = args.model
|
this.beginCalc()
|
}
|
|
//航线高度会影响gsd值
|
updataGsdForHeight () {
|
if (this.camera) {
|
if (this.is3Td == 'M3TD') {
|
//广角
|
let gsdLi = (this.NOR_H * (100 * this.camera.wide.width)) / (this.camera.wide.foc * this.camera.wide.imgWidth)
|
emitter.emit('gsdLiChange', Number(gsdLi.toFixed(2)))
|
//红外
|
let gsdIr = gsdLi * 3.75
|
emitter.emit('gsdIrChange', Number(gsdIr.toFixed(2)))
|
} else {
|
//M3D,只计算广角
|
let gsdLi = (this.NOR_H * (100 * this.camera.wide.width)) / (this.camera.wide.foc * this.camera.wide.imgWidth)
|
emitter.emit('gsdLiChange', Number(gsdLi.toFixed(2)))
|
}
|
}
|
}
|
/**
|
* 更新航线模式和高度
|
*/
|
updataHeihgtModel (parmars) {
|
let { model, height } = parmars
|
this.NOR_H = height
|
this.HIS_NOR_H = -this.NOR_H
|
this.heightModel = model
|
//更新gsd
|
this.updataGsdForHeight()
|
//重新计算旁向重叠率
|
let space = this.sideOverlap()
|
this.hfSpace = space
|
this.beginCalc()
|
}
|
/**
|
* 全局航线速度改变(会影响拍照数目)
|
*/
|
updataSpeed (parmars) {
|
// let { model, height } = parmars;
|
// this.NOR_H = height;
|
// this.heightModel = model;
|
// this.beginCalc();
|
}
|
|
/**
|
* 旁向重叠率改变
|
*/
|
updataOverLap (parmars) {
|
this.pxSpace = parmars.crossLap
|
let space = this.sideOverlap()
|
this.hfSpace = space //旁向重叠率
|
this.tabRightArr = []
|
|
if (this.isOrtho) {
|
this.beginCalc()
|
} else {
|
this.calculateInclinedRoute()
|
}
|
}
|
/**
|
* 主航线角度改变
|
*/
|
updataMainAngle (parmars) {
|
this.angle = parmars.angle
|
//刷新航线
|
this.beginCalc()
|
}
|
//根据相机参数以及gsd参数计算航线高度
|
calculateAirLineHeight (gsd, isIr) {
|
if (this.camera) {
|
//广角相机计算出此gsd下的航线高度
|
let h = (gsd * this.camera.wide.foc * this.camera.wide.imgWidth) / (100 * this.camera.wide.width)
|
let height = Number(h.toFixed(1))
|
//刷新UI
|
emitter.emit('updataLineHeight', height)
|
return height
|
}
|
return 0
|
}
|
/**
|
* 航线边距改变
|
*/
|
updataMargin (parmars) {
|
if (parmars.margin == 0) {
|
this.viewer.entities.removeById('scale-polygon')
|
//重置
|
this.polyArr = this.oldArray
|
this.beginCalc()
|
return
|
}
|
let res = this.calculateZoom(this.oldArray, parmars.margin)
|
// let entity = this.viewer.entities.getById("scale-polygon")
|
this.viewer.entities.removeById('scale-polygon')
|
const polygon = this.viewer.entities.add({
|
id: 'scale-polygon',
|
polygon: {
|
hierarchy: res,
|
material: Cesium.Color.fromCssColorString('#0358b1').withAlpha(0.3)
|
}
|
})
|
//开始计算航点
|
this.polyArr = res
|
this.beginCalc()
|
}
|
//gsd参数调节
|
updataGsd (parmars) {
|
// GSD = (飞行高度×传感器宽度) / (焦距×图像宽度) x 100
|
//gsd变化之后根据gsd的值动态计算航线高度
|
// 二者任何一个修改都会影响航线高度
|
let airLineHeight = 0
|
if (this.droneMode == 'M3TD') {
|
//有红外gsd
|
if (parmars.type == 'gsd_l') {
|
airLineHeight = this.calculateAirLineHeight(parmars.gsdLight, false)
|
//计算红外的影响值
|
// let gsdIr = (height * camera.infrared.width * 100) / (camera.infrared.foc * camera.infrared.maxSize);
|
let gsdIr = parmars.gsdLight * 3.75
|
emitter.emit('gsdIrChange', gsdIr)
|
}
|
if (parmars.type == 'gsd_r') {
|
//红外gsd
|
let gsdLi = Number((parmars.gsdIr / 3.75).toFixed(2))
|
emitter.emit('gsdLiChange', gsdLi)
|
airLineHeight = this.calculateAirLineHeight(gsdLi, false)
|
}
|
} else {
|
//M3D只有广角gsd(无红外gsd)
|
if (parmars.type == 'gsd_l') {
|
airLineHeight = this.calculateAirLineHeight(parmars.gsdLight, false)
|
}
|
}
|
|
//更新航线,重新计算
|
if (airLineHeight > 0) {
|
this.updataHeihgtModel({
|
model: this.heightModel,
|
height: airLineHeight
|
})
|
}
|
}
|
|
/**
|
* 清理entity
|
*/
|
cleanEntity () {
|
removeEntityLikeName(this.viewer, 'uav-')
|
this.cleanEntityCollection(this.viewer, 'uav')
|
this.viewer.entities.removeById('scale-polygon')
|
this.polyArr = []
|
this.viewer.clockViewModel.shouldAnimate = false
|
this.viewer.trackedEntity = undefined
|
}
|
cleanEntityCollection (viewer, key) {
|
var tmp = viewer.dataSources.getByName(key)
|
if (tmp.length > 0) {
|
tmp.map((res) => {
|
viewer.dataSources.remove(res)
|
})
|
}
|
}
|
// 弧度转换为经纬度
|
rectangle2LonLat (coor) {
|
const northwest = Cesium.Rectangle.northwest(coor)
|
const southwest = Cesium.Rectangle.southwest(coor)
|
const northeast = Cesium.Rectangle.northeast(coor)
|
const southeast = Cesium.Rectangle.southeast(coor)
|
const leftTop = [Cesium.Math.toDegrees(northwest.longitude), Cesium.Math.toDegrees(northwest.latitude)]
|
const leftBottom = [Cesium.Math.toDegrees(southwest.longitude), Cesium.Math.toDegrees(southwest.latitude)]
|
const rightTop = [Cesium.Math.toDegrees(northeast.longitude), Cesium.Math.toDegrees(northeast.latitude)]
|
const rightBottom = [Cesium.Math.toDegrees(southeast.longitude), Cesium.Math.toDegrees(southeast.latitude)]
|
return [leftTop, rightTop, leftBottom, rightBottom]
|
}
|
|
/**
|
* 航向重叠率计算
|
*/
|
forwardPverlap () {
|
//飞行前进间隔 是指无人机拍摄两张连续照片之间的飞行距离,这个值由拍摄间隔(曝光时间)和飞行速度决定。
|
//H:无人机飞行高度(相机离地面高度,单位为米)。
|
// FOV_vertical:相机的垂直视场角(单位为°)
|
// 实际拍摄长度(L) = H × 2 × tan(FOV_vertical / 2)
|
// 航向重叠率 (%) =(相机实际拍摄长度−飞行前进间隔)/相机实际拍摄长度 × 100
|
}
|
|
/**
|
* 旁向重叠率计算(相邻航线的间距)
|
*/
|
sideOverlap () {
|
/**
|
* // FOV是相机的视场角
|
* 实际拍摄宽度 = 飞行高度 × 2 × tan(FOV/2)
|
*例如:
|
如果实际拍摄宽度是100米
|
航线间距是60米
|
则旁向重叠率 = (100-60)/100 = 0.4
|
|
//反算航线间距X(假设重叠率80%)
|
(飞行高度 × 2 × tan(FOV/2)) - X = 80
|
|
旁向重叠率 = (实际拍摄宽度 - 航线间距) / 实际拍摄宽度
|
航线间距 = 实际拍摄宽度 - 旁向重叠率 * 实际拍摄宽度
|
*/
|
//计算实际拍摄宽度
|
//1.获取相机参数
|
if (this.camera) {
|
//2.计算实际拍摄宽度(广角镜头)
|
// let realWidth = this.NOR_H * 2 * Math.tan((this.camera.wide.fov / 2) * (Math.PI / 180));
|
let realWidth = this.NOR_H * 2 * Math.tan((60 / 2) * (Math.PI / 180))
|
//3.计算航线间距
|
let lineSpace = realWidth - realWidth * this.pxSpace * 0.01
|
return lineSpace
|
}
|
return 10
|
}
|
|
//计算每个线段长度
|
calculateLineLength (positions) {
|
if (positions.length < 2) return
|
let array = [...positions, positions[0]]
|
// 清除之前计算结果entity
|
removeEntityLikeName(this.viewer, 'uav-label')
|
for (let index = 0; index < array.length; index++) {
|
const first = array[index]
|
if (index < array.length - 1) {
|
const last = array[index + 1]
|
//英里转米
|
let distance = getDistance(first, last)
|
let len = (distance * 1609.34).toFixed(1) //mi 1609.34
|
//计算两点中心店
|
var midpoint = getMidPoint(first, last)
|
//添加长度标注
|
this.viewer.entities.add({
|
name: 'uav-label',
|
id: 'label' + index,
|
position: Cesium.Cartesian3.fromDegrees(...midpoint.geometry.coordinates),
|
label: {
|
show: true,
|
text: len + 'm',
|
font: '12px Helvetica',
|
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
|
scale: 1.0, //缩放
|
showBackground: true, //指定标签背后背景的可见性
|
backgroundColor: Cesium.Color.BLACK.withAlpha(0.45), //背景颜色
|
backgroundPadding: new Cesium.Cartesian2(5, 5), //以像素为单位指定水平和垂直背景填充
|
pixelOffset: Cesium.Cartesian2.ZERO, //设置其原始位置上的偏移量Cartesian2(x,y)
|
//指定标签在眼睛坐标中的偏移量。眼睛坐标是左手坐标系,其中 x 指向观看者的右侧, y 指向上方, z 指向屏幕内。
|
eyeOffset: Cesium.Cartesian3.ZERO,
|
//指定高度相对于什么。
|
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
|
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
|
verticalOrigin: Cesium.VerticalOrigin.CENTER
|
}
|
})
|
}
|
}
|
}
|
|
//计算缩放倍数
|
calculateZoom (positions, margin) {
|
if (positions && positions.length > 0) {
|
// 计算中心点
|
const center = Cesium.Cartesian3.fromElements(
|
positions.reduce((sum, pos) => sum + pos.x, 0) / positions.length,
|
positions.reduce((sum, pos) => sum + pos.y, 0) / positions.length,
|
positions.reduce((sum, pos) => sum + pos.z, 0) / positions.length
|
)
|
const scaledPositions = positions.map((pos) => {
|
const offset = Cesium.Cartesian3.subtract(pos, center, new Cesium.Cartesian3())
|
//缩放倍率(1m距离缩放 1/25.5139 )
|
let s = 1 + margin * (1 / (25.5139 * 8)) //放大10m
|
const scaledOffset = Cesium.Cartesian3.multiplyByScalar(offset, s, new Cesium.Cartesian3())
|
return Cesium.Cartesian3.add(center, scaledOffset, new Cesium.Cartesian3())
|
})
|
return scaledPositions
|
}
|
return []
|
}
|
|
//添加s点
|
addStartPoint (pos) {
|
this.viewer.entities.add({
|
name: 'uav-tmp-point',
|
position: Cesium.Cartesian3.fromDegrees(...pos),
|
billboard: {
|
image: showLabelFun({
|
text: 's'
|
}),
|
pixelOffset: new Cesium.Cartesian2(0, 0),
|
disableDepthTestDistance: Number.POSITIVE_INFINITY //被建筑物遮挡问题
|
}
|
})
|
}
|
|
//正射
|
calculateOrthoRoute () {
|
this.angle = 0
|
this.polyArr = this.oldArray
|
this.beginCalc()
|
}
|
|
//倾斜
|
async calculateInclinedRoute () {
|
if (this.areaPoints.length == 0) return
|
removeEntityLikeName(this.viewer, 'in-line')
|
//0.原始点
|
let points = [...this.areaPoints]
|
points.push(this.areaPoints[0])
|
let oragin = []
|
points.forEach((e) => {
|
oragin.push([e.longitude, e.latitude])
|
})
|
let is3Td = this.droneMode == 'M3TD'
|
if (is3Td) {
|
//总共5条航线
|
this.inclineArray = this.m3tdInclineFun(points, oragin)
|
//把第一条航线加进去
|
this.inclineArray.unshift(oragin)
|
} else {
|
//只有两条航线
|
this.inclineArray = this.m3DInclineFun(points, oragin)
|
}
|
|
//'log========this.inclineArray======'
|
|
//默认计算第一个条
|
let temp = []
|
if (is3Td) {
|
// 一把生成所有航线
|
this.inclineArray.forEach((coors) => {
|
let arr = []
|
coors.map((e) => {
|
arr.push(transformWGS84ToCartesian({ lng: e[0], lat: e[1], alt: 0 }))
|
})
|
//移除最后一个点
|
arr.pop()
|
temp.push(arr)
|
})
|
} else {
|
this.angle = 89
|
this.inclineArray.forEach((coors) => {
|
let arr = []
|
coors.map((e) => {
|
arr.push(transformWGS84ToCartesian({ lng: e[0], lat: e[1], alt: 0 }))
|
})
|
//移除最后一个点
|
arr.pop()
|
temp.push(arr)
|
})
|
}
|
//开始计算航线
|
for (let index = 0; index < temp.length; index++) {
|
const ls = temp[index]
|
this.polyArr = [...ls]
|
await this.beginCalc()
|
}
|
}
|
|
//计算m3D机型倾斜
|
m3DInclineFun (points, oragin) {
|
//偏移距离
|
let distance = 50.0 / 1000 //默认点位 公里,转为m
|
//1.计算南北方向的矩形范围(南北方向各自偏移求矩形盒)
|
let northAndSouthPoints = this.calculateRectOfM3D(points, oragin, 0, 180, distance)
|
//2.计算东西方向矩形范围
|
let eastAndwestPoints = this.calculateRectOfM3D(points, oragin, 90, 270, distance)
|
let array = [northAndSouthPoints, eastAndwestPoints]
|
this.rectangularAll(array)
|
return array
|
}
|
|
//计算M3D的矩形范围
|
calculateRectOfM3D (points, oragin, northAng, southAng, distance) {
|
let norths = this.skewingOfOrigin(points, oragin, northAng, distance)
|
let souths = this.skewingOfOrigin(points, oragin, southAng, distance)
|
//合并两组数据
|
let array = [...norths, ...souths]
|
//求平均海拔
|
let height = 0
|
array.forEach((e) => {
|
height += e[2]
|
})
|
height = height / array.length
|
//计算边界框
|
var line = turf.lineString(array)
|
var bbox = turf.bbox(line)
|
var bboxPolygon = turf.bboxPolygon(bbox)
|
let temp = bboxPolygon.geometry.coordinates[0]
|
temp.forEach((tm) => {
|
tm[2] = height
|
})
|
return temp
|
}
|
//计算M3TD计算的倾斜
|
m3tdInclineFun (points, oragin) {
|
//计算倾斜新的其他四个面(东西南北)
|
//偏移距离
|
let distance = 50.0 / 1000 //默认点位 公里,转为m
|
//1.正北(0度)
|
let norths = this.skewingOfOrigin(points, oragin, 0, distance)
|
//正东(90)
|
let easts = this.skewingOfOrigin(points, oragin, 90, distance)
|
//正南(180)
|
let souths = this.skewingOfOrigin(points, oragin, 180, distance)
|
//正西(270)
|
let wests = this.skewingOfOrigin(points, oragin, 270, distance)
|
//计算包含所有点的多边形
|
// let temp = [...norths, ...easts, ...souths, ...wests];
|
// let array = temp.map((e) => this.transLngAndLat(e));
|
let array = [norths, easts, souths, wests]
|
this.rectangularAll(array)
|
//开始计算倾斜的5条航线数据
|
return array
|
}
|
//求包含所有点的多边形
|
rectangularAll (array) {
|
let res = getMuiltBoxRange(array)
|
//绘制面
|
this.viewer.entities.add({
|
name: 'in-line',
|
polygon: {
|
hierarchy: Cesium.Cartesian3.fromDegreesArray(res.flat()),
|
material: Cesium.Color.BLUE.withAlpha(0.2)
|
}
|
})
|
}
|
//计算偏移和方向(返回一组新坐标点)
|
skewingOfOrigin (points, oragin, ang, distance) {
|
var poly = turf.polygon([oragin])
|
var translatedPoly = turf.transformTranslate(poly, distance, ang, { units: 'kilometers' })
|
let array = translatedPoly.geometry.coordinates[0]
|
//划线前加上高程
|
points.forEach((e, index) => {
|
array[index][2] = e.altitude
|
})
|
return array
|
}
|
//带高程数据转为无高程数据
|
transLngAndLat (array) {
|
if (!array) return []
|
if (array.length <= 2) {
|
return array
|
}
|
return [array[0], array[1]]
|
}
|
changeLine (e, i) {
|
// ## waring 切换逻辑重写
|
alert('waring 切换逻辑重写')
|
return
|
// [北东南西] == 【2,3,4,5】m3td
|
//【左右】 ==【1,2】
|
//默认计算第一个条
|
let temp = []
|
this.inclineArray[i - 1].map((e) => {
|
temp.push(transformWGS84ToCartesian({ lng: e[0], lat: e[1], alt: 0 }))
|
})
|
//移除最后一个点
|
temp.pop()
|
//开始计算航线
|
this.polyArr = [...temp]
|
if (this.droneMode == 'M3TD') {
|
if (i == 2 || i == 4) {
|
this.angle = 89
|
} else {
|
this.angle = 0
|
}
|
} else {
|
if (i == 1) {
|
this.angle = 89
|
} else {
|
this.angle = 0
|
}
|
}
|
// this.addLine(this.inclineArray[i - 1], true);
|
// log======this.polyArr========
|
this.beginCalc()
|
}
|
//辅助工具
|
addLine (array, isH, color = Cesium.Color.YELLOW) {
|
let line = this.viewer.entities.add({
|
name: 'line' + Math.random(),
|
polyline: {
|
show: true,
|
// 定义线条的 Cartesian3 位置的数组
|
// positions: Cesium.Cartesian3.fromDegreesArrayHeights(array.flat()),
|
positions: isH ? Cesium.Cartesian3.fromDegreesArrayHeights(array.flat()) : Cesium.Cartesian3.fromDegreesArray(array.flat()),
|
// 以像素为单位指定宽度。
|
width: 1,
|
// 如果arcType不是ArcType.NONE,则指定每个纬度和经度之间的角距离
|
// granularity: Cesium.Math.RADIANS_PER_DEGREE,
|
material: color,
|
// 线低于地形时用于绘制折线的材质(地下管道)
|
// depthFailMaterial: Cesium.Color.WHITE,
|
// 折线段必须遵循的线型
|
// arcType: Cesium.ArcType.GEODESIC,
|
clampToGround: true, // 是否贴地
|
shadows: Cesium.ShadowMode.DISABLED, // 折线是投射还是接收光源的阴影
|
// distanceDisplayCondition: new Cesium.DistanceDisplayCondition(
|
// 1.0e3,
|
// 2.0e3
|
// ),
|
// 在地面上时将对地形,3D tiles还是对两者进行分类 type:ClassificationType default:ClassificationType.BOTH
|
// TERRAIN 将仅对地形进行分类;CESIUM_3D_TILE 将仅对3D Tiles进行分类;BOTH 将同时对Terrain和3D Tiles进行分类。
|
classificationType: Cesium.ClassificationType.BOTH
|
|
// 指定用于订购地面几何形状的z索引。仅在多边形为常数且未指定高度或拉伸高度的情况下才有效 type:ConstantProperty
|
// zIndex: 0,
|
}
|
})
|
}
|
addPoint (array) {
|
let point = this.viewer.entities.add({
|
position: Cesium.Cartesian3.fromDegrees(...array),
|
point: {
|
show: true,
|
pixelSize: 10, // 像素大小
|
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, //指定相对高度
|
color: Cesium.Color.YELLOW,
|
outlineColor: Cesium.Color.WHITE,
|
outlineWidth: 1
|
}
|
})
|
}
|
|
setPositionData (positions, angle, isRight) {
|
/**
|
var ellipsoid = this.viewer.scene.globe.ellipsoid;
|
|
let maxHeight = 0
|
positions.forEach(item=>{
|
var cartographic = ellipsoid.cartesianToCartographic(item);
|
var height = cartographic.height
|
maxHeight +=height;
|
})
|
|
var cartographic = ellipsoid.cartesianToCartographic(positions[0]);
|
var height = cartographic.height
|
var cartographic1 = ellipsoid.cartesianToCartographic(positions[1]);
|
var height1 = cartographic1.height
|
var cartographic2 = ellipsoid.cartesianToCartographic(positions[2]);
|
var height2 = cartographic2.height
|
//this.avHeight = (height+height1+height2)/3
|
//"向左-向右"
|
this.avHeight = (height+height2)/2
|
this.positions = positions;
|
let initAngle = 0;
|
|
var cartographic = ellipsoid.cartesianToCartographic(positions[2]);
|
var lat = Cesium.Math.toDegrees(cartographic.latitude);
|
var lng = Cesium.Math.toDegrees(cartographic.longitude);
|
var cartographic1 = ellipsoid.cartesianToCartographic(positions[4]);
|
var lat1 = Cesium.Math.toDegrees(cartographic1.latitude);
|
var lng1 = Cesium.Math.toDegrees(cartographic1.longitude);
|
|
var cartographic0 = ellipsoid.cartesianToCartographic(positions[0]);
|
var lat0 = Cesium.Math.toDegrees(cartographic0.latitude);
|
var lng0 = Cesium.Math.toDegrees(cartographic0.longitude);
|
let positions1 = []
|
if(lat0 < lat){
|
positions1[0] = positions[2]
|
positions1[1] = positions[1]
|
positions1[2] = positions[0]
|
positions1[3] = positions[7]
|
positions1[4] = positions[6]
|
positions1[5] = positions[5]
|
positions1[6] = positions[4]
|
positions1[7] = positions[3]
|
this.positions = positions1
|
}
|
|
if (lng - lng1 > 0) {
|
|
//向左画
|
this.roateAngle = 360 - angle;
|
this.hisroateAngle = this.roateAngle
|
this.HIS_NOR_H = -this.NOR_H
|
|
} else {
|
|
//向右画
|
this.roateAngle = angle;
|
this.hisroateAngle = this.roateAngle
|
this.HIS_NOR_H = -this.NOR_H
|
|
}
|
|
this.pointA = this.positions[0];
|
this.pointB = this.positions[1];
|
// let rotatedPositions = this.roatePositionAngle(positions, initAngle);
|
|
let rotatedPositions = this.positions
|
//const projectedPoints = this.rotatePoints(positions,initAngle);
|
|
|
// 通过fromPoints方法获取中心坐标
|
|
|
if(angle > 40){
|
let newpositions = []
|
newpositions.push(rotatedPositions[0])
|
newpositions.push(rotatedPositions[1])
|
newpositions.push(rotatedPositions[2])
|
//newpositions.push(rotatedPositions[3])
|
for(var i =3;i<7;i+=1){
|
debugger
|
var last = 2
|
if(i == 4 || i ==3){
|
last = 2
|
}else if(i == 5){
|
last = 1
|
}else if(i == 6){
|
last = 0
|
}
|
var ellipsoid = this.viewer.scene.globe.ellipsoid;
|
var cartographic = ellipsoid.cartesianToCartographic(rotatedPositions[last]);
|
var lat = Cesium.Math.toDegrees(cartographic.latitude);
|
var lng = Cesium.Math.toDegrees(cartographic.longitude);
|
var cartographic1 = ellipsoid.cartesianToCartographic(rotatedPositions[i]);
|
var lat1 = Cesium.Math.toDegrees(cartographic1.latitude);
|
var lng1 = Cesium.Math.toDegrees(cartographic1.longitude);
|
var point1 = turf.point([lng, lat]);
|
var point2 = turf.point([lng1, lat1]);
|
var bearing = turf.bearing(point1, point2);
|
var options = { units: 'metres' };
|
var rate = 0.4
|
if(angle > 70){
|
rate = 0.8
|
}
|
var distance = Cesium.Cartesian3.distance(rotatedPositions[last],rotatedPositions[i])*rate;
|
var height = cartographic1.height
|
var destination = turf.destination(point2, distance,bearing, options);
|
var newPoint = Cesium.Cartesian3.fromDegrees(destination.geometry.coordinates[0], destination.geometry.coordinates[1],0);
|
newpositions.push(newPoint)
|
if(i == 6){
|
newpositions.push(rotatedPositions[7])
|
}
|
}
|
rotatedPositions = newpositions
|
}*/
|
|
/**
|
var polygon = this.viewer.entities.add({
|
polygon: {
|
hierarchy: rotatedPositions,
|
material: Cesium.Color.RED.withAlpha(0.5) // 设置材料和透明度
|
}
|
}); */
|
|
/** 缩放倍数
|
let scaleFactor = 1/Math.cos(this.roateAngle)
|
rotatedPositions = this.scalePolygon(rotatedPositions,scaleFactor); */
|
/**
|
debugger
|
this.viewer.entities.add({
|
polygon: {
|
hierarchy: rotatedPositions,
|
material: Cesium.Color.YELLOW.withAlpha(0.5) // 设置材料和透明度
|
|
}
|
});*/
|
|
/**
|
let positions1 = []
|
if(!(angle>=0 && angle <=90)){
|
positions1[0] = positions[2]
|
positions1[1] = positions[1]
|
positions1[2] = positions[0]
|
positions1[3] = positions[7]
|
positions1[4] = positions[6]
|
positions1[5] = positions[5]
|
positions1[6] = positions[4]
|
positions1[7] = positions[3]
|
positions = positions1
|
} */
|
|
if (isRight) {
|
//向右画
|
this.roateAngle = angle
|
this.hisroateAngle = this.roateAngle
|
this.HIS_NOR_H = -this.NOR_H
|
this.isRight = true
|
} else {
|
//向左画
|
this.roateAngle = angle
|
this.hisroateAngle = this.roateAngle
|
this.HIS_NOR_H = -this.NOR_H
|
this.isRight = false
|
}
|
|
// 计算几何中心
|
var ellipsoid = this.viewer.scene.globe.ellipsoid
|
|
/**
|
let maxHeight = 0
|
positions.forEach(item=>{
|
var cartographic = ellipsoid.cartesianToCartographic(item);
|
var height = cartographic.height
|
maxHeight +=height;
|
})*/
|
|
var cartographic = ellipsoid.cartesianToCartographic(positions[0])
|
var height = cartographic.height
|
var cartographic1 = ellipsoid.cartesianToCartographic(positions[1])
|
var height1 = cartographic1.height
|
var cartographic2 = ellipsoid.cartesianToCartographic(positions[2])
|
var height2 = cartographic2.height
|
this.avHeight = (height + height1 + height2) / 3
|
//this.avHeight = 0;
|
|
//this.avHeight = maxHeight/positions.length
|
this.positions = positions
|
this.pointA = this.positions[0]
|
this.pointB = this.positions[1]
|
this.cleanEntity()
|
this.polyArr = []
|
this.polyArr = positions
|
this.oldArray.push(...this.polyArr)
|
//计算旁向间距
|
this.updataOverLap({
|
crossLap: 70 //在LeftBox.vue中给的默认值是70
|
})
|
//开始计算航点
|
// that.beginCalc();
|
//计算每个线段长度
|
}
|
|
projectPolygonToPlane (points) {
|
const centroid = this.computeCentroid(points)
|
const normal = this.computePlaneNormalUsingNewell(points, centroid)
|
const { right, forward } = this.computeLocalBasis(centroid, normal)
|
|
return points.map((point) => {
|
const delta = Cesium.Cartesian3.subtract(point, centroid, new Cesium.Cartesian3())
|
return Cesium.Cartesian3.fromDegrees(Cesium.Cartesian3.dot(delta, right), Cesium.Cartesian3.dot(delta, forward), 0)
|
})
|
}
|
|
computeCentroid (points) {
|
const centroid = new Cesium.Cartesian3()
|
points.forEach((point) => Cesium.Cartesian3.add(point, centroid, centroid))
|
Cesium.Cartesian3.multiplyByScalar(centroid, 1 / points.length, centroid)
|
return centroid
|
}
|
|
// 使用 Newell 算法计算法向量(关键修复)
|
computePlaneNormalUsingNewell (editPointArr) {
|
const a = editPointArr[0]
|
const b = editPointArr[2]
|
const c = editPointArr[4]
|
const v1 = Cesium.Cartesian3.subtract(b, a, new Cesium.Cartesian3())
|
const v2 = Cesium.Cartesian3.subtract(c, a, new Cesium.Cartesian3())
|
const normal = Cesium.Cartesian3.cross(v2, v1, new Cesium.Cartesian3())
|
return normal
|
}
|
|
// 重构局部坐标系构建(修复关键点)
|
computeLocalBasis (normal) {
|
// 动态选择参考轴避免与法向量平行
|
const refAxis = Math.abs(Cesium.Cartesian3.dot(normal, Cesium.Cartesian3.UNIT_X)) < 0.9 ? Cesium.Cartesian3.UNIT_X : Cesium.Cartesian3.UNIT_Y
|
|
// 计算右向量(right = refAxis - (normal·refAxis) * normal)
|
const dot = Cesium.Cartesian3.dot(normal, refAxis)
|
const right = Cesium.Cartesian3.multiplyByScalar(normal, dot, new Cesium.Cartesian3())
|
Cesium.Cartesian3.subtract(refAxis, right, right)
|
|
// 处理极小值情况
|
if (Cesium.Cartesian3.magnitudeSquared(right) < 1e-6) {
|
Cesium.Cartesian3.clone(Cesium.Cartesian3.UNIT_Z, right)
|
}
|
Cesium.Cartesian3.normalize(right, right)
|
|
// 前向向量(forward = normal × right)
|
const forward = Cesium.Cartesian3.cross(normal, right, new Cesium.Cartesian3())
|
Cesium.Cartesian3.normalize(forward, forward)
|
|
return { right, forward }
|
}
|
|
// 计算多边形的中心点
|
calculateCentroid (positions) {
|
var sumX = 0
|
var sumY = 0
|
var sumZ = 0
|
for (var i = 0; i < 2; i++) {
|
//sumX += positions[i].x;
|
//sumY += positions[i].y;
|
//sumZ += positions[i].z;
|
|
sumX += positions[i].x
|
sumY += positions[i].y
|
sumZ += positions[i].z
|
}
|
var centroid = new Cesium.Cartesian3(sumX / 2, sumY / 2, sumZ / 2)
|
return centroid
|
}
|
|
// 缩放多边形
|
scalePolygon (positions, scaleFactor) {
|
var centroid = this.calculateCentroid(positions)
|
|
var scaledPositions = []
|
for (var i = 1; i < positions.length - 1; i++) {
|
var position = positions[i]
|
var vector = Cesium.Cartesian3.subtract(position, centroid, new Cesium.Cartesian3())
|
var scaledVector = Cesium.Cartesian3.multiplyByScalar(vector, scaleFactor, new Cesium.Cartesian3())
|
var scaledPosition = Cesium.Cartesian3.add(centroid, scaledVector, new Cesium.Cartesian3())
|
scaledPositions.push(scaledPosition)
|
}
|
|
return scaledPositions
|
}
|
|
roatePositionAngle (positionArr, angle) {
|
/**
|
let pointA = this.pointA;
|
// 计算旋转轴(方向向量 AB)
|
const direction = Cesium.Cartesian3.subtract(this.pointB, this.pointA, new Cesium.Cartesian3());
|
Cesium.Cartesian3.normalize(direction, direction); // 单位化
|
// 构建旋转矩阵
|
const que = Cesium.Quaternion.fromAxisAngle(direction, Cesium.Math.toRadians(angle));
|
const rotationMatrix = Cesium.Matrix3.fromQuaternion(que);
|
|
//let originalPositions = newPositions.slice(2,newPositions.length)
|
|
// 计算旋转后的顶点位置
|
const rotatedPositions = positionArr.map((position) => {
|
// 将点移动到局部坐标系(以 A 为原点)
|
|
const localPosition = Cesium.Cartesian3.subtract(position, pointA, new Cesium.Cartesian3());
|
// 应用旋转矩阵
|
const rotatedPosition = Cesium.Matrix3.multiplyByVector(rotationMatrix, localPosition, new Cesium.Cartesian3());
|
|
// 将点移回全局坐标系
|
return Cesium.Cartesian3.add(rotatedPosition, pointA, new Cesium.Cartesian3());
|
}); */
|
let A = this.pointA
|
let B = this.pointB
|
let isRight = this.isRight
|
let neweditPointArr = []
|
for (var i = 0; i < positionArr.length; i++) {
|
const C = positionArr[i]
|
// 1. 计算AB轴方向向量(单位化)
|
const axis = Cesium.Cartesian3.subtract(B, A, new Cesium.Cartesian3())
|
Cesium.Cartesian3.normalize(axis, axis)
|
// 2. 计算向量AC(从A到C)
|
const vecAC = Cesium.Cartesian3.subtract(C, A, new Cesium.Cartesian3())
|
// 3. 创建绕AB轴的旋转矩阵
|
const angleRadians = Cesium.Math.toRadians(isRight ? angle : angle - 180)
|
//const angleRadians = Cesium.Math.toRadians(angle>0&& angle<=90?angle:angle-180);
|
const quaternion = Cesium.Quaternion.fromAxisAngle(axis, angleRadians)
|
// 4. 将四元数转换为旋转矩阵(Matrix3)
|
const rotationMatrix = Cesium.Matrix3.fromQuaternion(quaternion)
|
// 5. 应用旋转矩阵到向量AC
|
const rotatedVecAC = Cesium.Matrix3.multiplyByVector(rotationMatrix, vecAC, new Cesium.Cartesian3())
|
// 5. 计算新点C的坐标
|
const newC = Cesium.Cartesian3.add(A, rotatedVecAC, new Cesium.Cartesian3())
|
neweditPointArr.push(newC)
|
}
|
return neweditPointArr
|
}
|
}
|
|
|
// 绘制边角点
|
let pointCollection = new Cesium.PointPrimitiveCollection()
|
let handler = null
|
let movePoint, panel
|
let pointprimitive
|
let isDrag = false
|
|
let isRegistMove = false
|
|
let faceAirLineTool
|
|
|
let allPoints = {}
|
|
|
function safeCartesianToLonLat (cartesian) {
|
try {
|
if (!cartesian || !Cesium.defined(cartesian)) {
|
throw new Error('无效的笛卡尔坐标')
|
}
|
|
const cartographic = Cesium.Cartographic.fromCartesian(cartesian)
|
|
// 检查是否为有效的地理坐标
|
if (!isFinite(cartographic.longitude) || !isFinite(cartographic.latitude)) {
|
throw new Error('无法转换为有效的地理坐标')
|
}
|
|
return {
|
longitude: Cesium.Math.toDegrees(cartographic.longitude),
|
latitude: Cesium.Math.toDegrees(cartographic.latitude),
|
height: cartographic.height
|
}
|
} catch (error) {
|
console.error('坐标转换错误:', error)
|
return null
|
}
|
}
|
|
function getArea (e) {
|
allPoints = {
|
...e[0],
|
areaList: e[0].areaList.map((item) => {
|
return safeCartesianToLonLat(item)
|
}),
|
points: e[0].points.map((item) => {
|
return safeCartesianToLonLat(item)
|
})
|
}
|
|
console.log('allPoints==', allPoints)
|
}
|
|
initFaceLine()
|
//初始化航线绘制
|
function initFaceLine () {
|
if (!faceAirLineTool) {
|
//创建面航线工具类
|
faceAirLineTool = new SideFaceAirLine(viewer, {
|
dock: {
|
address: null,
|
bindingTime: 1752128271233,
|
boundStatus: '1',
|
childSn: '1581F5BMD228Q00A2F9J',
|
children: null,
|
childrenVo: [
|
{
|
address: null,
|
bindingTime: 1746862495145,
|
boundStatus: '0',
|
childSn: '',
|
children: null,
|
childrenVo: null,
|
compatibleStatus: '1',
|
coordinate: null,
|
createDept: '1871739307690668032',
|
debugger: null,
|
deptName: '精景慧城作业区',
|
deviceClass: null,
|
deviceId: '1900015205962878976',
|
deviceInfo: {
|
rth_altitude: 150,
|
country: 'CN',
|
latitude: '34.3133992800426',
|
firmware_version: '10.01.0014',
|
storage: {}
|
},
|
deviceModel: 'Matrice 30T',
|
deviceName: 'M30T',
|
deviceSecret: 'f04f43275a4a2f793daf9085f518e817',
|
deviceSn: '1581F5BMD228Q00A2F9J',
|
deviceStatus: '0',
|
deviceType: 67,
|
domain: '0',
|
eventDesc: null,
|
eventStatus: '1',
|
firmwareVersion: '10.01.0014',
|
isLoadSpeaker: 0,
|
loginTime: 1754503673413,
|
nonce: 'bbd1355f6ddd41d843d993a5df88a8db',
|
onlineStatus: '0',
|
percent: 0,
|
projectCode: null,
|
projectId: '1871739307220905986',
|
projectName: null,
|
rebootStatus: null,
|
simulateMission: 0,
|
subType: 1
|
}
|
],
|
compatibleStatus: '1',
|
coordinate: { x: 108.801663746, y: 34.313398518, z: 348.5820007324219, m: 'NaN' },
|
createDept: '1871739307690668032',
|
debugger: null,
|
deptName: '精景慧城作业区',
|
deviceClass: null,
|
deviceId: '1900015205954490368',
|
deviceInfo: {
|
sdr: {},
|
first_power_on: 1631945855969,
|
electric_supply_voltage: 201,
|
latitude: '34.313398518',
|
working_current: 820
|
},
|
deviceModel: 'DJI Dock',
|
deviceName: 'DJI Dock',
|
deviceSecret: '05ac8e16304bcd50d838dfc079775f0f',
|
deviceSn: '4TADL21001002X',
|
deviceStatus: '0',
|
deviceType: 1,
|
domain: '3',
|
eventDesc: null,
|
eventStatus: '1',
|
firmwareVersion: '10.01.0203',
|
isLoadSpeaker: 0,
|
loginTime: 1754529888773,
|
nonce: '83a22e1bc30849342e00f0e4a3bd1523',
|
onlineStatus: '1',
|
percent: 0,
|
projectCode: null,
|
projectId: '1871739307220905986',
|
projectName: null,
|
rebootStatus: null,
|
simulateMission: 0,
|
subType: 0
|
}, //机场对象
|
height: 30, //航线高度
|
startFlyPoint: 120, //机场的高程
|
heightModel: 'relativeToStartPoint' //想对起飞点高度
|
})
|
|
// viewer.scene.globe.depthTestAgainstTerrain = true
|
// faceAirLineTool.startDrawRegion();
|
if (!isRegistMove) {
|
isRegistMove = true
|
handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
|
pointprimitive = viewer.scene.primitives.add(pointCollection)
|
drawing()
|
}
|
}
|
}
|
|
}
|
})
|
.use(ElementPlus)
|
.mount('#app')
|
</script>
|
|
</html>
|