Cesium绘制矩形

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

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

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

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

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

Cesium绘制矩形_第1张图片

如上图所示,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' })

看看绘制的效果:
Cesium绘制矩形_第2张图片

肉眼可见是直角,接下来计算另一个点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' })

看看最终效果:
Cesium绘制矩形_第3张图片

总结

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
}

你可能感兴趣的:(Cesium,JavaScript,几何学,线性代数,矩阵)