feat:实现多边形、矩形、圆形绘制和多边形面积测量

devzpx
zhaipx 4 months ago
parent 819d0d32e5
commit 7a2cdfa8da

@ -17,7 +17,10 @@
"preinstall": "node ./scripts/preinstall.js" "preinstall": "node ./scripts/preinstall.js"
}, },
"dependencies": { "dependencies": {
"@vicons/carbon": "^0.13.0",
"@vicons/fa": "^0.13.0",
"@vicons/ionicons5": "^0.13.0", "@vicons/ionicons5": "^0.13.0",
"@vicons/material": "^0.13.0",
"axios": "^1.6.7", "axios": "^1.6.7",
"cesium": "1.108", "cesium": "1.108",
"cesium-navigation-es6": "^3.0.8", "cesium-navigation-es6": "^3.0.8",

@ -5,9 +5,18 @@ settings:
excludeLinksFromLockfile: false excludeLinksFromLockfile: false
dependencies: dependencies:
'@vicons/carbon':
specifier: ^0.13.0
version: 0.13.0
'@vicons/fa':
specifier: ^0.13.0
version: 0.13.0
'@vicons/ionicons5': '@vicons/ionicons5':
specifier: ^0.13.0 specifier: ^0.13.0
version: 0.13.0 version: 0.13.0
'@vicons/material':
specifier: ^0.13.0
version: 0.13.0
axios: axios:
specifier: ^1.6.7 specifier: ^1.6.7
version: 1.6.7 version: 1.6.7
@ -1268,10 +1277,22 @@ packages:
resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==}
dev: true dev: true
/@vicons/carbon@0.13.0:
resolution: {integrity: sha512-Z/jExyyS4gsXJc66oTqV/j98nsaiX2JlQ0IUwu9Ms3rztf8VOHEQRuX8Jey1/zbxJpFY/tU+bWvKPRFYGIvCWQ==, tarball: https://registry.npmmirror.com/@vicons/carbon/-/carbon-0.13.0.tgz}
dev: false
/@vicons/fa@0.13.0:
resolution: {integrity: sha512-BFcDewcT78fSn4Y/fOgqlswbLUEW3+qJK2iJiNtgmkMzadBVpDXhNyVKsYM3V2uKPvDUrZT0JCWDWVRCiBXJZA==, tarball: https://registry.npmmirror.com/@vicons/fa/-/fa-0.13.0.tgz}
dev: false
/@vicons/ionicons5@0.13.0: /@vicons/ionicons5@0.13.0:
resolution: {integrity: sha512-zvZKBPjEXKN7AXNo2Na2uy+nvuv6SP4KAMQxpKL2vfHMj0fSvuw7JZcOPCjQC3e7ayssKnaoFVAhbYcW6v41qQ==, tarball: https://registry.npmmirror.com/@vicons/ionicons5/-/ionicons5-0.13.0.tgz} resolution: {integrity: sha512-zvZKBPjEXKN7AXNo2Na2uy+nvuv6SP4KAMQxpKL2vfHMj0fSvuw7JZcOPCjQC3e7ayssKnaoFVAhbYcW6v41qQ==, tarball: https://registry.npmmirror.com/@vicons/ionicons5/-/ionicons5-0.13.0.tgz}
dev: false dev: false
/@vicons/material@0.13.0:
resolution: {integrity: sha512-lKVxFNprM+CaBkUH3gt6VjIeiMsKQl2zARQMwTCZruQl2vRHzyeZiKeCflWS99CEfv2JzX/6y697smxlzyxcVw==, tarball: https://registry.npmmirror.com/@vicons/material/-/material-0.13.0.tgz}
dev: false
/@vitejs/plugin-vue@5.0.4(vite@5.1.5)(vue@3.4.21): /@vitejs/plugin-vue@5.0.4(vite@5.1.5)(vue@3.4.21):
resolution: {integrity: sha512-WS3hevEszI6CEVEx28F8RjTX97k3KsrcY6kvTg7+Whm5y3oYvcqzVeGCU3hxSAn4uY2CLCkeokkGKpoctccilQ==} resolution: {integrity: sha512-WS3hevEszI6CEVEx28F8RjTX97k3KsrcY6kvTg7+Whm5y3oYvcqzVeGCU3hxSAn4uY2CLCkeokkGKpoctccilQ==}
engines: {node: ^18.0.0 || >=20.0.0} engines: {node: ^18.0.0 || >=20.0.0}

@ -10,7 +10,7 @@
</n-message-provider> </n-message-provider>
</template> </template>
<script setup lang="ts"> <script setup>
import SceneViewer from './components/map/SceneViewer.vue' import SceneViewer from './components/map/SceneViewer.vue'
import BottomBar from '@/components/map/BottomBar.vue' import BottomBar from '@/components/map/BottomBar.vue'
import Toolbar from "@/components/toolbar.vue"; import Toolbar from "@/components/toolbar.vue";

@ -1,22 +1,243 @@
import * as Cesium from 'cesium' import * as Cesium from 'cesium'
import {Cartesian3} from 'cesium'
export default class MeasureDistance { export default class MeasureDistance {
constructor(viewer) { constructor(viewer) {
this.viewer = viewer this.viewer = viewer
this.scene = viewer.scene
this.isMeasure = false this.isMeasure = false
this.initEvents()
this.positions = [] this.positions = []
this.temPositions = [] // 鼠标移动时产生的临时点 this.temPositions = [] // 鼠标移动时产生的临时点
this.vertexEntities = [] // 节点元素 this.vertexEntities = [] // 节点元素
this.lineEntity = undefined // 折线元素 this.lineEntity = undefined // 距离测量折线元素
this.totalDistance = 0 // 总距离 this.lineEntitys = [] // 距离测量折线元素数组,每完成一次距离测量,将折线元素加入此数组
this.totalDistance = 0 // 总距离
this.activeShapePoints = [] //面积测量多边形顶点
this.polygon = undefined
this.measAreaStatus = false //是否在测量面积
this.graphics = []
this.graphicStyle = {
borderColor: Cesium.Color.BLUE,
borderWidth: 1,
material: Cesium.Color.GREEN.withAlpha(0.5),
}
} }
initEvents(){ stopAreaMeasure(){
if (!this.measAreaStatus) return;
this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
this.handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE);
this.handler.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK);
this.measAreaStatus = false;
this.viewer._element.style.cursor = 'default';
this.viewer.enableCursorStyle = true;
}
//清空绘制多边形和label
clearAreaEntity() {
//清除多边形
this.viewer.entities.removeById('4399');
this.viewer.entities.removeById('4390');
this.polygon = undefined;
this.activeShapePoints = [];
}
activateAreaMeasure(){
this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas)
this.viewer.scene.globe.depthTestAgainstTerrain = true
// 清除可能会用到的监听事件
if (this.handler) {
this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
this.handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE);
this.handler.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK);
}
this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas) this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas)
this.measAreaStatus = true;
this.viewer._element.style.cursor = 'crosshair';
this.viewer.enableCursorStyle = true;
//鼠标左键--确定选中点
this.handler.setInputAction((event) => {
let ray = viewer.camera.getPickRay(event.position);
let earthPosition = viewer.scene.globe.pick(ray, viewer.scene)
//鼠标开始点击多边形的第一个点
if (this.activeShapePoints.length === 0) {
//将第一个左击的点添加到多边形顶点集合中
this.activeShapePoints.push(earthPosition)
//多边形的坐标采用回调的形式
//边线顶点
let linePoints = new Cesium.CallbackProperty(() => {
return this.activeShapePoints.concat([this.activeShapePoints[0]]);
}, false)
//多边形顶点
let dynamicPositions = new Cesium.CallbackProperty(() => {
return new Cesium.PolygonHierarchy(this.activeShapePoints)
}, false)
//添加一个多边形
this.polygon = new Cesium.Entity({
name: "area polygon",
id: '4399',
polyline: {
positions: linePoints,
width: 1,
material: Cesium.Color.RED.withAlpha(0.8),
heightReference: Cesium.HeightReference.NONE,
clampToGround: true
},
polygon: {
hierarchy: dynamicPositions,
material: Cesium.Color.ORANGERED.withAlpha(0.8),
heightReference: Cesium.HeightReference.NONE
// outlineColor: Cesium.Color.RED.withAlpha(0.7),
// height: 0
},
})
this.polygon.GeoType = "Polygon"
this.viewer.entities.add(this.polygon)
}
this.viewer.scene.requestRender()
//将鼠标点击的点添加到多边形顶点集合中
this.activeShapePoints.push(earthPosition)
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
//鼠标移动--实时绘制多边形
this.handler.setInputAction((movement) => {
//获取鼠标所在的位置
const ray = this.viewer.camera.getPickRay(movement.endPosition)
const newPosition = this.viewer.scene.globe.pick(ray, this.viewer.scene)
//已经定义了polygon
if (Cesium.defined(this.polygon)) {
//删除多边形顶点中最新的一个点
this.activeShapePoints.pop()
//将最新获取到的点添加到多边形顶点集合中
this.activeShapePoints.push(newPosition)
}
if (this.activeShapePoints.length === 3) {
this.polygon.polygon.heightReference = Cesium.HeightReference.CLAMP_TO_GROUND;
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
//鼠标右键--结束绘制
this.handler.setInputAction((event) => {
//删除最后一个点(重复添加的点)
this.activeShapePoints.pop()
this.polygon.pottingPoint = this.activeShapePoints
this._showResultArea()
this.stopAreaMeasure()
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
}
_showResultArea(){
let text = "面积:" + this.getPolygonArea(this.polygon.pottingPoint)
let centerPoint = this._getCenterOfGravityPoint(this.polygon.pottingPoint)
this._addLabel(centerPoint, text)
}
/*角度*/
_Angle(p1, p2, p3) {
let angle =this._Bearing(p2, p1) - this._Bearing(p2, p3);
if (angle < 0) {
angle += 360;
}
return angle;
} }
//激活 /*方向*/
_Bearing(from, to) {
from = Cesium.Cartographic.fromCartesian(from);
to = Cesium.Cartographic.fromCartesian(to);
let lat1 = from.latitude;
let lon1 = from.longitude;
let lat2 = to.latitude;
let lon2 = to.longitude;
let angle = -Math.atan2(Math.sin(lon1 - lon2) * Math.cos(lat2), Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(lon1 - lon2));
if (angle < 0) {
angle += Math.PI * 2.0;
}
let degreesPerRadian = 180.0 / Math.PI; //弧度转化为角度
angle = angle * degreesPerRadian; //角度
return angle;
}
distance(point1, point2) {
let point1cartographic = Cesium.Cartographic.fromCartesian(point1);
let point2cartographic = Cesium.Cartographic.fromCartesian(point2);
/**根据经纬度计算出距离**/
let geodesic = new Cesium.EllipsoidGeodesic();
geodesic.setEndPoints(point1cartographic, point2cartographic);
let s = geodesic.surfaceDistance;
//返回两点之间的距离
s = Math.sqrt(Math.pow(s, 2) + Math.pow(point2cartographic.height - point1cartographic.height, 2));
return s;
}
getPolygonArea(points){
let res = 0;
//拆分三角曲面
for (let i = 0; i < points.length - 2; i++) {
let j = (i + 1) % points.length;
let k = (i + 2) % points.length;
let totalAngle = this._Angle(points[i], points[j], points[k]);
let dis_temp1 = this.distance(points[j], points[0]);
let dis_temp2 = this.distance(points[k], points[0]);
res += dis_temp1 * dis_temp2 * Math.sin(totalAngle) / 2;
}
if (res < 1000000) {
res = Math.abs(res).toFixed(4) + " 平方米";
} else {
res = Math.abs(res / 1000000.0).toFixed(4) + " 平方公里";
}
return res
}
_getCenterOfGravityPoint(mPoints){
let centerPoint = mPoints[0];
for (let i = 1; i < mPoints.length; i++) {
centerPoint = Cesium.Cartesian3.midpoint(centerPoint, mPoints[i], new Cesium.Cartesian3());
}
return centerPoint
}
_addLabel(centerPoint, text){
return this.viewer.entities.add(
new Cesium.Entity({
name: 'area label',
id: '4390',
position: centerPoint,
label:{
text: text,
font: "2.5rem sans-serif",
fillColor: Cesium.Color.WHITE,
style: Cesium.LabelStyle.FILL,
eyeOffset: new Cartesian3(0,0,50),
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.CENTER,
scale: 0.4,
showBackground: true,
backgroundColor: new Cesium.Color(0.165, 0.165, 0.165, 0.99),
backgroundPadding: new Cesium.Cartesian2(15, 7),
clampToGround: true,
heightReference:Cesium.HeightReference.CLAMP_TO_GROUND,
disableDepthTestDistance:99000000,
},
})
)
}
// -------------------------------------------//
//激活测距
activate() { activate() {
this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas)
this.viewer.scene.globe.depthTestAgainstTerrain = true
this.registerEvents(); //注册鼠标事件 this.registerEvents(); //注册鼠标事件
this.isMeasure = true; this.isMeasure = true;
this.totalDistance = 0 // 总距离 this.totalDistance = 0 // 总距离
@ -25,32 +246,40 @@ export default class MeasureDistance {
this.viewer.enableCursorStyle = true; this.viewer.enableCursorStyle = true;
this.temPositions = []; this.temPositions = [];
this.positions = []; this.positions = [];
this.viewer.scene.globe.depthTestAgainstTerrain = true
} }
//禁用 //禁用测距
deactivate() { deactivate() {
if (!this.isMeasure) return; if (!this.isMeasure) return;
this.unRegisterEvents(); this.unRegisterEvents();
this.viewer._element.style.cursor = 'default'; this.viewer._element.style.cursor = 'default';
this.viewer.enableCursorStyle = true; this.viewer.enableCursorStyle = true;
this.isMeasure = false; this.isMeasure = false;
this.viewer.scene.globe.depthTestAgainstTerrain = false this.lineEntitys.push(this.lineEntity)
}
//清空绘制 }
clear() {
//清除线对象
this.viewer.entities.remove(this.lineEntity);
this.lineEntity = undefined;
//清空绘制(测距)
clearDisEntity() {
//清除折线
this.lineEntitys.forEach(item => {
this.viewer.entities.remove(item);
});
//清除节点 //清除节点
this.vertexEntities.forEach(item => { this.vertexEntities.forEach(item => {
this.viewer.entities.remove(item); this.viewer.entities.remove(item);
}); });
this.vertexEntities = [];
this.positions = []
this.temPositions = [] // 鼠标移动时产生的临时点
this.vertexEntities = [] // 节点元素
this.lineEntity = undefined // 距离测量折线元素
this.lineEntitys = [] // 距离测量折线元素数组,每完成一次距离测量,将折线元素加入此数组
this.totalDistance = 0 // 总距离
} }
//创建线对象
//创建线对象(测距)
createLineEntity() { createLineEntity() {
this.lineEntity = this.viewer.entities.add({ this.lineEntity = this.viewer.entities.add({
polyline: { polyline: {
@ -59,14 +288,12 @@ export default class MeasureDistance {
}, false), }, false),
width: 2, width: 2,
material: Cesium.Color.YELLOW, material: Cesium.Color.YELLOW,
// depthFailMaterial: Cesium.Color.YELLOW,
clampToGround: true, clampToGround: true,
disableDepthTestDistance:99000000, },
heightReference:Cesium.HeightReference.CLAMP_TO_GROUND
}
}) })
this.viewer.scene.requestRender()
} }
//创建线节点 //创建线节点(测距)
createVertex() { createVertex() {
let vertexEntity = new Cesium.Entity({ let vertexEntity = new Cesium.Entity({
id: "MeasureDistanceVertex" + this.positions[this.positions.length - 1], id: "MeasureDistanceVertex" + this.positions[this.positions.length - 1],
@ -91,14 +318,15 @@ export default class MeasureDistance {
showBackground: true, showBackground: true,
backgroundColor: new Cesium.Color(0.165, 0.165, 0.165, 0.5), backgroundColor: new Cesium.Color(0.165, 0.165, 0.165, 0.5),
backgroundPadding: new Cesium.Cartesian2(10, 10), backgroundPadding: new Cesium.Cartesian2(10, 10),
clampToGround: true,
heightReference:Cesium.HeightReference.CLAMP_TO_GROUND,
disableDepthTestDistance:99000000, disableDepthTestDistance:99000000,
heightReference:Cesium.HeightReference.CLAMP_TO_GROUND
}, },
}); });
this.vertexEntities.push(vertexEntity) this.vertexEntities.push(vertexEntity)
this.viewer.entities.add(vertexEntity) this.viewer.entities.add(vertexEntity)
} }
//创建起点 //创建起点(测距)
createStartEntity() { createStartEntity() {
let vertexEntity = this.viewer.entities.add({ let vertexEntity = this.viewer.entities.add({
position: this.positions[0], position: this.positions[0],
@ -109,13 +337,14 @@ export default class MeasureDistance {
color: Cesium.Color.RED, color: Cesium.Color.RED,
outlineColor: Cesium.Color.WHITE, outlineColor: Cesium.Color.WHITE,
outlineWidth: 1, outlineWidth: 1,
disableDepthTestDistance:99000000, clampToGround: true,
heightReference:Cesium.HeightReference.CLAMP_TO_GROUND, heightReference:Cesium.HeightReference.CLAMP_TO_GROUND,
disableDepthTestDistance:99000000,
}, },
}); });
this.vertexEntities.push(vertexEntity) this.vertexEntities.push(vertexEntity)
} }
//创建终点节点 //创建终点节点(测距)
createEndEntity() { createEndEntity() {
let vertexEntity = this.viewer.entities.add({ let vertexEntity = this.viewer.entities.add({
position: this.positions[this.positions.length - 1], position: this.positions[this.positions.length - 1],
@ -129,38 +358,32 @@ export default class MeasureDistance {
eyeOffset: new Cesium.Cartesian3(0, 0, 30), eyeOffset: new Cesium.Cartesian3(0, 0, 30),
horizontalOrigin: Cesium.HorizontalOrigin.CENTER, horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM, verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
// distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 20000), scale: 0.4,
scale: 0.5,
showBackground: true, showBackground: true,
backgroundColor: new Cesium.Color(0.165, 0.165, 0.165, 0.99), backgroundColor: new Cesium.Color(0.165, 0.165, 0.165, 0.99),
backgroundPadding: new Cesium.Cartesian2(10, 10), backgroundPadding: new Cesium.Cartesian2(10, 10),
disableDepthTestDistance:99000000, disableDepthTestDistance:99000000,
heightReference:Cesium.HeightReference.CLAMP_TO_GROUND heightReference:Cesium.HeightReference.CLAMP_TO_GROUND
}, },
// billboard: {
// // image: "../../static/images/end.png",
// scaleByDistance: new Cesium.NearFarScalar(300, 1, 1200, 0.4), //设置随图缩放距离和比例
// distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 20000), //设置可见距离 10000米可见
// verticalOrigin: Cesium.VerticalOrigin.BOTTOM
// },
point: { point: {
pixelSize: 10, pixelSize: 10,
color: Cesium.Color.RED, color: Cesium.Color.RED,
outlineColor: Cesium.Color.WHITE, outlineColor: Cesium.Color.WHITE,
outlineWidth: 1, outlineWidth: 1,
clampToGround: true,
heightReference:Cesium.HeightReference.CLAMP_TO_GROUND, heightReference:Cesium.HeightReference.CLAMP_TO_GROUND,
disableDepthTestDistance:99000000 disableDepthTestDistance:99000000
}, },
}); });
this.vertexEntities.push(vertexEntity) this.vertexEntities.push(vertexEntity)
} }
//注册鼠标事件 //注册鼠标事件(测距)
registerEvents() { registerEvents() {
this.leftClickEvent(); this.leftClickEvent();
this.rightClickEvent(); this.rightClickEvent();
this.mouseMoveEvent(); this.mouseMoveEvent();
} }
//左键点击事件 //左键点击事件(测距)
leftClickEvent() { leftClickEvent() {
//单击鼠标左键画点点击事件 //单击鼠标左键画点点击事件
this.handler.setInputAction(e => { this.handler.setInputAction(e => {
@ -180,7 +403,7 @@ export default class MeasureDistance {
}, Cesium.ScreenSpaceEventType.LEFT_CLICK); }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
} }
//鼠标移动事件 //鼠标移动事件(测距)
mouseMoveEvent() { mouseMoveEvent() {
this.handler.setInputAction(e => { this.handler.setInputAction(e => {
if (!this.isMeasure) return; if (!this.isMeasure) return;
@ -193,18 +416,18 @@ export default class MeasureDistance {
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE); }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
} }
//处理鼠标移动 //处理鼠标移动(测距)
handleMoveEvent(position) { handleMoveEvent(position) {
if (this.positions.length < 1) return; if (this.positions.length < 1) return;
this.temPositions = this.positions.concat(position); this.temPositions = this.positions.concat(position);
} }
//右键事件 //右键事件(测距)
rightClickEvent() { rightClickEvent() {
this.handler.setInputAction(e => { this.handler.setInputAction(e => {
if (!this.isMeasure || this.positions.length < 1) { if (!this.isMeasure || this.positions.length < 1) {
this.deactivate(); this.deactivate();
this.clear() this.clearDisEntity()
} else { } else {
this.createEndEntity(); this.createEndEntity();
this.lineEntity.polyline = { this.lineEntity.polyline = {
@ -218,7 +441,7 @@ export default class MeasureDistance {
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK); }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
} }
//解除鼠标事件 //解除鼠标事件(测距)
unRegisterEvents() { unRegisterEvents() {
this.handler.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK); this.handler.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK);
this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK); this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
@ -239,4 +462,240 @@ export default class MeasureDistance {
this.totalDistance += geodesic.surfaceDistance/1000 this.totalDistance += geodesic.surfaceDistance/1000
return (geodesic.surfaceDistance/1000).toFixed(3); return (geodesic.surfaceDistance/1000).toFixed(3);
} }
clearDraw(){
if(this.graphics.length<1)
return true;
this._stopDraw();
this.graphics.forEach(graphic => {
this.viewer.entities.remove(graphic)
})
this.graphics = []
}
drawGraphics(key){
this.viewer.scene.globe.depthTestAgainstTerrain = true
// 清除可能会用到的监听事件
if (this.handler) {
this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
this.handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE);
this.handler.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK);
}
this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas)
this.viewer._element.style.cursor = 'crosshair';
this.viewer.enableCursorStyle = true;
if(key==='polygon'){
this._drawPolygon()
}
else if(key==='rec'){
this._drawRec()
}
else if(key==='circle'){
this._drawCircle()
}
}
_stopDraw(){
this.viewer.scene.globe.depthTestAgainstTerrain = false
// 清除可能会用到的监听事件
this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
this.handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE);
this.handler.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK);
this.viewer._element.style.cursor = 'default';
this.viewer.enableCursorStyle = true;
}
_drawPolygon(){
let aPolygon;
let drawPolygonPts = []
//鼠标左键--确定选中点
this.handler.setInputAction((event) => {
let ray = this.viewer.camera.getPickRay(event.position);
let earthPosition = this.scene.globe.pick(ray, this.scene)
//鼠标开始点击多边形的第一个点
if (drawPolygonPts.length === 0) {
//将第一个左击的点添加到多边形顶点集合中
drawPolygonPts.push(earthPosition)
//多边形的坐标采用回调的形式
//边线顶点
let linePoints = new Cesium.CallbackProperty(() => {
return drawPolygonPts.concat([drawPolygonPts[0]]);
}, false)
//多边形顶点
let dynamicPositions = new Cesium.CallbackProperty(() => {
return new Cesium.PolygonHierarchy(drawPolygonPts)
}, false)
//添加一个多边形
aPolygon = this.viewer.entities.add({
name: "draw polygon",
polyline: {
positions: linePoints,
width: this.graphicStyle.borderWidth,
material: this.graphicStyle.borderColor,
clampToGround: true
},
polygon: {
hierarchy: dynamicPositions,
material: this.graphicStyle.material,
heightReference: Cesium.HeightReference.NONE
},
})
}
this.viewer.scene.requestRender()
//将鼠标点击的点添加到多边形顶点集合中
drawPolygonPts.push(earthPosition)
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
//鼠标移动--实时绘制多边形
this.handler.setInputAction((movement) => {
//获取鼠标所在的位置
const ray = this.viewer.camera.getPickRay(movement.endPosition)
const newPosition = this.viewer.scene.globe.pick(ray, this.viewer.scene)
//已经定义了polygon
if (Cesium.defined(aPolygon)) {
//删除多边形顶点中最新的一个点
drawPolygonPts.pop()
//将最新获取到的点添加到多边形顶点集合中
drawPolygonPts.push(newPosition)
}
if (drawPolygonPts.length === 3) {
aPolygon.polygon.heightReference = Cesium.HeightReference.CLAMP_TO_GROUND;
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
//鼠标右键--结束绘制
this.handler.setInputAction((event) => {
//删除最后一个点(重复添加的点)
drawPolygonPts.pop()
this.graphics.push(aPolygon)
this._stopDraw()
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
}
_drawRec(){
let aPolygon = undefined;
let westSouthEastNorth = []
let lat1, lng1, lat, lng
let rec_polyline = new Cesium.CallbackProperty(function () {
return Cesium.Cartesian3.fromDegreesArray(westSouthEastNorth, Cesium.Ellipsoid.WGS84,undefined)
}, false)
let rec_polygon = new Cesium.CallbackProperty(function () {
return {
positions: Cesium.Cartesian3.fromDegreesArray(westSouthEastNorth, Cesium.Ellipsoid.WGS84,undefined)
}
}, false)
this.handler.setInputAction(event => {
/**点击位置笛卡尔坐标 */
let cartesian = this.viewer.camera.pickEllipsoid(event.position, this.viewer.scene.globe.ellipsoid)
/**笛卡尔转弧度坐标 */
let cartographic = Cesium.Cartographic.fromCartesian(cartesian, this.viewer.scene.globe.ellipsoid, new Cesium.Cartographic())
/**点击位置经度 */
lng1 = Cesium.Math.toDegrees(cartographic.longitude)
/**点击位置维度 */
lat1 = Cesium.Math.toDegrees(cartographic.latitude)
/**边框坐标 */
westSouthEastNorth = [lng1, lat1]
/**面实例对象 */
aPolygon = this.viewer.entities.add({
name: 'rectangle',
polygon: {
hierarchy: rec_polygon,
height: 0,
// 填充的颜色withAlpha透明度
material: this.graphicStyle.material,
// 是否被提供的材质填充
fill: true,
// 是否显示
show: true,
},
polyline: {
positions: rec_polyline,
material: this.graphicStyle.borderColor,
width: this.graphicStyle.borderWidth,
zIndex: 1
}
})
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
this.handler.setInputAction((move) => {
if(westSouthEastNorth.length > 0){
let cartesian = this.viewer.camera.pickEllipsoid(move.endPosition, this.viewer.scene.globe.ellipsoid)
let cartographic = Cesium.Cartographic.fromCartesian(cartesian, this.viewer.scene.globe.ellipsoid, new Cesium.Cartographic())
lng = Cesium.Math.toDegrees(cartographic.longitude)
lat = Cesium.Math.toDegrees(cartographic.latitude)
westSouthEastNorth = [lng1, lat1, lng1, lat, lng, lat, lng, lat1, lng1, lat1]
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
this.handler.setInputAction(() => {
if (aPolygon) {
this.viewer.scene.requestRender()
this.graphics.push(aPolygon)
this._stopDraw()
}
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
}
_drawCircle(){
/**圆半径 */
let centerPoint = null;
let radius = 0.0;
let aPolygon = undefined;
this.handler.setInputAction(event => {
if(centerPoint==null) {
let ray = this.viewer.camera.getPickRay(event.position);
centerPoint = this.scene.globe.pick(ray, this.scene)
aPolygon = this.viewer.entities.add({
position: centerPoint,
name: 'draw circle',
ellipse: {
height: 30,
material: this.graphicStyle.material,
outline: true,
outlineColor: this.graphicStyle.borderColor,
outlineWidth: this.graphicStyle.borderWidth,
fill: true,
semiMajorAxis: new Cesium.CallbackProperty(() => {
return radius
}, false),
semiMinorAxis: new Cesium.CallbackProperty(() => {
return radius
}, false)
}
})
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
this.handler.setInputAction((move) => {
if(centerPoint){
let cartesian2 = this.viewer.camera.pickEllipsoid(move.endPosition, this.viewer.scene.globe.ellipsoid)
radius = Cesium.Cartesian3.distance(centerPoint, cartesian2)
this.viewer.scene.requestRender()
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
this.handler.setInputAction(() => {
if (centerPoint !== null && radius > 0) {
this.viewer.scene.requestRender()
this.graphics.push(aPolygon)
this._stopDraw()
}
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
}
} }

@ -15,7 +15,7 @@ let isDecimal = ref(true)
onMounted(()=>{ onMounted(()=>{
let _viewer = window.viewer let _viewer = window.viewer
let canvas = _viewer.scene.canvas let canvas = _viewer.scene.canvas
let handler = new ScreenSpaceEventHandler(canvas) const handler = new ScreenSpaceEventHandler(canvas)
handler.setInputAction((e:any)=> { handler.setInputAction((e:any)=> {
// //
let position = cartesian2ToCartesian3(_viewer, e.endPosition) let position = cartesian2ToCartesian3(_viewer, e.endPosition)

@ -4,15 +4,15 @@
创建人Zhaipeixiu 创建人Zhaipeixiu
--> -->
<script setup> <script setup>
import { CashOutline} from '@vicons/ionicons5' import { DuplicateSharp,Layers,ChevronBack,ChevronForward,CreateOutline} from '@vicons/ionicons5'
import { NTooltip, useMessage } from 'naive-ui' import { RulerAlt} from '@vicons/carbon'
// import {UploadFileInfo} from "naive-ui"; import { TerrainSharp} from '@vicons/material'
// import {DataSource} from "cesium"; import { DrawPolygon} from '@vicons/fa'
import MeasureDistance from "@/assets/js/cesium-map/measureDistance"; import { useMessage } from 'naive-ui'
import {ref} from "vue"; import {ref} from "vue";
const message = useMessage(); const message = useMessage();
let file, measureDis; let file;
let options = [ let options = [
{ {
label: 'Drive My Car', label: 'Drive My Car',
@ -21,7 +21,7 @@ let options = [
]; ];
let layerValue = ref('test'); let layerValue = ref('test');
let barIsOpen = ref(true);
let MeasureOptions = [ let MeasureOptions = [
{ {
label: '距离测量', label: '距离测量',
@ -37,13 +37,42 @@ let MeasureOptions = [
}, },
] ]
let DrawOptions = [
{
label: '多边形',
key: 'polygon'
},
{
label: '矩形',
key: 'rec'
},{
label: '圆形',
key: 'circle'
},
{
label: '清除',
key: 'clear'
},
]
function handleDrawSelect(key) {
if(key === 'clear') {
if(window.measureViewer.clearDraw()){
message.warning('无可清除图形')
}
}
else{
window.measureViewer.drawGraphics(key)
}
}
// //
function handleSelect(key) { function handleSelect(key) {
if(key === 'distance') { if(key === 'distance') {
measure(); measure();
} }
else if(key === 'area') { else if(key === 'area') {
measureArea()
}else if(key === 'clear') { }else if(key === 'clear') {
measureEnd() measureEnd()
} }
@ -66,79 +95,102 @@ function handleFile(event) {
}); });
} }
/**
* 多点距离测量
*/
function measure(){ function measure(){
measureDis = new MeasureDistance(window.viewer) window.measureViewer.clearDisEntity()
measureDis.activate() window.measureViewer.activate()
} }
/**
* 清除面积测量和多点距离测量
*/
function measureEnd(){ function measureEnd(){
if(measureDis.vertexEntities.length>0){ if(window.measureViewer.vertexEntities.length>0 || window.measureViewer.activeShapePoints.length>0){
measureDis.deactivate() window.measureViewer.deactivate()
measureDis.clear() window.measureViewer.stopAreaMeasure()
measureDis.viewer.scene.requestRender() window.measureViewer.clearDisEntity()
window.measureViewer.clearAreaEntity()
window.measureViewer.viewer.scene.requestRender()
}else{ }else{
message.warning('无可清除元素') message.warning('无可清除元素')
} }
} }
/**
* 面积测量
*/
function measureArea() {
window.measureViewer.clearAreaEntity()
window.measureViewer.activateAreaMeasure();
}
</script> </script>
<template> <template>
<n-flex id="panel"> <n-flex id="panel">
<n-popselect v-model:value="layerValue" :options="options" size="medium"> <n-popselect v-model:value="layerValue" :options="options" size="medium">
<n-button> <n-button tertiary circle type="warning">
图层管理 <template #icon>
<n-icon><Layers/></n-icon>
</template>
</n-button> </n-button>
</n-popselect> </n-popselect>
<n-button> <n-tooltip placement="bottom" trigger="hover">
添加文件 <template #trigger>
</n-button> <n-button tertiary circle type="warning">
<n-button> <template #icon>
地形分析 <n-icon><DuplicateSharp /></n-icon>
</n-button> </template>
<n-button> </n-button>
编辑工具 </template>
<span> 添加数据 </span>
</n-tooltip>
<n-tooltip placement="bottom" trigger="hover">
<template #trigger>
<n-button tertiary circle type="warning">
<template #icon>
<n-icon><TerrainSharp/></n-icon>
</template>
</n-button>
</template>
<span> 地形分析 </span>
</n-tooltip>
<n-button tertiary circle type="warning">
<template #icon>
<n-icon><CreateOutline/></n-icon>
</template>
</n-button> </n-button>
<n-dropdown :options="MeasureOptions" @select="handleSelect"> <n-dropdown :options="MeasureOptions" @select="handleSelect">
<n-button tertiary circle type="info"> <n-button tertiary circle type="warning">
<template #icon> <template #icon>
<n-icon><CashOutline /></n-icon> <n-icon><RulerAlt/></n-icon>
</template> </template>
</n-button> </n-button>
</n-dropdown> </n-dropdown>
<n-button> <n-dropdown :options="DrawOptions" @select="handleDrawSelect">
绘制工具 <n-button tertiary circle type="warning">
<template #icon>
<n-icon><DrawPolygon/></n-icon>
</template>
</n-button> </n-button>
<n-button> </n-dropdown>
显示/隐藏 <n-button tertiary circle type="warning">
<template #icon>
<!-- ChevronBack,ChevronForward,-->
<n-icon><ChevronBack/></n-icon>
</template>
</n-button> </n-button>
</n-flex> </n-flex>
<!--<div id="panel">-->
<!-- -->
<!--&lt;!&ndash; <input type="file" @change="handleFile" >&ndash;&gt;-->
<!-- <n-upload action="" @change="handleFinish" >-->
<!-- <n-button secondary type="info" >上传文件</n-button>-->
<!-- </n-upload>-->
<!-- <n-popover trigger="hover">-->
<!-- <template #trigger>-->
<!-- <n-button class="toolbts" @click="measure" size="small" icon="el-icon-edit-outline"></n-button>-->
<!-- </template>-->
<!-- <span>测距</span>-->
<!-- </n-popover>-->
<!-- <n-popover trigger="hover">-->
<!-- <template #trigger>-->
<!-- <n-button class="toolbts" @click="measureEnd" size="small" icon=el-icon-delete></n-button>-->
<!-- </template>-->
<!-- <span>清除</span>-->
<!-- </n-popover>-->
<!--</div>-->
</template> </template>
<style scoped> <style scoped>
#panel{ #panel{
position: absolute; position: absolute;
top: 40px; top: 10px;
left: 2px; left: 2px;
width: 50vw; background: rgba(21, 21, 21, 0.73);
height: 1rem; border-radius: 7px;
} }
</style> </style>

Loading…
Cancel
Save