Cesium绘制矩形

有个项目中,要求绘制多边形和矩形电子围栏。多边形的绘制很快做好了,但矩形花了一天多。官网的矩形示例是给定两个对角点坐标生成矩形,但这个不太对,它是水平垂直方向的。

我想要的效果是点击三次:

  1. 设置起点
  2. 设置方向
  3. 设置终点

一开始我想用修改官网示例来完成,通过矩形的旋转属性(rotation: Cesium.Math.toRadians(45))来完成,但旋转的中心点是矩形的中心点,无法设置起点为旋转中心。这样的效果会让甲方迷惑,行不通。

还得是用绘制多边形的方式,自动生成相邻点的坐标。

在这里插入图片描述

如上图所示,p0/p1/p2是依次点击的三个点位

生成点位C1

p1点不绘制,它是一个辅助点,用于确定c1点在这条延长线上。求取c1点的坐标,可以分为以下几个步骤:

1. 求取p0p2长度

借助turf.js工具distance计算两点的距离

import distance from "@turf/distance"
const length = distance(p0, p2, { units: 'miles' })
2. 求p1p0p2的夹角

rhumbBearing求取两点与正北方向的夹角

import rhumbBearing from "@turf/rhumb-bearing"
const bearing1 = rhumbBearing(p0, p1)
const bearing2 = rhumbBearing(p0, p2)
const angle1 = bearing2 - bearing1
3. p0c1的长度

根据前面求得的角度和距离,将余弦与长度相乘

const len1 = Math.cos(angle1 / 180 * Math.PI) * length
4. c1点坐标

步骤2中已经求出p0p1点与正北方向的夹角bearing1,这里使用destination求取目标点c1

const dest1 = destination(p0, len1, bearing1, { units: 'miles' })

看看绘制的效果:
请添加图片描述

肉眼可见是直角,接下来计算另一个点c2

生成点位C2

点位c2与c1原理相同,只是角度计算方式不同

1. 求p2p0c2角度

p1p0与p0c2垂直,所以

const angle2 = 90 - angle1
2. p0c2的长度
const len2 = Math.cos(angle2 / 180 * Math.PI) * length
3. c2点坐标

p0c1点与p0c2点差了90度,所以

const dest2 = destination(p0, len2, 90 + bearing1, { units: 'miles' })

看看最终效果:
在这里插入图片描述

总结

turf.js是个好东西,我在项目中经常使用。前面的绘制一开始我是没用到turf的,结果绘制出来的效果出乎意料,索性全部用turf中的工具进行了替换。

可能有些人会用到矩形绘制功能,这里把关键代码放在这里吧:

外部引入:

import { bearingToAzimuth, point } from "@turf/helpers"
import rhumbBearing from "@turf/rhumb-bearing"
import distance from "@turf/distance"
import destination from "@turf/destination"

绘制部分, points是数组,引用类型,所以只要在最开始调用一次就行了。

drawRectangle() {
  console.log('draw rectangle')
  
  this.handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas)
  const points = []
  let shape = this.renderRect(points)
  let step = 0

  this.handler.setInputAction(e => {
    let cartesian = viewer.scene.pickPosition(e.position);
    if (!Cesium.defined(cartesian)) {
      const ray = viewer.camera.getPickRay(e.position);
      cartesian = viewer.scene.globe.pick(ray, viewer.scene);
    }

    points[step] = cartesian
    step++

    if (step === 3) {
      this.handler.destroy();
    }
  }, Cesium.ScreenSpaceEventType.LEFT_CLICK)

  this.handler.setInputAction(e => {
    let cartesian = viewer.scene.pickPosition(e.startPosition);

    if (!Cesium.defined(cartesian)) {
      const ray = viewer.camera.getPickRay(e.startPosition);
      cartesian = viewer.scene.globe.pick(ray, viewer.scene);
    }

    points[2] = cartesian
  }, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
}

renderRect(points) {
  const shape = this.viewer.entities.add({
    polygon: {
      hierarchy: new Cesium.CallbackProperty(() => {

        if (points[0] && points[1] && points[2]) {
          const r0 = Cesium.Cartographic.fromCartesian(points[0])
          const r1 = Cesium.Cartographic.fromCartesian(points[1]) // 辅助点
          const r2 = Cesium.Cartographic.fromCartesian(points[2])

          const p0 = point([r0.longitude * 180 / Math.PI, r0.latitude * 180 / Math.PI])
          const p1 = point([r1.longitude * 180 / Math.PI, r1.latitude * 180 / Math.PI])
          const p2 = point([r2.longitude * 180 / Math.PI, r2.latitude * 180 / Math.PI])

          const bearing1 = rhumbBearing(p0, p1)
          const bearing2 = rhumbBearing(p0, p2)
          const angle1 = bearing2 - bearing1

          // 对角长度
          const length = distance(p0, p2, { units: 'miles' })

          const len1 = Math.cos(angle1 / 180 * Math.PI) * length
          const dest1 = destination(p0, len1, bearing1, { units: 'miles' })

          const angle2 = 90 - angle1
          const len2 = Math.cos(angle2 / 180 * Math.PI) * length
          const dest2 = destination(p0, len2, 90 + bearing1, { units: 'miles' })

          const coordinates = [points[0], Cesium.Cartesian3.fromDegrees(...dest1.geometry.coordinates), points[2], Cesium.Cartesian3.fromDegrees(...dest2.geometry.coordinates)]

          return new Cesium.PolygonHierarchy(coordinates)
        }

      }, false)
    },
  })


  return shape
}
  • 4
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
要实现cesium动态绘制矩形,可以使用Cesium的Primitive API和MouseEvents。具体步骤如下: 1. 创建矩形entity并添加到场景中。 ``` var entity = viewer.entities.add({ rectangle: { coordinates: Cesium.Rectangle.fromDegrees(-100.0, 20.0, -90.0, 30.0), material: Cesium.Color.RED.withAlpha(0.5), outline: true, outlineColor: Cesium.Color.BLACK } }); ``` 2. 获取鼠标左键按下和移动事件,并更新矩形的坐标。 ``` var startPosition; var mouseHandler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas); mouseHandler.setInputAction(function(movement) { startPosition = movement.position; }, Cesium.ScreenSpaceEventType.LEFT_DOWN); mouseHandler.setInputAction(function(movement) { if (Cesium.defined(startPosition)) { var endPosition = movement.position; var startCartesian = viewer.scene.camera.pickEllipsoid(startPosition, viewer.scene.globe.ellipsoid); var endCartesian = viewer.scene.camera.pickEllipsoid(endPosition, viewer.scene.globe.ellipsoid); if (Cesium.defined(startCartesian) && Cesium.defined(endCartesian)) { var startCartographic = Cesium.Cartographic.fromCartesian(startCartesian); var endCartographic = Cesium.Cartographic.fromCartesian(endCartesian); var west = Math.min(startCartographic.longitude, endCartographic.longitude); var east = Math.max(startCartographic.longitude, endCartographic.longitude); var south = Math.min(startCartographic.latitude, endCartographic.latitude); var north = Math.max(startCartographic.latitude, endCartographic.latitude); entity.rectangle.coordinates = Cesium.Rectangle.fromDegrees(west, south, east, north); } } }, Cesium.ScreenSpaceEventType.MOUSE_MOVE); ``` 3. 获取鼠标左键松开事件,结束矩形绘制。 ``` mouseHandler.setInputAction(function(movement) { startPosition = undefined; }, Cesium.ScreenSpaceEventType.LEFT_UP); ``` 这样,当用户按下鼠标左键并移动时,就可以动态绘制矩形
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值