ts/src/hooks/measure.ts

419 lines
14 KiB
TypeScript
Raw Normal View History

2025-02-11 02:56:16 +00:00
import { cartesian32LonLat } from '@/utils/pos'
2025-01-13 08:45:08 +00:00
let handler = null
let bMeasuring = false
const measureIds = []
export const useMeasure = (viewer: any, target: string, terrain: any) => {
return {
distanceMeasure,
angleMeasure,
clearMeasure,
}
}
function distanceMeasure() {
//贴地测量距离函数
// var terrainProvider = this.terrainProvider
2025-02-14 08:33:28 +00:00
viewer.scene.globe.depthTestAgainstTerrain = true
2025-01-13 08:45:08 +00:00
handler = new Cesium.ScreenSpaceEventHandler(
viewer.scene._imageryLayerCollection
)
let positions: any[] = []
let poly: null = null
// var tooltip = document.getElementById("toolTip");
let distance = 0
let cartesian = null
let floatingPoint
// tooltip.style.display = "block";
handler.setInputAction(function (movement) {
// tooltip.style.left = movement.endPosition.x + 3 + "px";
// tooltip.style.top = movement.endPosition.y - 25 + "px";
// tooltip.innerHTML = '<p>单击开始,右击结束</p>';
cartesian = viewer.scene.pickPosition(movement.endPosition)
if (!Cesium.defined(cartesian)) {
const ray = viewer.camera.getPickRay(movement.endPosition)
cartesian = viewer.scene.globe.pick(ray, viewer.scene)
}
const p = Cesium.Cartographic.fromCartesian(cartesian)
p.height = viewer.scene.sampleHeight(p)
cartesian = viewer.scene.globe.ellipsoid.cartographicToCartesian(p)
//cartesian = viewer.scene.camera.pickEllipsoid(movement.endPosition, viewer.scene.globe.ellipsoid);
if (positions.length >= 2) {
if (!Cesium.defined(poly)) {
poly = new PolyLinePrimitive(positions)
} else {
positions.pop()
// cartesian.y += (1 + Math.random());
positions.push(cartesian)
}
// console.log("distance: " + distance);
// tooltip.innerHTML='<p>'+distance+'米</p>';
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
handler.setInputAction(function (movement) {
// tooltip.style.display = "none";
// cartesian = viewer.scene.camera.pickEllipsoid(movement.position, viewer.scene.globe.ellipsoid);
cartesian = viewer.scene.pickPosition(movement.position)
if (!Cesium.defined(cartesian)) {
const ray = viewer.camera.getPickRay(movement.position)
cartesian = viewer.scene.globe.pick(ray, viewer.scene)
}
let p = Cesium.Cartographic.fromCartesian(cartesian)
p.height = viewer.scene.sampleHeight(p)
cartesian = viewer.scene.globe.ellipsoid.cartographicToCartesian(p)
if (positions.length == 0) {
positions.push(cartesian.clone())
}
positions.push(cartesian)
getSpaceDistance(positions)
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
handler.setInputAction(function (movement) {
handler.destroy() //关闭事件句柄
positions.pop() //最后一个点无效
// viewer.entities.remove(floatingPoint);
// tooltip.style.display = "none";
bMeasuring = false
viewer._container.style.cursor = ''
2025-02-14 08:33:28 +00:00
viewer.scene.globe.depthTestAgainstTerrain = false
2025-01-13 08:45:08 +00:00
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
const PolyLinePrimitive = (function () {
function _(positions) {
this.options = {
name: '直线',
polyline: {
show: true,
positions: [],
material: Cesium.Color.RED,
2025-01-13 08:45:08 +00:00
width: 2,
clampToGround: true,
},
}
this.positions = positions
this._init()
}
_.prototype._init = function () {
const _self = this
const _update = function () {
return _self.positions
}
//实时更新polyline.positions
this.options.polyline.positions = new Cesium.CallbackProperty(
_update,
false
)
const et = viewer.entities.add(this.options)
measureIds.push(et.id)
}
return _
})()
//空间两点距离计算函数
function getSpaceDistance(positions) {
let distance_ = 0
if (positions.length > 2) {
const positions_ = []
const sp = Cesium.Cartographic.fromCartesian(
positions[positions.length - 3]
)
const ep = Cesium.Cartographic.fromCartesian(
positions[positions.length - 2]
)
const geodesic = new Cesium.EllipsoidGeodesic()
geodesic.setEndPoints(sp, ep)
const s = geodesic.surfaceDistance
positions_.push(sp)
let num = parseInt((s / 100).toFixed(0))
num = num > 200 ? 200 : num
num = num < 20 ? 20 : num
for (let i = 1; i < num; i++) {
const res = geodesic.interpolateUsingSurfaceDistance(
(s / num) * i,
new Cesium.Cartographic()
)
res.height = viewer.scene.sampleHeight(res)
positions_.push(res)
}
positions_.push(ep)
// var promise = Cesium.sampleTerrainMostDetailed(terrainProvider, positions_);
// Cesium.when(promise, function (updatedPositions) {
for (let ii = 0; ii < positions_.length - 1; ii++) {
geodesic.setEndPoints(positions_[ii], positions_[ii + 1])
const d = geodesic.surfaceDistance
distance_ =
Math.sqrt(
Math.pow(d, 2) +
Math.pow(positions_[ii + 1].height - positions_[ii].height, 2)
) + distance_
}
//在三维场景中添加Label
const distance_add = parseFloat(distance_.toFixed(2))
distance += distance_add
const textDistance =
(distance > 1000
? (distance / 1000).toFixed(3) + '千米'
: distance.toFixed(2) + '米') +
'\n(+' +
(distance_add > 1000
? (distance_add / 1000).toFixed(3) + '千米'
: distance_add + '米') +
')'
// var textDistance = distance + "米";
// if (distance > 1000) {
// textDistance = (distance / 1000).toFixed(3) + "千米";
// }
floatingPoint = viewer.entities.add({
name: '空间直线距离',
position: positions[positions.length - 1],
point: {
pixelSize: 5,
color: Cesium.Color.WHITE,
2025-01-13 08:45:08 +00:00
outlineColor: Cesium.Color.WHITE,
outlineWidth: 2,
// disableDepthTestDistance: Number.POSITIVE_INFINITY
},
label: {
text: textDistance,
font: '16px sans-serif',
fillColor: Cesium.Color.RED,
2025-01-13 08:45:08 +00:00
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
outlineWidth: 2,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
disableDepthTestDistance: Number.POSITIVE_INFINITY,
pixelOffset: new Cesium.Cartesian2(20, -20),
// disableDepthTestDistance: Number.POSITIVE_INFINITY
},
})
measureIds.push(floatingPoint.id)
// });
}
}
}
function angleMeasure() {
const pArr = []
let distanceLineNum = 0
let Line1
let Line2
let angleT
let floatingPoint //浮动点
handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
handler.setInputAction(function (movement) {
2025-02-14 08:33:28 +00:00
// let cartesian = viewer.scene.pickPosition(movement.endPosition)
// if (!Cesium.defined(cartesian)) {
const ray = viewer.camera.getPickRay(movement.endPosition)
let cartesian = viewer.scene.globe.pick(ray, viewer.scene)
// }
2025-01-13 08:45:08 +00:00
//cartesian = viewer.scene.camera.pickEllipsoid(movement.endPosition, viewer.scene.globe.ellipsoid);
if (distanceLineNum === 1) {
pArr.length = 1
pArr.push(cartesian)
2025-02-11 02:56:16 +00:00
// console.log(pArr, 'pArr')
2025-01-13 08:45:08 +00:00
draw_Angle()
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
handler.setInputAction(function (movement) {
2025-02-14 08:33:28 +00:00
// let cartesian = viewer.scene.pickPosition(movement.position)
2025-02-11 02:56:16 +00:00
// console.log('cartesian', cartesian32LonLat(cartesian))
2025-02-14 08:33:28 +00:00
// if (!Cesium.defined(cartesian)) {
// console.log('false')
const ray = viewer.camera.getPickRay(movement.position)
let cartesian = viewer.scene.globe.pick(ray, viewer.scene)
// }
2025-01-13 08:45:08 +00:00
// var cartesian = viewer.scene.pickPosition(movement.position);
distanceLineNum++
if (distanceLineNum === 1) {
pArr.push(cartesian)
floatingPoint = viewer.entities.add({
name: '方位角',
position: cartesian,
point: {
pixelSize: 3,
color: Cesium.Color.WHITE,
2025-01-13 08:45:08 +00:00
outlineColor: Cesium.Color.WHITE,
outlineWidth: 2,
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
},
})
measureIds.push(floatingPoint.id)
} else {
pArr.length = 1
pArr.push(cartesian)
handler.destroy()
bMeasuring = false
viewer._container.style.cursor = ''
draw_Angle()
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
handler.setInputAction(function (movement) {
handler.destroy()
bMeasuring = false
viewer._container.style.cursor = ''
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
function draw_Angle() {
// 空间
const cartographic1 = Cesium.Cartographic.fromCartesian(pArr[0])
const lon1 = Cesium.Math.toDegrees(cartographic1.longitude)
const lat1 = Cesium.Math.toDegrees(cartographic1.latitude)
const cartographic2 = Cesium.Cartographic.fromCartesian(pArr[1])
const lon2 = Cesium.Math.toDegrees(cartographic2.longitude)
const lat2 = Cesium.Math.toDegrees(cartographic2.latitude)
const lineDistance = Cesium.Cartesian3.distance(
Cesium.Cartesian3.fromDegrees(lon1, lat1),
Cesium.Cartesian3.fromDegrees(lon2, lat2)
)
const localToWorld_Matrix = Cesium.Transforms.eastNorthUpToFixedFrame(
Cesium.Cartesian3.fromDegrees(lon1, lat1)
)
const NorthPoint = Cesium.Cartographic.fromCartesian(
Cesium.Matrix4.multiplyByPoint(
localToWorld_Matrix,
Cesium.Cartesian3.fromElements(0, lineDistance, 0),
new Cesium.Cartesian3()
)
)
const npLon = Cesium.Math.toDegrees(NorthPoint.longitude)
const npLat = Cesium.Math.toDegrees(NorthPoint.latitude)
// var angle = Cesium.Cartesian3.angleBetween(Cesium.Cartesian3.fromDegrees(lon1, lat1),
// Cesium.Cartesian3.fromDegrees(lon2, lat2));
const angle = courseAngle(lon1, lat1, lon2, lat2)
let textDistance = lineDistance.toFixed(2) + '米'
if (lineDistance > 1000) {
textDistance = (lineDistance / 1000).toFixed(3) + '千米'
}
if (Cesium.defined(Line1)) {
//更新线
Line1.polyline.positions = new Cesium.Cartesian3.fromDegreesArray([
lon1,
lat1,
npLon,
npLat,
])
Line2.polyline.positions = new Cesium.Cartesian3.fromDegreesArray([
lon1,
lat1,
lon2,
lat2,
])
angleT.label.text = '角度:' + angle + '°\n距离:' + textDistance
angleT.position = pArr[1]
return
}
//北方线
Line1 = viewer.entities.add({
name: 'Angle1',
polyline: {
positions: new Cesium.Cartesian3.fromDegreesArray([
lon1,
lat1,
npLon,
npLat,
]),
width: 3,
material: new Cesium.PolylineDashMaterialProperty({
color: Cesium.Color.RED,
}),
clampToGround: true,
},
})
measureIds.push(Line1.id)
//线
Line2 = viewer.entities.add({
name: 'Angle2',
polyline: {
positions: new Cesium.Cartesian3.fromDegreesArray([
lon1,
lat1,
lon2,
lat2,
]),
width: 10,
material: new Cesium.PolylineArrowMaterialProperty(Cesium.Color.YELLOW),
clampToGround: true,
},
})
measureIds.push(Line2.id)
//文字
angleT = viewer.entities.add({
name: 'AngleT',
position: pArr[1],
label: {
text: '角度:' + angle + '°\n距离:' + textDistance,
// scaleByDistance: new Cesium.NearFarScalar(7000000, 1.0, 18000000, 0.4),
// translucencyByDistance: new Cesium.NearFarScalar(1.5e2, 2.0, 1.5e5, 0),
2025-02-14 08:33:28 +00:00
font: '14px sans-serif',
fillColor: Cesium.Color.RED,
2025-01-13 08:45:08 +00:00
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
outlineWidth: 2,
pixelOffset: new Cesium.Cartesian2(0, -20),
disableDepthTestDistance: Number.POSITIVE_INFINITY,
backgroundColor: new Cesium.Color.fromCssColorString(
'rgba(0, 0, 0, 1)'
),
backgroundPadding: new Cesium.Cartesian2(10, 10),
verticalOrigin: Cesium.VerticalOrigin.BASELINE,
},
})
measureIds.push(angleT.id)
}
function courseAngle(lng_a, lat_a, lng_b, lat_b) {
/////////////方法
let dRotateAngle = Math.atan2(
Math.abs(lng_a - lng_b),
Math.abs(lat_a - lat_b)
)
if (lng_b >= lng_a) {
if (lat_b >= lat_a) {
} else {
dRotateAngle = Math.PI - dRotateAngle
}
} else {
if (lat_b >= lat_a) {
dRotateAngle = 2 * Math.PI - dRotateAngle
} else {
dRotateAngle = Math.PI + dRotateAngle
}
}
dRotateAngle = (dRotateAngle * 180) / Math.PI
return parseInt(dRotateAngle * 100) / 100
/////方法
// //以a点为原点建立局部坐标系东方向为x轴,北方向为y轴,垂直于地面为z轴得到一个局部坐标到世界坐标转换的变换矩阵
// var localToWorld_Matrix = Cesium.Transforms.eastNorthUpToFixedFrame(new Cesium.Cartesian3.fromDegrees(lng_a, lat_a));
// //求世界坐标到局部坐标的变换矩阵
// var worldToLocal_Matrix = Cesium.Matrix4.inverse(localToWorld_Matrix, new Cesium.Matrix4());
// //a点在局部坐标的位置其实就是局部坐标原点
// var localPosition_A = Cesium.Matrix4.multiplyByPoint(worldToLocal_Matrix, new Cesium.Cartesian3.fromDegrees(lng_a, lat_a), new Cesium.Cartesian3());
// //B点在以A点为原点的局部的坐标位置
// var localPosition_B = Cesium.Matrix4.multiplyByPoint(worldToLocal_Matrix, new Cesium.Cartesian3.fromDegrees(lng_b, lat_b), new Cesium.Cartesian3());
// //弧度
// var angle = Math.atan2((localPosition_B.y - localPosition_A.y), (localPosition_B.x - localPosition_A.x))
// //角度
// var theta = angle * (180 / Math.PI);
// if (theta < 0) {
// theta = theta + 360;
// }
// return theta.toFixed(2);
}
}
function clearMeasure() {
for (let jj = 0; jj < measureIds.length; jj++) {
viewer.entities.removeById(measureIds[jj])
}
measureIds.length = 0
if (handler && !handler.isDestroyed()) handler = handler && handler.destroy()
}