Cesium 自定义Primitive - 矩形

本文介绍了如何在Vue项目中创建一个自定义的CustomRectanglePrimitive,利用cesium库处理几何图形,根据两点生成矩形,提供动态更新属性的方法,用于实时调整矩形位置。

一、创作思路

        1、创建一个自定义CustomPrimitive,包括update和destroy方法

        2、然后根据两个点,生成矩形,取两点的包围和为矩形,得到的矩形为正矩形

        3、暴露更新属性方法,updateProperty,方便后期绘制矩形

二、实现代码

      1、turf

        在vue的包中引入turf:npm install @turf/turf或者yarn add @turf/turf

      2、自定义CustomRectanglePrimitive

        创建一个CustomRectanglePrimitive类,并加入更新、销毁的代码

import {
  Color,
  GeometryInstance,
  GroundPolylineGeometry,
  GroundPolylinePrimitive,
  Material,
  PolylineMaterialAppearance,
} from "cesium";
import { getRectanglePositions } from "@/components/MilitaryPlot/utils/PlotUtils";

export default class CustomRectanglePrimitive {
  constructor(options) {
    this._props = options;
    /**
     * 渲染列表
     * @type {*[]}
     * @private
     */
    this._primitiveCollection = [];

    this._dynamicPrimitive = undefined;
  }
  updateProperty(options) {
  }
  /**
   * 更新
   * @param frameState
   */
  update(frameState) {
    this._primitiveCollection.forEach((primitive) => {
      primitive && !primitive.isDestroyed() && primitive.update(frameState);
    });
    if (this._dynamicPrimitive) {
      this._dynamicPrimitive.update(frameState);
    }
  }
  destroy() {
    this._primitiveCollection.forEach((primitive) => {
      primitive && !primitive.isDestroyed() && primitive.destroy();
    });
    this._primitiveCollection = undefined;
    if (this._dynamicPrimitive) {
      this._dynamicPrimitive.destroy();
    }
    this._dynamicPrimitive = undefined;
  }
}

      3、更新属性

        对外暴露更新属性方法,主要参数为positions以及complete

        positions:点位用于确认矩形框

        complete:表示是否完成绘制

updateProperty(options) {
    this._props = {
      ...this._props,
      ...options,
    };
    let positions = this._props.positions;
    let complete = this._props.complete;
    if (positions.length > 1) {
      let dynamicPrimitive = this._dynamicPrimitive;
      if (dynamicPrimitive) {
        dynamicPrimitive.destroy();
        dynamicPrimitive = null;
        this._dynamicPrimitive = null;
      }
      let primitive = this.initRectanglePrimitive(positions);
      if (complete) {
        this._primitiveCollection.push(primitive);
      } else {
        this._dynamicPrimitive = primitive;
      }
    }
  }

     4、生成矩形

        编写绘制矩形的代码

initRectanglePrimitive(positions) {
    let rectanglePositions = getRectanglePositions(positions);
    let instance = new GeometryInstance({
      geometry: new GroundPolylineGeometry({
        positions: rectanglePositions,
        width: 4,
      }),
    });
    return new GroundPolylinePrimitive({
      geometryInstances: instance,
      appearance: new PolylineMaterialAppearance({
        material: new Material({
          fabric: {
            type: "Color",
            uniforms: {
              color: Color.fromCssColorString("#ff0000"),
            },
          },
        }),
      }),
      asynchronous: false,
    });
  }

      5、 坐标转换

        1、将世界坐标转换值WGS84坐标

        2、根据点位生成矩形包围盒,然后转换为世界坐标

const ellipsoid = Ellipsoid.WGS84;
/**
 * 将世界坐标系转换为球面坐标系
 * @param {Cartesian3} position
 * @return {{alt: number, lon: number, lat: number}}
 */
export const Cartesian3ToWgs84 = (position) => {
  let cartographic = ellipsoid.cartesianToCartographic(position);
  let lon = CesiumMath.toDegrees(cartographic.longitude);
  let lat = CesiumMath.toDegrees(cartographic.latitude);
  let alt = cartographic.height;
  return {
    lon,
    lat,
    alt,
  };
};
/**
 * 将世界坐标系转换为球面坐标系
 * @param {Cartesian3[]} positions
 * @return {{alt: number, lon: number, lat: number}[]}
 */
export const Cartesian3ListToWgs84 = (positions) => {
  return positions.map((position) => Cartesian3ToWgs84(position));
};
export const getRectanglePositions = (positions) => {
  let position84List = Cartesian3ListToWgs84(positions);
  let featureList = featureCollection(
    position84List.map((item) => point([item.lon, item.lat]))
  );
  let enveloped = envelope(featureList);
  return enveloped.geometry.coordinates[0].map((item) => {
    return Cartesian3.fromDegrees(item[0], item[1]);
  });
};

      6、测试代码

        测试代码,每个1秒,更新控制点位,连续更新10次

let primitive = new CustomRectanglePrimitive();
      viewer.scene.primitives.add(primitive);
      let lon = 106;
      let count = 0;
      let lat = 26;
      let centerP = Cartesian3.fromDegrees(lon, lat);
      let interval = setInterval(() => {
        count++;
        let lonTemp = lon + count * 0.00002;
        let latTemp = lat + count * 0.00001;
        let nextP = Cartesian3.fromDegrees(lonTemp, latTemp);
        primitive.updateProperty({
          positions: [centerP, nextP],
          complete: count === 11,
        });
        if (count > 10) {
          primitive.updateProperty({
            positions: [centerP, nextP],
            complete: true,
          });
          clearInterval(interval);
        } else {
          primitive.updateProperty({
            positions: [centerP, nextP],
            complete: false,
          });
        }
      }, 1000);

三、展示效果

四、全部代码

import {
  Color,
  GeometryInstance,
  GroundPolylineGeometry,
  GroundPolylinePrimitive,
  Material,
  PolylineMaterialAppearance,
} from "cesium";
import { getRectanglePositions } from "@/components/MilitaryPlot/utils/PlotUtils";

export default class CustomRectanglePrimitive {
  constructor(options) {
    this._props = options;
    /**
     * 渲染列表
     * @type {*[]}
     * @private
     */
    this._primitiveCollection = [];

    this._dynamicPrimitive = undefined;
  }
  updateProperty(options) {
    this._props = {
      ...this._props,
      ...options,
    };
    let positions = this._props.positions;
    let complete = this._props.complete;
    if (positions.length > 1) {
      let dynamicPrimitive = this._dynamicPrimitive;
      if (dynamicPrimitive) {
        dynamicPrimitive.destroy();
        dynamicPrimitive = null;
        this._dynamicPrimitive = null;
      }
      let primitive = this.initRectanglePrimitive(positions);
      if (complete) {
        this._primitiveCollection.push(primitive);
      } else {
        this._dynamicPrimitive = primitive;
      }
    }
  }
  initRectanglePrimitive(positions) {
    let rectanglePositions = getRectanglePositions(positions);
    let instance = new GeometryInstance({
      geometry: new GroundPolylineGeometry({
        positions: rectanglePositions,
        width: 4,
      }),
    });
    return new GroundPolylinePrimitive({
      geometryInstances: instance,
      appearance: new PolylineMaterialAppearance({
        material: new Material({
          fabric: {
            type: "Color",
            uniforms: {
              color: Color.fromCssColorString("#ff0000"),
            },
          },
        }),
      }),
      asynchronous: false,
    });
  }
  /**
   * 更新
   * @param frameState
   */
  update(frameState) {
    this._primitiveCollection.forEach((primitive) => {
      primitive && !primitive.isDestroyed() && primitive.update(frameState);
    });
    if (this._dynamicPrimitive) {
      this._dynamicPrimitive.update(frameState);
    }
  }
  destroy() {
    this._primitiveCollection.forEach((primitive) => {
      primitive && !primitive.isDestroyed() && primitive.destroy();
    });
    this._primitiveCollection = undefined;
    if (this._dynamicPrimitive) {
      this._dynamicPrimitive.destroy();
    }
    this._dynamicPrimitive = undefined;
  }
}

评论 6
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

生活真难

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值