【Cesium】距离量测和面积量测

7 篇文章 11 订阅

1 、空间量测

        空间量测是在三维空间中测量距离、角度、面积等内容。实现方法为在屏幕中拾取对应点的位置,然后将屏幕坐标转换为地理坐标,再根据地球椭球参数,进行几何解算,获取地理空间距离、面积等。

1.1、 距离量测

        两点之间的距离量测,核心代码:

function distanceCal(point1,point2){
  var cartographic1 = Cesium.Cartographic.fromCartesian(point1); 
  var cartographic2 = Cesium.Cartographic.fromCartesian(point2); 
  console.log(cartographic1);
  console.log(cartographic2);
  var geodesic = new Cesium.EllipsoidGeodesic();
  geodesic.setEndPoints(cartogrartographic2);
  //两点的贴地线距离(不计算高度差)
  var s =geodesic.surfaceDistance;
  return s;
}

思路是先获取两点的屏幕坐标,将其转为笛卡尔空间直角坐标,然后转成WGS-84。利用WGS-84椭球体得出两点的距离。

1.2、 面积量测

//计算多边形面积, S=[(x1*y2-y1*x2)+(x2*y3-y2*x3)+.....+(xn*y1*x1)]/2,
function getArea(points) {
  let s = 0;
  let p1 = 0;
  let p2 = 0;
  for (let i = 0; i < points.length; ++i)
  { 
      p1 = points[i];
      let j = (i + 1) % points.length;
      p2 = points[j];
      s += p1.x * p2.y;
      s -= p2.x * p1.y;
  }
  return Math.abs(s/2/1000000.0).toFixed(6);
}

根据官网案例

https://sandcastle.cesium.com/?src=Drawing%20on%20Terrain.html

改造完成距离和面积测量功能,效果如下:
距离量测:
距离量测

面积量测:
面积量测
完整代码如下:

<div id="container"></div>
<div id="toolbar" style="display: inline;">
    <select id="spatial_cal" class="cesium-button">
        <option value="distance">距离量算</option>
        <option value="area">面积量算</option>
    </select>
    <button id="calculate" class="cesium-button" onclick="cal();">计算</button>
    <button id="clear" class="cesium-button" onclick="clearCal();">清空</button>
</div>
//创建点
function createPoint(windowPosition){
  var point = new Cesium.Entity({
    position: windowPosition, 
    point:{
        pixelSize: 10, //点的大小
        color : Cesium.Color.WHITE,//点的颜色
        heightReference : Cesium.HeightReference.NONE, //高度参考,NONE表示绝对高程
    }
})
  viewer.entities.add(point);
  return point;
}

var drawingMode = "polyline";
var activeShapePoints = []; //参与画图的点集合
var activeShape;  //正在绘制的图形
var floatingPoint;  //绘制图形时的跟踪点
var calPoints = [];
var calEntity;
var floatingPoints = [];
var label;
//监听下拉框的变化
var selectForm = document.getElementById("spatial_cal");
selectForm.addEventListener('change',function(){
  let select_val = selectForm.options[selectForm.selectedIndex].value;
  if(select_val == "distance"){
    drawingMode = "polyline";
  }
  else if(select_val == "area"){
    drawingMode = "polygon";
  }
});

const handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);
//添加鼠标左键处理事件(在鼠标右键终止绘制后,将会禁用该事件) 
function setBuildShapeHandler(flag){
  if(flag){
    handler.setInputAction(function (event) {
      const earthPosition = viewer.scene.pickPosition(event.position);
      // `earthPosition` will be undefined if our mouse is not over the globe.
      if (Cesium.defined(earthPosition)) {
        if (activeShapePoints.length === 0) {
          floatingPoint = createPoint(earthPosition);
          floatingPoints.push(floatingPoint);
          activeShapePoints.push(earthPosition);
          const dynamicPositions = new Cesium.CallbackProperty(function () {
              if (drawingMode === "polygon") {
                return new Cesium.PolygonHierarchy(activeShapePoints);
              }
              return activeShapePoints;
            }, false);
            activeShape = drawShape(dynamicPositions);
          }
          activeShapePoints.push(earthPosition);
          floatingPoint = createPoint(earthPosition);
          floatingPoints.push(floatingPoint);
      }
    }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
    //添加鼠标移动处理事件
    handler.setInputAction(function (event) {
      if (Cesium.defined(floatingPoint)) {
        const newPosition = viewer.scene.pickPosition(event.endPosition);
        if (Cesium.defined(newPosition)) {
          floatingPoint.position.setValue(newPosition);
          activeShapePoints.pop();
          activeShapePoints.push(newPosition);
        }
      }
    }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
  }else{
    handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE);
    handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
  }
}
//默认开启
setBuildShapeHandler(true);


//绘制图形
function drawShape(positionData)
{
    let shape;
    if(drawingMode === "polyline"){
      shape = viewer.entities.add({
        polyline: {
          positions: positionData,
          width: 5,
          material: Cesium.Color.RED,
          heightReference : Cesium.HeightReference.NONE,
          depthFailMaterial: Cesium.Color.RED, //被地形遮挡部分的颜色
        },
      });
    }
    else if(drawingMode === "polygon"){
      shape = viewer.entities.add({
        polygon: {
          hierarchy: positionData,
          material: new Cesium.ColorMaterialProperty(
            Cesium.Color.WHITE.withAlpha(0.7)
          ),
        },
      });
    }
    return shape;
}
// Redraw the shape so it's not dynamic and remove the dynamic shape.
function terminateShape() {
  activeShapePoints.pop();
  calEntity = drawShape(activeShapePoints);
  calPoints = activeShapePoints;
  viewer.entities.remove(floatingPoint);
  viewer.entities.remove(activeShape);
  floatingPoint = undefined;
  activeShape = undefined;
  activeShapePoints = [];
  //绘制完一个图形后,移除鼠标左键和移动的监听事件,防止再次绘制。
  setBuildShapeHandler(false);
}
handler.setInputAction(function (event) {
  terminateShape();
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);

//计算距离、面积、角度
window.cal = function(){
  let result = 0;
  if(drawingMode == "polyline"){
    result = distanceCal(calPoints);
    let text = "距离:"+result+"km";
    label = createLabel(calPoints[calPoints.length-1],text);
  }
  else{
    result = getArea(calPoints);
    let text = "面积:"+result+"km²";
    label = createLabel(calPoints[calPoints.length-1],text);
  }
}
//清空,注意viewer.scene.requestRenderMode为true时,不会立刻显示清空后的样子,只有当鼠标中键滚动或鼠标左键拖拽时才会渲染!!!
function clearCalculate()
{
    viewer.entities.remove(calEntity);
    viewer.entities.remove(label);
    for(let i=0;i<floatingPoints.length;++i)
    {
        viewer.entities.remove(floatingPoints[i]);
    }
    floatingPoint = undefined;
    floatingPoints = [];
    activeShape = undefined;
    activeShapePoints = [];
    calEntity = undefined;
    calPoints = [];
    label = undefined;
    //清空后,再次添加鼠标左键和移动的监听事件,以便下一次测量。
    setBuildShapeHandler(true);
}
window.clearCal = function(){
  clearCalculate();
}

function createLabel(position,text){
  const label = viewer.entities.add({
    position: position,
    label : {
        text : text,
        font : '20px sans-serif',
        style : Cesium.LabelStyle.FILL,
        backgroundColor : Cesium.Color.GRAY.withAlpha(0.3),
        showBackground : true,
        fillColor : Cesium.Color.YELLOW,
        heightReference : Cesium.HeightReference.CLAMP_GROUND, //高度参考,NONE表示绝对高程,
        horizontalOrigin : Cesium.HorizontalOrigin.LEFT,
        verticalOrigin : Cesium.VerticalOrigin.TOP,
        disableDepthTestDistance: Number.POSITIVE_INFINITY //解决了label被地形建筑遮挡的问题!
    }
  })
  return label;
}
//计算多边形面积, 微元法求面积,S=[(x1*y2-y1*x2)+(x2*y3-y2*x3)+.....+(xn*y1-yn*x1)]/2,
//但是结果不除以2才是真实面积,不知道为什么!
function getArea(points) {
  let s = 0;
  let p1 = 0;
  let p2 = 0;
  for (let i = 0; i < points.length; ++i)
  { 
      p1 = points[i];
      let j = (i + 1) % points.length;
      p2 = points[j];
      s += p1.x * p2.y;
      s -= p2.x * p1.y;
  }
  return Math.abs(s/1000000.0).toFixed(6);
}
//计算两点之间的距离
function distanceBetweenTwoPoints(point1,point2){
  let cartographic1 = Cesium.Cartographic.fromCartesian(point1); 
  let cartographic2 = Cesium.Cartographic.fromCartesian(point2); 
  let geodesic = new Cesium.EllipsoidGeodesic();
  geodesic.setEndPoints(cartographic1,cartographic2);
  //这里得出来的是两个点的测地线距离
  let s =geodesic.surfaceDistance;
  return s;
}
//计算总长度
function distanceCal(points){
  let res = 0;
  for(let i=0;i<points.length-1;++i)
  {
    res += distanceBetweenTwoPoints(points[i],points[i+1]);
  }
  return (res/1000.0).toFixed(3);
}
  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值