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 : [ ] ,
2025-04-09 01:29:23 +00:00
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 ,
2025-04-09 01:29:23 +00:00
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 ,
2025-04-09 01:29:23 +00:00
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 ,
2025-04-09 01:29:23 +00:00
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' ,
2025-04-09 01:29:23 +00:00
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 ( )
}