Cesium 自定义Primitive - 圆

一、创作思路

        1、创建一个自定义CustomPrimitive

        2、然后根据两个点,生成圆

        3、方便后期绘制圆

二、实现代码

        1、在vue的包中加入turf.

        npm install @turf/turf

        1、创建一个CustomCirclePrimitive类,并加入更新的代码

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

    this._dynamicPrimitive = undefined;
  }
  updateProperty(options) {
    this._props = {
      ...this._props,
      ...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;
  }
}

        2、编写更新代码

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.initCirclePrimitive(positions);
      if (complete) {
        this._primitiveCollection.push(primitive);
      } else {
        this._dynamicPrimitive = primitive;
      }
    }
  }

        3、编写绘制圆的代码

        设定第一个点为中心点,第二个点为半径上面的点

        半径为第一个点到第二个点的距离

initCirclePrimitive(positions) {
    let centerP = positions[0];
    let radiusP = positions[1];
    let radius = getDistance(centerP, radiusP);
    let circlePositions = getCircle(centerP, radius);
    let instance = new GeometryInstance({
      geometry: new GroundPolylineGeometry({
        positions: circlePositions,
        width: 4,
      }),
    });
    return new GroundPolylinePrimitive({
      geometryInstances: instance,
      appearance: new PolylineMaterialAppearance({
        material: new Material({
          fabric: {
            type: "Color",
            uniforms: {
              color: Color.fromCssColorString("#ff0000"),
            },
          },
        }),
      }),
      asynchronous: false,
    });
  }

        4、额外的算法代码

        

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} startPoint 起点
 * @param {Cartesian3} endPoint 终点
 * @return {number} 平面距离
 */
export const getDistance = (startPoint, endPoint) => {
  let start84 = Cartesian3ToWgs84(startPoint);
  let end84 = Cartesian3ToWgs84(endPoint);
  let startPosition = point([start84.lon, start84.lat]);
  let endPosition = point([end84.lon, end84.lat]);
  let startToEnd = distance(startPosition, endPosition, options);
  return startToEnd * 1000;
};
/**
 * 根据半径和中心点,获取圆形
 * @param center
 * @param radius
 * @return {Cartesian3[]}
 */
export const getCircle = (center, radius) => {
  let center84 = Cartesian3ToWgs84(center);
  let centerP = [center84.lon, center84.lat];
  let circleInfo = circle(centerP, radius / 1000.0, options);
  return circleInfo.geometry.coordinates[0].map((item) => {
    return Cartesian3.fromDegrees(item[0], item[1]);
  });
};

        5、测试代码

        

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

三、实现效果

四、代码

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

export default class CustomCirclePrimitive {
  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.initCirclePrimitive(positions);
      if (complete) {
        this._primitiveCollection.push(primitive);
      } else {
        this._dynamicPrimitive = primitive;
      }
    }
  }
  initCirclePrimitive(positions) {
    let centerP = positions[0];
    let radiusP = positions[1];
    let radius = getDistance(centerP, radiusP);
    let circlePositions = getCircle(centerP, radius);
    let instance = new GeometryInstance({
      geometry: new GroundPolylineGeometry({
        positions: circlePositions,
        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;
  }
}

  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

生活真难

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

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

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

打赏作者

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

抵扣说明:

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

余额充值