416 lines
14 KiB
TypeScript
416 lines
14 KiB
TypeScript
![]() |
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 = ''
|
|||
|
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
|
|||
|
|
|||
|
const PolyLinePrimitive = (function () {
|
|||
|
function _(positions) {
|
|||
|
this.options = {
|
|||
|
name: '直线',
|
|||
|
polyline: {
|
|||
|
show: true,
|
|||
|
positions: [],
|
|||
|
material: Cesium.Color.GOLD,
|
|||
|
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.RED,
|
|||
|
outlineColor: Cesium.Color.WHITE,
|
|||
|
outlineWidth: 2,
|
|||
|
// disableDepthTestDistance: Number.POSITIVE_INFINITY
|
|||
|
},
|
|||
|
label: {
|
|||
|
text: textDistance,
|
|||
|
font: '18px sans-serif',
|
|||
|
fillColor: Cesium.Color.GOLD,
|
|||
|
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)
|
|||
|
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)
|
|||
|
draw_Angle()
|
|||
|
}
|
|||
|
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
|
|||
|
handler.setInputAction(function (movement) {
|
|||
|
let 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)
|
|||
|
}
|
|||
|
// 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.RED,
|
|||
|
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: '24px 楷体',
|
|||
|
fillColor: Cesium.Color.WHITE,
|
|||
|
outlineColor: Cesium.Color.BLACK,
|
|||
|
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
|
|||
|
outlineWidth: 2,
|
|||
|
scale: 0.5,
|
|||
|
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()
|
|||
|
}
|