cesium的标绘与测量

标绘

思路:注册左击事件,在事件中获取屏幕坐标,转换为cartesian3,作为point的坐标添加至entities

具体实现

class DrawPoint {
  constructor(arg) {
    console.log(arg)
    this.viewer = arg.viewer
    this.Cesium = arg.Cesium
    this.callback = arg.callback
    this._point = null //最后一个点
    this._pointData = null //点数据用于构造点
    this._entities = [] //脏数据
  }

  //返回最后活动点
  get point() {
    return this._point
  }

  //加载点
  loadPoint(data) {
    return this.createPoint(data)
  }

  //返回点数据用于加载点
  getData() {
    return this._pointData
  }

  //开始绘制
  startCreate() {
    var $this = this
    this.handler = new this.Cesium.ScreenSpaceEventHandler(
      this.viewer.scene.canvas
    )
    this.handler.setInputAction(function (evt) {
      //单机开始绘制
      var cartesian = $this.getCatesian3FromPX(evt.position)
      if (!cartesian) return
      var point = $this.createPoint(cartesian)
      $this._pointData = cartesian
      $this._point = point
      if (typeof $this.callback == 'function') {
        $this.callback(point)
      }
    }, $this.Cesium.ScreenSpaceEventType.LEFT_CLICK)
  }

  //创建点
  createPoint(cartesian) {
    var $this = this
    var point = this.viewer.entities.add({
      position: cartesian,
      point: {
        pixelSize: 10,
        color: $this.Cesium.Color.YELLOW,
      },
    })
    $this._entities.push(point) //加载脏数据
    return point
  }

  //销毁鼠标事件
  destroy() {
    if (this.handler) {
      this.handler.destroy()
      this.handler = null
    }
  }

  //清空实体对象
  clear() {
    for (var i = 0; i < this._entities.length; i++) {
      this.viewer.entities.remove(this._entities[i])
    }
    this._entities = []
    this._point = null
  }

  getCatesian3FromPX(px) {
    var cartesian
    var ray = this.viewer.camera.getPickRay(px)
    if (!ray) return null
    cartesian = this.viewer.scene.globe.pick(ray, this.viewer.scene)
    return cartesian
  }
}

折线

思路:

注册左击事件,在事件中获取屏幕坐标,转换为cartesian3,在该位置添加point,并将该位置push到一个cartesian3数组positions中,作为后续折线的position(注意第一个点要存两遍,因为在后续鼠标move事件中会对position数组pop)

注册鼠标move事件,positions长度小于2时,不执行逻辑直接返回,因为经过pop和push操作之后,仍小于2,无法绘制折线。创建polyline令其position为CallbackProperty,回调中返回positions(只创建一次)。令positions pop一次,再将move事件中获取的cartesian3 push进去

注册鼠标右击事件,positions 进行pop和push操作,移除动态position的polyline,添加新的polyline,该polyline的position为positions。

实现

class DrawPolyline {
  constructor(arg) {
    this.viewer = arg.viewer
    this.Cesium = arg.Cesium
    this.callback = arg.callback
    this._polyline = null //活动线
    this._polylineLast = null //最后一条线
    this._positions = [] //活动点
    this._entities_point = [] //脏数据
    this._entities_line = [] //脏数据
    this._polylineData = null //用于构造线数据
  }

  //返回最后活动线
  get line() {
    return this._polylineLast
  }

  //返回线数据用于加载线
  getData() {
    return this._polylineData
  }

  //加载线
  loadPolyline(data) {
    var $this = this
    var polyline = this.viewer.entities.add({
      polyline: {
        positions: data,
        show: true,
        material: $this.Cesium.Color.RED,
        width: 3,
        clampToGround: true,
      },
    })
    return polyline
  }

  //开始创建
  startCreate() {
    var $this = this
    this.handler = new this.Cesium.ScreenSpaceEventHandler(
      this.viewer.scene.canvas
    )
    this.handler.setInputAction(function (evt) {
      //单机开始绘制
      //屏幕坐标转地形上坐标
      var cartesian = $this.getCatesian3FromPX(evt.position)
      if ($this._positions.length == 0) {
        //第一个点要加两次,因为在move事件时,cartesian会弹出一个
        $this._positions.push(cartesian.clone())
      }
      $this._positions.push(cartesian)
      $this.createPoint(cartesian) // 绘制点
      console.log($this._positions)
    }, $this.Cesium.ScreenSpaceEventType.LEFT_CLICK)
    this.handler.setInputAction(function (evt) {
      //移动时绘制线
      if ($this._positions.length < 1) return
      var cartesian = $this.getCatesian3FromPX(evt.endPosition)
      if (!$this.Cesium.defined($this._polyline)) {
        $this._polyline = $this.createPolyline()
      }
      if ($this._polyline) {
        $this._positions.pop()
        $this._positions.push(cartesian)
      }
    }, $this.Cesium.ScreenSpaceEventType.MOUSE_MOVE)
    this.handler.setInputAction(function (evt) {
      if (!$this._polyline) return
      var cartesian = $this.getCatesian3FromPX(evt.position)
      $this._positions.pop()
      $this._positions.push(cartesian)
      $this.createPoint(cartesian) // 绘制点
      $this._polylineData = $this._positions.concat()
      $this.viewer.entities.remove($this._polyline) //移除
      $this._polyline = null
      $this._positions = []
      var line = $this.loadPolyline($this._polylineData) //加载线
      $this._entities_line.push(line)
      $this._polylineLast = line
      if (typeof $this.callback == 'function') {
        $this.callback(line)
      }
    }, $this.Cesium.ScreenSpaceEventType.RIGHT_CLICK)
  }

  //创建点
  createPoint(cartesian) {
    var $this = this
    var point = this.viewer.entities.add({
      position: cartesian,
      point: {
        pixelSize: 10,
        color: $this.Cesium.Color.YELLOW,
      },
    })
    $this._entities_point.push(point)
    return point
  }

  //创建线
  createPolyline() {
    var $this = this
    var polyline = this.viewer.entities.add({
      polyline: {
        //使用cesium的peoperty
        positions: new $this.Cesium.CallbackProperty(function () {
          return $this._positions
        }, false),
        show: true,
        material: $this.Cesium.Color.RED,
        width: 3,
        clampToGround: true,
      },
    })
    $this._entities_line.push(polyline)
    return polyline
  }

  //销毁
  destroy() {
    if (this.handler) {
      this.handler.destroy()
      this.handler = null
    }
  }

  //清空实体对象
  clear() {
    for (var i = 0; i < this._entities_point.length; i++) {
      this.viewer.entities.remove(this._entities_point[i])
    }
    for (var i = 0; i < this._entities_line.length; i++) {
      this.viewer.entities.remove(this._entities_line[i])
    }
    this._polyline = null
    this._positions = []
    this._entities_point = [] //脏数据
    this._entities_line = [] //脏数据
    this._polylineData = null //用于构造线数据
    this._polylineLast = null
  }

  getCatesian3FromPX(px) {
    var cartesian
    var ray = this.viewer.camera.getPickRay(px)
    if (!ray) return null
    cartesian = this.viewer.scene.globe.pick(ray, this.viewer.scene)
    return cartesian
  }
}

曲线

思路:与折线实现思路大致相同。需要注意:1.在move事件中positions长度小于4时,直接返回,因为当长度为3时,positions经过pop和push操作后有三个点,但只有两个不同点,无法拟合出曲线。2.在move事件中新建的polyline的动态position应该使用贝塞尔曲线拟合后的坐标。

实现:

class DrawCurve {
  constructor(arg) {
    this.viewer = arg.viewer
    this.Cesium = arg.Cesium
    this.callback = arg.callback
    this.floatingPoint = null //标识点
    this._curveline = null //活动曲线
    this._curvelineLast = null //最后一条曲线
    this._positions = [] //活动点
    this._entities_point = [] //脏数据
    this._entities_line = [] //脏数据
    this._curvelineData = null //用于构造曲线数据
  }

  //返回最后活动曲线
  get curveline() {
    return this._curvelineLast
  }

  //返回线数据用于加载线
  getData() {
    return this._curvelineData
  }

  //加载曲线
  loadCurveline(data) {
    var $this = this
    var points = $this.fineBezier(data)
    var polyline = this.viewer.entities.add({
      polyline: {
        positions: points,
        show: true,
        material: $this.Cesium.Color.RED,
        width: 3,
        clampToGround: true,
      },
    })
    return polyline
  }

  //开始创建
  startCreate() {
    var $this = this
    this.handler = new this.Cesium.ScreenSpaceEventHandler(
      this.viewer.scene.canvas
    )
    this.handler.setInputAction(function (evt) {
      //单机开始绘制
      //屏幕坐标转地形上坐标
      var cartesian = $this.getCatesian3FromPX(evt.position)
      if ($this._positions.length == 0) {
        $this._positions.push(cartesian.clone())
        $this.floatingPoint = $this.createPoint(cartesian)
        $this.createPoint(cartesian) // 绘制点
      }
      $this._positions.push(cartesian)
    }, $this.Cesium.ScreenSpaceEventType.LEFT_CLICK)
    this.handler.setInputAction(function (evt) {
      //移动时绘制线
      if ($this._positions.length < 4) return
      var cartesian = $this.getCatesian3FromPX(evt.endPosition)
      if (!$this.Cesium.defined($this._curveline)) {
        $this._curveline = $this.createCurveline()
      }
      //移动时显示当前点
      $this.floatingPoint.position.setValue(cartesian)
      if ($this._curveline) {
        $this._positions.pop()
        $this._positions.push(cartesian)
      }
    }, $this.Cesium.ScreenSpaceEventType.MOUSE_MOVE)
    this.handler.setInputAction(function (evt) {
      if (!$this._curveline) return
      var cartesian = $this.getCatesian3FromPX(evt.position)
      $this._positions.pop()
      $this._positions.push(cartesian)
      $this.createPoint(cartesian) // 绘制点
      $this._curvelineData = $this._positions.concat()
      $this.viewer.entities.remove($this._curveline) //移除
      $this._curveline = null
      $this._positions = []
      $this.floatingPoint.position.setValue(cartesian)
      var line = $this.loadCurveline($this._curvelineData) //加载曲线
      $this._entities_line.push(line)
      $this._curvelineLast = line
    }, $this.Cesium.ScreenSpaceEventType.RIGHT_CLICK)
  }

  //创建点
  createPoint(cartesian) {
    var $this = this
    var point = this.viewer.entities.add({
      position: cartesian,
      point: {
        pixelSize: 10,
        color: $this.Cesium.Color.YELLOW,
      },
    })
    $this._entities_point.push(point)
    return point
  }

  //创建曲线
  createCurveline() {
    var $this = this
    var polyline = this.viewer.entities.add({
      polyline: {
        //使用cesium的peoperty
        positions: new $this.Cesium.CallbackProperty(function () {
          return $this.fineBezier($this._positions)
        }, false),
        show: true,
        material: $this.Cesium.Color.RED,
        width: 3,
        clampToGround: true,
      },
    })
    $this._entities_line.push(polyline)
    return polyline
  }

  //销毁
  destroy() {
    if (this.handler) {
      this.handler.destroy()
      this.handler = null
    }
  }

  //清空实体对象
  clear() {
    for (var i = 0; i < this._entities_point.length; i++) {
      this.viewer.entities.remove(this._entities_point[i])
    }
    for (var i = 0; i < this._entities_line.length; i++) {
      this.viewer.entities.remove(this._entities_line[i])
    }
    this.floatingPoint = null //标识点
    this._curveline = null //活动曲线
    this._curvelineLast = null //最后一条曲线
    this._positions = [] //活动点
    this._entities_point = [] //脏数据
    this._entities_line = [] //脏数据
    this._curvelineData = null //用于构造曲线数据
  }

  getCatesian3FromPX(px) {
    var cartesian
    var ray = this.viewer.camera.getPickRay(px)
    if (!ray) return null
    cartesian = this.viewer.scene.globe.pick(ray, this.viewer.scene)
    return cartesian
  }

  cartesianToLatlng(cartesian) {
    var latlng =
      this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian)
    var lat = this.Cesium.Math.toDegrees(latlng.latitude)
    var lng = this.Cesium.Math.toDegrees(latlng.longitude)
    return [lng, lat]
  }

  //贝塞尔曲线实现

  fineBezier(points) {
    var $this = this
    var pointNUM = 40 //个点
    var poins2D = []
    var d = []
    for (var i = 0; i < points.length; i++) {
      var res = $this.cartesianToLatlng(points[i])
      var point = new Object()
      point.x = res[0]
      point.y = res[1]
      poins2D.push(point)
    }
    var cbs = $this.ComputeBezier(poins2D, pointNUM)
    for (var j = 0; j < cbs.length; j++) {
      d.push(cbs[j].x)
      d.push(cbs[j].y)
    }
    return $this.Cesium.Cartesian3.fromDegreesArray(d)
  }

  // cp在此是四個元素的陣列:
  // cp[0]為起始點,或上圖中的P0
  // cp[1]為第一個控制點,或上圖中的P1
  // cp[2]為第二個控制點,或上圖中的P2
  // cp[3]為結束點,或上圖中的P3
  // t為參數值,0 <= t <= 1

  PointOnCubicBezier(cp, t) {
    var ax, bx, cx
    var ay, by, cy
    var tSquared, tCubed
    var result = new Object()
    var length = cp.length
    var inteval = Math.floor(length / 4) // 向下取整
    /*計算多項式係數*/
    cx = 3.0 * (cp[inteval].x - cp[0].x)
    bx = 3.0 * (cp[2 * inteval].x - cp[inteval].x) - cx
    ax = cp[length - 1].x - cp[0].x - cx - bx
    cy = 3.0 * (cp[inteval].y - cp[0].y)
    by = 3.0 * (cp[2 * inteval].y - cp[inteval].y) - cy
    ay = cp[length - 1].y - cp[0].y - cy - by
    /*計算位於參數值t的曲線點*/
    tSquared = t * t
    tCubed = tSquared * t
    result.x = ax * tCubed + bx * tSquared + cx * t + cp[0].x
    result.y = ay * tCubed + by * tSquared + cy * t + cp[0].y
    return result
  }

  /*
ComputeBezier以控制點cp所產生的曲線點,填入Point2D結構的陣列。
呼叫者必須分配足夠的記憶體以供輸出結果,其為<sizeof(Point2D) numberOfPoints>
*/
  ComputeBezier(cp, numberOfPoints) {
    var $this = this
    var dt
    var i
    var curve = []
    dt = 1.0 / (numberOfPoints - 1)
    for (i = 0; i < numberOfPoints; i++) {
      curve[i] = $this.PointOnCubicBezier(cp, i * dt)
    }
    return curve
  }
}

绘制圆(圆心+半径)

思路:

注册左击事件,事件执行逻辑:在单击处添加点,作为圆心。将该位置添加至positions数组(首次两遍)

注册move事件,事件执行逻辑:创建ellipse实体并添加(只执行一次),该实体的semiMinorAxis和semiMajorAxis均为CallbackProperty,回调中实时计算半径(positions数组中第一个和最后一个点的距离,因为左击时一直向positions数组中添加点)。对positions数组执行pop和push操作。

注册右击事件,事件执行逻辑:对positions进行pop和push操作。删除move事件创建的ellipse实体,以positions数组中第一个点为原点,第一个点和最后一个点距离为半径创建ellipse实体并添加

//加载圆
  loadCicle(data) {
    var that = this
    var position = data[0]
    var value = data
    var r = Math.sqrt(
      Math.pow(value[0].x - value[value.length - 1].x, 2) +
        Math.pow(value[0].y - value[value.length - 1].y, 2)
    )
    var shape = this.viewer.entities.add({
      position: position,
      name: 'circle',
      type: 'circle',
      ellipse: {
        semiMinorAxis: r,
        semiMajorAxis: r,
        material: that.Cesium.Color.RED.withAlpha(0.5),
        outline: true,
      },
    })
    return shape
  }

  //返回数据
  getData() {
    return this._cicleData
  }

  startCreate() {
    this.handler = new this.Cesium.ScreenSpaceEventHandler(
      this.viewer.scene.canvas
    )
    this.viewer.scene.globe.depthTestAgainstTerrain = true
    var $this = this
    this.handler.setInputAction(function (evt) {
      //单机开始绘制
      $this.viewer.scene.globe.depthTestAgainstTerrain = true
      //屏幕坐标转地形上坐标
      var cartesian = $this.getCatesian3FromPX(evt.position)
      if ($this._positions.length == 0) {
        $this._positions.push(cartesian.clone())
        $this.floatingPoint = $this.createPoint(cartesian)
      }
      if (!$this._cicle) {
        $this.createPoint(cartesian) // 绘制点
      }
      $this._positions.push(cartesian)
    }, $this.Cesium.ScreenSpaceEventType.LEFT_CLICK)
    this.handler.setInputAction(function (evt) {
      //移动时绘制圆
      if ($this._positions.length < 1) return
      var cartesian = $this.viewer.scene.pickPosition(evt.endPosition) // $this.getCatesian3FromPX(evt.endPosition);
      if (!$this.Cesium.defined($this._cicle)) {
        $this._cicle = $this.createCicle()
      }
      $this.floatingPoint.position.setValue(cartesian)
      if ($this._cicle) {
        $this._positions.pop()
        $this._positions.push(cartesian)
      }
    }, $this.Cesium.ScreenSpaceEventType.MOUSE_MOVE)
    this.handler.setInputAction(function (evt) {
      if (!$this._cicle) return
      $this.viewer.scene.globe.depthTestAgainstTerrain = false
      var cartesian = $this.viewer.scene.pickPosition(evt.position) // $this.getCatesian3FromPX(evt.position);
      $this._positions.pop()
      $this._positions.push(cartesian)
      $this._cicleData = $this._positions.concat()
      $this.viewer.entities.remove($this._cicle) //移除
      $this._cicle = null
      $this._positions = []
      $this.floatingPoint.position.setValue(cartesian)
      var cicle = $this.loadCicle($this._cicleData) //加载
      $this._entities_cicle.push(cicle)
      $this._cicleLast = cicle
      $this.clearPoint()
      if (typeof $this.callback == 'function') {
        $this.callback(cicle)
      }
    }, $this.Cesium.ScreenSpaceEventType.RIGHT_CLICK)
  }

  //创建圆
  createCicle() {
    var that = this
    var shape = this.viewer.entities.add({
      position: that._positions[0],
      name: 'circle',
      type: 'circle',
      ellipse: {
        semiMinorAxis: new that.Cesium.CallbackProperty(function () {
          //半径 两点间距离
          var r = Math.sqrt(
            Math.pow(
              that._positions[0].x -
                that._positions[that._positions.length - 1].x,
              2
            ) +
              Math.pow(
                that._positions[0].y -
                  that._positions[that._positions.length - 1].y,
                2
              )
          )
          return r ? r : r + 1
        }, false),
        semiMajorAxis: new that.Cesium.CallbackProperty(function () {
          var r = Math.sqrt(
            Math.pow(
              that._positions[0].x -
                that._positions[that._positions.length - 1].x,
              2
            ) +
              Math.pow(
                that._positions[0].y -
                  that._positions[that._positions.length - 1].y,
                2
              )
          )
          return r ? r : r + 1
        }, false),
        material: that.Cesium.Color.RED.withAlpha(0.5),
        outline: true,
      },
    })
    that._entities_cicle.push(shape)
    return shape
  }

  //创建点
  createPoint(cartesian) {
    var $this = this
    var point = this.viewer.entities.add({
      position: cartesian,
      point: {
        pixelSize: 10,
        color: $this.Cesium.Color.YELLOW,
      },
    })
    $this._entities_point.push(point)
    return point
  }

  getCatesian3FromPX(px) {
    var cartesian
    var ray = this.viewer.camera.getPickRay(px)
    if (!ray) return null
    cartesian = this.viewer.scene.globe.pick(ray, this.viewer.scene)
    return cartesian
  }

  destroy() {
    if (this.handler) {
      this.handler.destroy()
      this.handler = null
    }
  }

  clearPoint() {
    for (var i = 0; i < this._entities_point.length; i++) {
      this.viewer.entities.remove(this._entities_point[i])
    }
    this._entities_point = [] //脏数据
  }
  clear() {
    for (var i = 0; i < this._entities_point.length; i++) {
      this.viewer.entities.remove(this._entities_point[i])
    }

    for (var i = 0; i < this._entities_cicle.length; i++) {
      this.viewer.entities.remove(this._entities_cicle[i])
    }
    this._cicle = null //活动圆
    this.floatingPoint = null
    this._cicleLast = null //最后一个圆
    this._positions = [] //活动点
    this._entities_point = [] //脏数据
    this._entities_cicle = [] //脏数据
    this._cicleData = null //用于构造圆形数据
  }
}

矩形(Rectangle.fromCartesianArray)

思路:

注册左击事件:在该位置添加点,将该位置push到positions数组(首次两遍)

注册move事件:positions长度小于3时,不执行逻辑直接返回。创建rectangle实体(只执行一次),coordinates属性设为CallbackProperty,回调中返回Cesium.Rectangle.fromCartesianArray(positions)(包含点的最小外接矩形)。对positions进行pop和push操作。

注册右击事件:对positions进行pop和push操作。删除动态属性的rectangle实体,新建相同的非动态属性的rectangle实体并添加。

实现

class DrawRectangle {
  constructor(arg) {
    this.viewer = arg.viewer
    this.Cesium = arg.Cesium
    this.callback = arg.callback
    this.floatingPoint = null //标识点
    this._rectangle = null //活动矩形
    this._rectangleLast = null //最后一个矩形
    this._positions = [] //活动点
    this._entities_point = [] //脏数据
    this._entities_rectangle = [] //脏数据
    this._rectangleData = null //用于构造矩形数据
  }

  //返回最后图形
  get line() {
    return this._rectangleLast
  }

  //返回矩形数据
  getData() {
    return this._rectangleData
  }

  //加载
  loadRectangle(data) {
    var $this = this
    var shape = this.viewer.entities.add({
      name: 'rectangle',
      rectangle: {
        coordinates: $this.Cesium.Rectangle.fromCartesianArray(data),
        material: $this.Cesium.Color.RED.withAlpha(0.5),
      },
    })
    $this._entities_rectangle.push(shape)
    return shape
  }

  //开始创建
  startCreate() {
    var $this = this
    this.handler = new this.Cesium.ScreenSpaceEventHandler(
      this.viewer.scene.canvas
    )
    this.handler.setInputAction(function (evt) {
      //单机开始绘制
      //屏幕坐标转地形上坐标
      var cartesian = $this.getCatesian3FromPX(evt.position)
      if ($this._positions.length == 0) {
        $this._positions.push(cartesian.clone())
        $this.floatingPoint = $this.createPoint(cartesian)
        $this.createPoint(cartesian) // 绘制点
      }
      $this._positions.push(cartesian)
    }, $this.Cesium.ScreenSpaceEventType.LEFT_CLICK)
    this.handler.setInputAction(function (evt) {
      //移动时绘制
      if ($this._positions.length < 3) return
      var cartesian = $this.getCatesian3FromPX(evt.endPosition)
      if (!$this.Cesium.defined($this._rectangle)) {
        $this._rectangle = $this.createRectangle()
      }
      $this.floatingPoint.position.setValue(cartesian)
      if ($this._rectangle) {
        $this._positions.pop()
        $this._positions.push(cartesian)
      }
    }, $this.Cesium.ScreenSpaceEventType.MOUSE_MOVE)
    this.handler.setInputAction(function (evt) {
      if (!$this._rectangle) return
      var cartesian = $this.getCatesian3FromPX(evt.position)
      $this._positions.pop()
      $this._positions.push(cartesian)
      $this.createPoint(cartesian) // 绘制点
      $this._rectangleData = $this._positions.concat()
      $this.viewer.entities.remove($this._rectangle) //移除
      $this._rectangle = null
      $this._positions = []
      $this.floatingPoint.position.setValue(cartesian)
      var rectangle = $this.loadRectangle($this._rectangleData) //加载
      $this._entities_rectangle.push(rectangle)
      $this._rectangleLast = rectangle
      if (typeof $this.callback == 'function') {
        $this.callback(rectangle)
      }
    }, $this.Cesium.ScreenSpaceEventType.RIGHT_CLICK)
  }

  //创建点
  createPoint(cartesian) {
    var $this = this
    var point = this.viewer.entities.add({
      position: cartesian,
      point: {
        pixelSize: 10,
        color: $this.Cesium.Color.YELLOW,
      },
    })
    $this._entities_point.push(point)
    return point
  }

  //创建矩形
  createRectangle() {
    var $this = this
    var shape = this.viewer.entities.add({
      name: 'rectangle',
      rectangle: {
        coordinates: new $this.Cesium.CallbackProperty(function () {
          var obj = $this.Cesium.Rectangle.fromCartesianArray($this._positions)
          return obj
        }, false),
        material: $this.Cesium.Color.RED.withAlpha(0.5),
      },
    })
    $this._entities_rectangle.push(shape)
    return shape
  }

  //销毁
  destroy() {
    if (this.handler) {
      this.handler.destroy()
      this.handler = null
    }
  }

  //清空实体对象
  clear() {
    for (var i = 0; i < this._entities_point.length; i++) {
      this.viewer.entities.remove(this._entities_point[i])
    }
    for (var i = 0; i < this._entities_rectangle.length; i++) {
      this.viewer.entities.remove(this._entities_rectangle[i])
    }
    this.floatingPoint = null //标识点
    this._rectangle = null //活动矩形
    this._rectangleLast = null //最后一个矩形
    this._positions = [] //活动点
    this._entities_point = [] //脏数据
    this._entities_rectangle = [] //脏数据
    this._rectangleData = null //用于构造矩形数据
  }

  getCatesian3FromPX(px) {
    var cartesian
    var ray = this.viewer.camera.getPickRay(px)
    if (!ray) return null
    cartesian = this.viewer.scene.globe.pick(ray, this.viewer.scene)
    return cartesian
  }
}

思路:

注册左击事件:在该位置添加点,将该位置push到positions数组(首次两遍)

注册move事件:positions长度小于2时,不执行逻辑直接返回。创建polygon实体(只创建一次),hierarchy属性设为CallbackProperty,回调中返回new Cesium.PolygonHierarchy(positions)。对positions进行pop和push操作。

注册右击事件:对positions进行pop和push操作。删除动态属性的polygon实体,新建相同的非动态属性的polygon实体并添加。

实现:

class DrawPolygon {
  constructor(arg) {
    this.viewer = arg.viewer
    this.Cesium = arg.Cesium
    this.callback = arg.callback
    this._polygon = null //活动面
    this._polygonLast = null //最后一个面
    this._positions = [] //活动点
    this._entities_point = [] //脏数据
    this._entities_polygon = [] //脏数据
    this._polygonData = null //用户构造面
  }

  //返回最后活动面
  get polygon() {
    return this._polygonLast
  }

  //返回面数据用于加载面
  getData() {
    return this._polygonData
  }

  //加载面
  loadPolygon(data) {
    var $this = this
    return this.viewer.entities.add({
      polygon: {
        hierarchy: new $this.Cesium.PolygonHierarchy(data),
        clampToGround: true,
        show: true,
        fill: true,
        material: $this.Cesium.Color.RED.withAlpha(0.5),
        width: 3,
        outlineColor: $this.Cesium.Color.BLACK,
        outlineWidth: 1,
        outline: false,
      },
    })
  }

  //开始绘制
  startCreate() {
    var $this = this
    this.handler = new this.Cesium.ScreenSpaceEventHandler(
      this.viewer.scene.canvas
    )
    this.handler.setInputAction(function (evt) {
      //单机开始绘制
      var cartesian = $this.getCatesian3FromPX(evt.position)
      if ($this._positions.length == 0) {
        $this._positions.push(cartesian.clone())
      }
      $this.createPoint(cartesian)
      $this._positions.push(cartesian)
    }, $this.Cesium.ScreenSpaceEventType.LEFT_CLICK)
    this.handler.setInputAction(function (evt) {
      //移动时绘制面
      if ($this._positions.length < 1) return
      var cartesian = $this.getCatesian3FromPX(evt.endPosition)
      // if ($this._positions.length == 3) {
      if (!$this.Cesium.defined($this._polygon)) {
        $this._polygon = $this.createPolygon()
      }
      // }
      $this._positions.pop()
      $this._positions.push(cartesian)
    }, $this.Cesium.ScreenSpaceEventType.MOUSE_MOVE)
    this.handler.setInputAction(function (evt) {
      if (!$this._polygon) return
      var cartesian = $this.getCatesian3FromPX(evt.position)
      $this._positions.pop()
      $this._positions.push(cartesian)
      $this.createPoint(cartesian)
      $this._polygonData = $this._positions.concat()
      $this.viewer.entities.remove($this._positions) //移除
      $this._positions = null
      $this._positions = []
      var Polygon = $this.loadPolygon($this._polygonData)
      $this._entities_polygon.push(Polygon)
      $this._polygonLast = Polygon
      if (typeof $this.callback == 'function') {
        $this.callback(Polygon)
      }
    }, $this.Cesium.ScreenSpaceEventType.RIGHT_CLICK)
  }

  //创建面
  createPolygon() {
    var $this = this
    var polygon = this.viewer.entities.add({
      polygon: {
        hierarchy: new $this.Cesium.CallbackProperty(function () {
          return new $this.Cesium.PolygonHierarchy($this._positions)
        }, false),
        clampToGround: true,
        show: true,
        fill: true,
        material: $this.Cesium.Color.RED.withAlpha(0.5),
        width: 3,
        outlineColor: $this.Cesium.Color.BLACK,
        outlineWidth: 1,
        outline: false,
      },
    })
    $this._entities_polygon.push(polygon)
    return polygon
  }

  //创建点
  createPoint(cartesian) {
    var $this = this
    var point = this.viewer.entities.add({
      position: cartesian,
      point: {
        pixelSize: 10,
        color: $this.Cesium.Color.YELLOW,
      },
    })
    $this._entities_point.push(point)
    return point
  }

  //销毁事件
  destroy() {
    if (this.handler) {
      this.handler.destroy()
      this.handler = null
    }
  }

  //清空实体对象
  clear() {
    for (var i = 0; i < this._entities_point.length; i++) {
      this.viewer.entities.remove(this._entities_point[i])
    }
    for (var i = 0; i < this._entities_polygon.length; i++) {
      this.viewer.entities.remove(this._entities_polygon[i])
    }
    this._polygon = null //活动面
    this._polygonLast = null //最后一个面
    this._positions = [] //活动点
    this._entities_point = [] //脏数据
    this._entities_polygon = [] //脏数据
    this._polygonData = null //用户构造面
  }

  getCatesian3FromPX(px) {
    var cartesian
    var ray = this.viewer.camera.getPickRay(px)
    if (!ray) return null
    cartesian = this.viewer.scene.globe.pick(ray, this.viewer.scene)
    return cartesian
  }
}

箭头

注册左击事件:在该位置添加点,将该位置push到positions数组(首次两遍)

注册move事件:positions长度小于2时,不执行逻辑直接返回。创建polygon实体(只创建一次),hierarchy属性设为CallbackProperty,回调中将positions第一个点和最后一个点作为箭头的起点和终点,计算箭头各个点的cartesian3坐标,存储到cartesian3数组res中,返回new Cesium.PolygonHierarchy(res)。对positions进行pop和push操作。

注册右击事件:对positions进行pop和push操作。删除动态属性的polygon实体,新建相同的非动态属性的polygon实体并添加。

计算箭头各个点的逻辑:已知一个点的位置和两点的距离和方向,求第三个点的位置

实现

class DrawStraightArrow {
  constructor(arg) {
    this.viewer = arg.viewer
    this.Cesium = arg.Cesium
    this.callback = arg.callback
    this.floatingPoint = null //标识点
    this._straightArrow = null //活动箭头
    this._straightArrowLast = null //最后一个箭头
    this._positions = [] //活动点
    this._entities_point = [] //脏数据
    this._entities_straightArrow = [] //脏数据
    this._straightArrowData = null //用于构造箭头数据
  }

  //返回箭头
  get straightArrow() {
    return this._straightArrowLast
  }

  //返回箭头数据用于加载箭头
  getData() {
    return this._straightArrowData
  }

  //加载箭头
  loadStraightArrow(data) {
    var $this = this
    if (data.length < 2) {
      return null
    }
    var length = data.length
    var p1 = data[0]
    var p2 = data[length - 1]
    var firstPoint = $this.cartesianToLatlng(p1)
    var endPoints = $this.cartesianToLatlng(p2)
    var arrow = []
    var res = $this.fineArrow(
      [firstPoint[0], firstPoint[1]],
      [endPoints[0], endPoints[1]]
    )
    for (var i = 0; i < res.length; i++) {
      var cart3 = new $this.Cesium.Cartesian3(res[i].x, res[i].y, res[i].z)
      arrow.push(cart3)
    }
    var arrowEntity = $this.viewer.entities.add({
      polygon: {
        hierarchy: new $this.Cesium.PolygonHierarchy(arrow),
        show: true,
        fill: true,
        clampToGround: true,
        material: $this.Cesium.Color.AQUA.withAlpha(0.5),
      },
    })
    return arrowEntity
  }

  //开始创建
  startCreate() {
    var $this = this
    this.handler = new this.Cesium.ScreenSpaceEventHandler(
      this.viewer.scene.canvas
    )
    this.handler.setInputAction(function (evt) {
      //单机开始绘制
      //屏幕坐标转地形上坐标
      var cartesian = $this.getCatesian3FromPX(evt.position)
      if ($this._positions.length == 0) {
        $this._positions.push(cartesian.clone())
        $this.floatingPoint = $this.createPoint(cartesian)
      }
      if (!$this._straightArrow) {
        $this.createPoint(cartesian) // 绘制点
      }
      $this._positions.push(cartesian)
    }, $this.Cesium.ScreenSpaceEventType.LEFT_CLICK)
    this.handler.setInputAction(function (evt) {
      //移动时绘制
      if ($this._positions.length < 2) return
      var cartesian = $this.getCatesian3FromPX(evt.endPosition)
      if (!$this.Cesium.defined($this._straightArrow)) {
        $this._straightArrow = $this.createStraightArrow()
      }
      $this.floatingPoint.position.setValue(cartesian)
      if ($this._straightArrow) {
        $this._positions.pop()
        $this._positions.push(cartesian)
      }
    }, $this.Cesium.ScreenSpaceEventType.MOUSE_MOVE)

    this.handler.setInputAction(function (evt) {
      if (!$this._straightArrow) return
      var cartesian = $this.getCatesian3FromPX(evt.position)
      $this._positions.pop()
      $this._positions.push(cartesian)
      $this._straightArrowData = $this._positions.concat()
      $this.viewer.entities.remove($this._straightArrow) //移除
      $this._straightArrow = null
      $this._positions = []
      $this.floatingPoint.position.setValue(cartesian)
      var straightArrow = $this.loadStraightArrow($this._straightArrowData) //加载
      $this._entities_straightArrow.push(straightArrow)
      $this._straightArrowLast = straightArrow
      $this.clearPoint()
    }, $this.Cesium.ScreenSpaceEventType.RIGHT_CLICK)
  }

  //创建直线箭头
  createStraightArrow() {
    var $this = this
    var arrowEntity = $this.viewer.entities.add({
      polygon: {
        hierarchy: new $this.Cesium.CallbackProperty(function () {
          // return new $this.Cesium.PolygonHierarchy($this._positions);
          var length = $this._positions.length
          var p1 = $this._positions[0]
          var p2 = $this._positions[length - 1]
          var firstPoint = $this.cartesianToLatlng(p1)
          var endPoints = $this.cartesianToLatlng(p2)
          var arrow = []
          var res = $this.fineArrow(
            [firstPoint[0], firstPoint[1]],
            [endPoints[0], endPoints[1]]
          )
          for (var i = 0; i < res.length; i++) {
            var cart3 = new $this.Cesium.Cartesian3(
              res[i].x,
              res[i].y,
              res[i].z
            )
            arrow.push(cart3)
          }
          return new $this.Cesium.PolygonHierarchy(arrow)
        }, false),
        show: true,
        fill: true,
        clampToGround: true,
        material: $this.Cesium.Color.AQUA.withAlpha(0.5),
      },
    })
    $this._entities_straightArrow.push(arrowEntity)
    return arrowEntity
  }

  //创建点
  createPoint(cartesian) {
    var $this = this
    var point = this.viewer.entities.add({
      position: cartesian,
      point: {
        pixelSize: 10,
        color: $this.Cesium.Color.YELLOW,
      },
    })
    $this._entities_point.push(point)
    return point
  }

  cartesianToLatlng(cartesian) {
    var latlng =
      this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian)
    var lat = this.Cesium.Math.toDegrees(latlng.latitude)
    var lng = this.Cesium.Math.toDegrees(latlng.longitude)
    return [lng, lat]
  }

  //销毁
  destroy() {
    if (this.handler) {
      this.handler.destroy()
      this.handler = null
    }
  }

  clearPoint() {
    for (var i = 0; i < this._entities_point.length; i++) {
      this.viewer.entities.remove(this._entities_point[i])
    }
    this._entities_point = [] //脏数据
  }

  //清空实体对象
  clear() {
    for (var i = 0; i < this._entities_point.length; i++) {
      this.viewer.entities.remove(this._entities_point[i])
    }
    for (var i = 0; i < this._entities_straightArrow.length; i++) {
      this.viewer.entities.remove(this._entities_straightArrow[i])
    }

    this.floatingPoint = null //标识点
    this._straightArrow = null //活动箭头
    this._straightArrowLast = null //最后一个箭头
    this._positions = [] //活动点
    this._entities_point = [] //脏数据
    this._entities_straightArrow = [] //脏数据
    this._straightArrowData = null //用于构造箭头数据
  }

  getCatesian3FromPX(px) {
    var cartesian
    var ray = this.viewer.camera.getPickRay(px)
    if (!ray) return null
    cartesian = this.viewer.scene.globe.pick(ray, this.viewer.scene)
    return cartesian
  }

  // 求取箭头坐标函数
  //箭头配置函数
  fineArrowDefualParam() {
    return {
      tailWidthFactor: 0.15,
      neckWidthFactor: 0.2,
      headWidthFactor: 0.25,
      headAngle: Math.PI / 8.5,
      neckAngle: Math.PI / 13,
    }
  }

  fineArrow(tailPoint, headerPoint) {
    var $this = this
    if (tailPoint.length < 2 || headerPoint.length < 2) return
    //画箭头的函数
    // let tailWidthFactor = $this.fineArrowDefualParam().tailWidthFactor
    // let neckWidthFactor = $this.fineArrowDefualParam().neckWidthFactor
    // let headWidthFactor = $this.fineArrowDefualParam().headWidthFactor
    // let headAngle = $this.fineArrowDefualParam().headAngle
    // let neckAngle = $this.fineArrowDefualParam().neckAngle
    let {
      tailWidthFactor,
      neckWidthFactor,
      headWidthFactor,
      headAngle,
      neckAngle,
    } = { ...$this.fineArrowDefualParam() }
    var o = []
    o[0] = tailPoint
    o[1] = headerPoint
    var e = o[0], //起点
      r = o[1], //终点
      n = $this.getBaseLength(o),
      g = n * tailWidthFactor,
      //尾部宽度因子
      i = n * neckWidthFactor,
      //脖子宽度银子
      s = n * headWidthFactor,
      //头部宽度因子
      a = $this.getThirdPoint(r, e, Math.PI / 2, g, !0),
      l = $this.getThirdPoint(r, e, Math.PI / 2, g, !1),
      u = $this.getThirdPoint(e, r, headAngle, s, !1),
      c = $this.getThirdPoint(e, r, headAngle, s, !0),
      p = $this.getThirdPoint(e, r, neckAngle, i, !1),
      h = $this.getThirdPoint(e, r, neckAngle, i, !0),
      d = []
    d.push(
      a[0],
      a[1],
      p[0],
      p[1],
      u[0],
      u[1],
      r[0],
      r[1],
      c[0],
      c[1],
      h[0],
      h[1],
      l[0],
      l[1],
      e[0],
      e[1]
    )
    return $this.Cesium.Cartesian3.fromDegreesArray(d)
  }

  getBaseLength(t) {
    return Math.pow(this.wholeDistance(t), 0.99)
  }

  wholeDistance(t) {
    for (var o = 0, e = 0; e < t.length - 1; e++)
      o += this.distance(t[e], t[e + 1])
    return o
  }

  distance(t, o) {
    return Math.sqrt(Math.pow(t[0] - o[0], 2) + Math.pow(t[1] - o[1], 2))
  }

  getThirdPoint(t, o, e, r, n) {
    var g = this.getAzimuth(t, o),
      i = n ? g + e : g - e,
      s = r * Math.cos(i),
      a = r * Math.sin(i)
    return [o[0] + s, o[1] + a]
  }

  getAzimuth(t, o) {
    var e,
      r = Math.asin(Math.abs(o[1] - t[1]) / this.distance(t, o))
    return (
      o[1] >= t[1] && o[0] >= t[0]
        ? (e = r + Math.PI)
        : o[1] >= t[1] && o[0] < t[0]
        ? (e = 2 * Math.PI - r)
        : o[1] < t[1] && o[0] < t[0]
        ? (e = r)
        : o[1] < t[1] && o[0] >= t[0] && (e = Math.PI - r),
      e
    )
  }
}

测量

测距

与绘制折线逻辑相同,只不过在左击事件时,在单击处添加lable实体,其text属性为当前positions数组中点距之和。距离计算分两种:

1.使用EllipsoidGeodesic计算贴地距离

let geodesic = new Cesium.EllipsoidGeodesic()
geodesic.setEndPoints(point1cartographic, point2cartographic)
let s = geodesic.surfaceDistance

2.使用Cesium.Cartesian3.distance()计算空间距离

let s = Cesium.Cartesian3.distance(cartesianFirst,cartesianSecond);

测面积

与绘制polygon逻辑相同,在右击逻辑中添加label实体,其text为polygon的面积。面积计算:利用positions数组拼接为geojson,使用turf.js计算

三角测量

同时绘制三条线:两点间直线、水平线和垂直线

注册左击事件:在该处绘制点,获取该点的cartesian3坐标,push到cartesin3数组positions(直线)和tempPoints(垂直线)中(两次)

注册move事件:判断positions长度小于2,直接返回不执行逻辑。获取点坐标,根据该点坐标和positions中第一个点坐标计算直角点坐标(经纬度为positions中第一个点经纬度,高度为最新获取点的高度),对positions和tempPoints进行pop和push操作,对tempPoints2(水平线)进行两次pop后,将直角点和最新获取点push进去,创建3个polyline实体(只创建一次),polyline的positions为CallbackProperty,回调中分别返回positions、tempPoints、tempPoints2,作为直线、垂直线、水平线。分别为三个实体设置label,label的text也为CallbackProperty,回调中返回根据相应polyline的positions计算的距离。分别将三个实体的position设置为CallbackProperty(保证label的位置正确),回调中返回相应polyline的positions的第一个点。

注册右击事件:如果不想继续测量可以直接handler.destroy()。如果需要继续测量,则需要根据上述三个动态属性的实体创建三个相应的固定属性的实体(与相应实体最新属性保持一致)并添加,最后将上述三个动态属性的实体移除。清空positions、tempPoints、tempPoints2

仓库地址:https://gitee.com/long-time-no-see-12/cesium-learn2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值