419 lines
14 KiB
TypeScript
419 lines
14 KiB
TypeScript
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()
|
||
}
|