Cesium 自定义Primitive - 矩形

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

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、创作思路

        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;
  }
}

<think>好的,我现在需要帮助用户解决在Cesium中为primitive设置材质的问题。首先,我得回忆一下Cesium的基本概念,primitive和entity的区别。Primitive是更底层的图形对象,通常用于高性能需求,而entity则是更高级的抽象。用户提到的是primitive,所以应该使用Primitive API。 接下来,材质设置。用户可能已经看过引用[2],里面提到了使用PolylineDashMaterialProperty来设置虚线材质。不过那是针对Polyline的,而primitive可能需要不同的方法。我需要确认Cesiumprimitive如何关联材质。 查找Cesium文档,发现primitive的材质是通过MaterialProperty来定义的。例如,在创建Primitive时,可以通过appearance的material属性指定材质。比如,使用ColorMaterialProperty来设置颜色,或者更复杂的材质如PolylineGlowMaterialProperty。 然后,我需要考虑用户可能的应用场景。比如,用户可能想给一个多边形或者折线设置材质,或者自定义着色器。这时候需要选择正确的材质类型,比如PolylineMaterialProperty或者MaterialProperty.fromType()方法。 另外,注意用户提供的引用[2]中的代码使用了PolylineDashMaterialProperty,这可能用于PolylineGraphics的材质设置。但如果是primitive,可能需要使用对应的Appearance和MaterialProperty的组合。 接下来,我需要组织步骤。首先,创建primitive,比如一个多边形,然后定义其外观,指定材质属性。可能需要使用MaterialProperty的子类,或者通过fromType来创建。 比如,创建一个矩形primitive,并应用颜色材质: 1. 创建几何实例,定义几何形状和属性。 2. 创建外观对象,设置材质。 3. 将几何实例和外观传递给Primitive构造函数。 然后,给出代码示例,使用ColorMaterialProperty或者更复杂的材质,比如Checkerboard。 可能还需要提到自定义材质,使用自定义的GLSL着色器,但这是高级用法,用户可能需要先了解基础。 最后,确保代码语法正确,符合用户提供的LaTeX格式要求,行内公式用$...$,独立公式用$$...$$。同时生成相关问题,如如何动态改变材质、自定义材质的方法等。 总结步骤:创建几何体,定义材质属性,设置外观,添加到primitive。同时引用提供的参考中的方法,如设置虚线材质的方式,但调整为适用于primitive的情况。</think>在Cesium中为Primitive设置材质需要结合几何体(Geometry)和外观(Appearance)来实现。以下是具体步骤及示例代码: ### 一、基本材质设置 1. **创建几何体实例**:使用$GeometryInstance$定义图形基础数据 2. **配置外观对象**:通过$MaterialProperty$指定材质属性 3. **构建Primitive对象**:将几何体与外观组合 ```javascript // 创建矩形几何体 const rectangle = new Cesium.RectangleGeometry({ rectangle: Cesium.Rectangle.fromDegrees(-110.0, 20.0, -100.0, 30.0), vertexFormat: Cesium.MaterialAppearance.VERTEX_FORMAT }); // 设置颜色材质 const material = new Cesium.ColorMaterialProperty(Cesium.Color.RED.withAlpha(0.5)); // 创建Primitive对象 const primitive = viewer.scene.primitives.add(new Cesium.Primitive({ geometryInstances: new Cesium.GeometryInstance({ geometry: rectangle }), appearance: new Cesium.MaterialAppearance({ material: material, translucent: true }) })); ``` ### 二、特殊材质应用 使用预置材质类型时,可通过$fromType()$方法快速创建: ```javascript // 棋盘格材质示例 const checkerboardMaterial = new Cesium.CheckerboardMaterialProperty({ evenColor: Cesium.Color.WHITE, oddColor: Cesium.Color.BLACK, repeat: new Cesium.Cartesian2(10, 10) }); // 更新外观材质 primitive.appearance.material = checkerboardMaterial; ``` ### 三、动态材质控制 通过$Property$系统实现材质动画效果: ```javascript // 创建动态颜色 const colorProperty = new Cesium.TimeIntervalCollectionProperty(); colorProperty.intervals.addInterval( Cesium.TimeInterval.fromIso8601({ iso8601: '2023-01-01/2023-01-02', data: Cesium.Color.BLUE }) ); // 应用动态材质 primitive.appearance.material = new Cesium.ColorMaterialProperty(colorProperty); ```
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

生活真难

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

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

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

打赏作者

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

抵扣说明:

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

余额充值