Cesium 自定义Primitive - 绘制多边形

本文介绍了如何在Cesium中使用CustomPolygonPrimitive绘制多边形,包括创建自定义primitive,处理属性更新,以及通过DrawPolygonTool实现用户交互式绘制。

一、创作来源

        1、cesium的entity绘制多边形

        2、不使用entity的情况下,使用自定义的primitive来绘制多边形

        3、同时使用自定义Primitive来执行属性更新,动态绘制多边形

二、创建自定义Primitive

1、CustomPolygonPrimitive

        1、创建类CustomPolygonPrimitive 

        2、编写构造函数,定义该对象的一些私有属性

        3、编写更新属性函数updateProperty

        4、编写渲染代码

        5、编写销毁代码

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

    this._dynamicPrimitive = undefined;
  }

  /**
   * 更新属性
   * @param options
   */
  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;
  }
}

2、编写更新属性代码

        当点位个数大于1个点的时候,开启对象的渲染

/**
   * 更新属性
   * @param options
   */
  updateProperty(options) {
    this._props = {
      ...this._props,
      ...options,
    };
    let positions = this._props.positions;
    let complete = this._props.complete;
    if (positions.length >= 2) {
      let dynamicPrimitive = this._dynamicPrimitive;
      if (dynamicPrimitive) {
        dynamicPrimitive.destroy();
        dynamicPrimitive = null;
        this._dynamicPrimitive = null;
      }
      let primitive = this.initPolygonPrimitive(positions);
      if (complete) {
        this._primitiveCollection.push(primitive);
      } else {
        this._dynamicPrimitive = primitive;
      }
    }
  }

3、编写多边形线的渲染代码

        当点位数大于2的时候,闭合形成多边形

/**
   * 初始化渲染对象
   * @param positions
   * @return {module:cesium.GroundPolylinePrimitive}
   */
  initPolygonPrimitive(positions) {
    let instance = new GeometryInstance({
      geometry: new GroundPolylineGeometry({
        positions: positions,
        width: 4,
        loop: positions.length > 2,
      }),
    });
    return new GroundPolylinePrimitive({
      geometryInstances: instance,
      appearance: new PolylineMaterialAppearance({
        material: new Material({
          fabric: {
            type: "Color",
            uniforms: {
              color: Color.fromCssColorString("#ff0000"),
            },
          },
        }),
      }),
      asynchronous: false,
    });
  }

二、创建绘制类

1、创建DrawPolygonTool

        1、编写构造函数

        2、编写绘制方法调用

        3、编写销毁代码

import { Viewer, ScreenSpaceEventHandler, ScreenSpaceEventType } from "cesium";
import { pickPosition } from "@/components/MilitaryPlot/utils/PlotUtils";
import CustomPolylinePrimitive from "@/components/entity/CustomPolylinePrimitive";
export default class DrawPolygonTool {
  /**
   * 构造函数
   * @param {Viewer} viewer
   */
  constructor(viewer) {
    /**
     * 地球视图
     * @type {Viewer}
     * @private
     */
    this._viewer = viewer;
    /**
     * 线对象
     * @type {CustomPolygonPrimitive}
     * @private
     */
    this._primitive = undefined;
    /**
     * 事件
     * @type {ScreenSpaceEventHandler}
     * @private
     */
    this._handler = undefined;
  }

  /**
   * 绘图
   */
  draw() {}
  /**
   * 销毁
   */
  destroy() {
    if (this._handler) {
      this._handler.isDestroyed() && this._handler.destroy();
      this._handler = null;
    }
  }
}

2、编写鼠标事件

        1、鼠标采点事件

        2、鼠标移动事件

        3、鼠标右键结束事件

/**
   * 绘图
   */
  draw() {
    this._handler = new ScreenSpaceEventHandler(this._viewer.canvas);
    let positions = [];
    let flag = this;
    this._handler.setInputAction((event) => {
      console.log("左键单机事件");
    }, ScreenSpaceEventType.LEFT_CLICK);
    this._handler.setInputAction((event) => {
      console.log("鼠标移动事件");
    }, ScreenSpaceEventType.MOUSE_MOVE);
    this._handler.setInputAction((event) => {
      console.log("鼠标右键单机事件");
    }, ScreenSpaceEventType.RIGHT_CLICK);
  }

3、获取点位并渲染

        =>初始为空的数组

        =>点击后当为空时直接push,当有两个点时,先pop后push

        =>移动:当只有一个点时直接push,当点位数大于1的时候,先移除后push

        =>右键直接结束

/**
   * 绘图
   */
  draw() {
    this._handler = new ScreenSpaceEventHandler(this._viewer.canvas);
    let positions = [];
    let flag = this;
    this._handler.setInputAction((event) => {
      console.log("左键单机事件");
      let position = pickPosition(event.position, flag._viewer);
      if (position) {
        if (positions.length === 0) {
          positions.push(position);
          flag._primitive = new CustomPolygonPrimitive();
          this._viewer.scene.primitives.add(this._primitive);
        } else {
          let moveP = positions.pop();
          positions.push(position, moveP);
        }
        if (flag._primitive) {
          flag._primitive.updateProperty({
            positions: [...positions],
            complete: false,
          });
        }
      }
    }, ScreenSpaceEventType.LEFT_CLICK);
    this._handler.setInputAction((event) => {
      console.log("鼠标移动事件");
      let position = pickPosition(event.endPosition, flag._viewer);
      if (position) {
        if (positions.length === 1) {
          positions.push(position);
        } else if (positions.length > 1) {
          positions.pop();
          positions.push(position);
        }
        if (flag._primitive) {
          flag._primitive.updateProperty({
            positions: [...positions],
            complete: false,
          });
        }
      }
    }, ScreenSpaceEventType.MOUSE_MOVE);
    this._handler.setInputAction((event) => {
      console.log("鼠标右键单机事件");
      if (flag._primitive) {
        flag._primitive.updateProperty({
          positions: [...positions],
          complete: false,
        });
      }
      this._primitive = undefined;
      positions = [];
    }, ScreenSpaceEventType.RIGHT_CLICK);
  }

4、调用代码

let tool = new DrawPolygonTool(viewer);
tool.draw();

三、显示效果

四、全部代码

1、CustomPolygonPrimitive

import {
  Color,
  GeometryInstance,
  GroundPolylineGeometry,
  GroundPolylinePrimitive,
  Material,
  PolylineMaterialAppearance,
} from "cesium";

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

    this._dynamicPrimitive = undefined;
  }

  /**
   * 更新属性
   * @param options
   */
  updateProperty(options) {
    this._props = {
      ...this._props,
      ...options,
    };
    let positions = this._props.positions;
    let complete = this._props.complete;
    if (positions.length >= 2) {
      let dynamicPrimitive = this._dynamicPrimitive;
      if (dynamicPrimitive) {
        dynamicPrimitive.destroy();
        dynamicPrimitive = null;
        this._dynamicPrimitive = null;
      }
      let primitive = this.initPolygonPrimitive(positions);
      if (complete) {
        this._primitiveCollection.push(primitive);
      } else {
        this._dynamicPrimitive = primitive;
      }
    }
  }

  /**
   * 初始化渲染对象
   * @param positions
   * @return {module:cesium.GroundPolylinePrimitive}
   */
  initPolygonPrimitive(positions) {
    let instance = new GeometryInstance({
      geometry: new GroundPolylineGeometry({
        positions: positions,
        width: 4,
        loop: positions.length > 2,
      }),
    });
    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;
  }
}

2、DrawPolygonTool

import { Viewer, ScreenSpaceEventHandler, ScreenSpaceEventType } from "cesium";
import { pickPosition } from "@/components/MilitaryPlot/utils/PlotUtils";
import CustomPolygonPrimitive from "@/components/samples/CustomPolygonPrimitive";
export default class DrawPolygonTool {
  /**
   * 构造函数
   * @param {Viewer} viewer
   */
  constructor(viewer) {
    /**
     * 地球视图
     * @type {Viewer}
     * @private
     */
    this._viewer = viewer;
    /**
     * 线对象
     * @type {CustomPolygonPrimitive}
     * @private
     */
    this._primitive = undefined;
    /**
     * 事件
     * @type {ScreenSpaceEventHandler}
     * @private
     */
    this._handler = undefined;
  }

  /**
   * 绘图
   */
  draw() {
    this._handler = new ScreenSpaceEventHandler(this._viewer.canvas);
    let positions = [];
    let flag = this;
    this._handler.setInputAction((event) => {
      console.log("左键单机事件");
      let position = pickPosition(event.position, flag._viewer);
      if (position) {
        if (positions.length === 0) {
          positions.push(position);
          flag._primitive = new CustomPolygonPrimitive();
          this._viewer.scene.primitives.add(this._primitive);
        } else {
          let moveP = positions.pop();
          positions.push(position, moveP);
        }
        if (flag._primitive) {
          flag._primitive.updateProperty({
            positions: [...positions],
            complete: false,
          });
        }
      }
    }, ScreenSpaceEventType.LEFT_CLICK);
    this._handler.setInputAction((event) => {
      console.log("鼠标移动事件");
      let position = pickPosition(event.endPosition, flag._viewer);
      if (position) {
        if (positions.length === 1) {
          positions.push(position);
        } else if (positions.length > 1) {
          positions.pop();
          positions.push(position);
        }
        if (flag._primitive) {
          flag._primitive.updateProperty({
            positions: [...positions],
            complete: false,
          });
        }
      }
    }, ScreenSpaceEventType.MOUSE_MOVE);
    this._handler.setInputAction((event) => {
      console.log("鼠标右键单机事件");
      if (flag._primitive) {
        flag._primitive.updateProperty({
          positions: [...positions],
          complete: false,
        });
      }
      this._primitive = undefined;
      positions = [];
    }, ScreenSpaceEventType.RIGHT_CLICK);
  }
  /**
   * 销毁
   */
  destroy() {
    if (this._handler) {
      this._handler.isDestroyed() && this._handler.destroy();
      this._handler = null;
    }
  }
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

生活真难

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

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

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

打赏作者

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

抵扣说明:

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

余额充值