ts/src/hooks/measure.ts

419 lines
14 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { cartesian32LonLat } from '@/utils/pos'
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
viewer.scene.globe.depthTestAgainstTerrain = true
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 = ''
viewer.scene.globe.depthTestAgainstTerrain = false
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
const PolyLinePrimitive = (function () {
function _(positions) {
this.options = {
name: '直线',
polyline: {
show: true,
positions: [],
material: Cesium.Color.RED,
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,
outlineColor: Cesium.Color.WHITE,
outlineWidth: 2,
// disableDepthTestDistance: Number.POSITIVE_INFINITY
},
label: {
text: textDistance,
font: '16px sans-serif',
fillColor: Cesium.Color.RED,
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) {
// 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)
// }
//cartesian = viewer.scene.camera.pickEllipsoid(movement.endPosition, viewer.scene.globe.ellipsoid);
if (distanceLineNum === 1) {
pArr.length = 1
pArr.push(cartesian)
// console.log(pArr, 'pArr')
draw_Angle()
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
handler.setInputAction(function (movement) {
// let cartesian = viewer.scene.pickPosition(movement.position)
// console.log('cartesian', cartesian32LonLat(cartesian))
// if (!Cesium.defined(cartesian)) {
// console.log('false')
const ray = viewer.camera.getPickRay(movement.position)
let cartesian = viewer.scene.globe.pick(ray, viewer.scene)
// }
// 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,
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),
font: '14px sans-serif',
fillColor: Cesium.Color.RED,
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()
}