【cesium与three结合使用】

cesium与three结合使用


文章目录


前言

提示:已开源 github-cesium-three

这两年做前端开发,积累了点经验。最近项目不多,领导就让我去学学Cesium和Three,说是以后做大屏展示会用到。就试着封装一些常用的api(实体对象,切换图源,降雨降雪,河流,动态绘图等)。欢迎各位提意见。

在这里插入图片描述
调用者可以根据需要自由添加或覆盖配置,而无需修改函数本身的代码:如实例化地图 otherConfigs

  const viewerConfig = {
    shouldAnimate: true,
   terrain: true,
  };
  const otherConfig = {
    timeline: false,
    animation: false
    ...其他配置
  };
 const viewer = initCesium('cesiumContainer', viewerConfig, otherConfig);

一、Cesium是什么?

Cesium是一个开源的3D地球渲染引擎,专注于地球科学和地理空间数据可视化。它利用WebGL技术,在网页中呈现高精度的三维地球、地图和地理数据,如地形、影像、3D模型等,并支持动态数据可视化和多种数据格式。Cesium特别适合用于地理信息系统(GIS)应用程序、航空航天应用程序、虚拟现实(VR)和增强现实(AR)应用程序等需要地理空间数据可视化和交互的场景。

二、Three是什么?

Three是一个通用的3D图形库,旨在简化在网页上创建和显示3D图形的过程。它提供了一套高级API,隐藏了WebGL的复杂性,使得开发者可以专注于创意和逻辑实现,而不是底层的图形渲染细节。Three.js适合创建各种类型的3D场景,从游戏、产品展示到艺术作品等,不特定于地理空间应用。

三、怎么结合使用

实现思路:以 Cesium 为主体,并通过双画布(或称为双渲染上下文)同步视角,通过 Three加载模型。
cesium官方文档

1.双画布

准备画布容器

 <div id="cesium-container"></div>
 
 #cesium-container > canvas {
  position: absolute;
  top: 0;
  left: 0;
  /* 设置鼠标事件穿透 */
  pointer-events: none;
}

初始化cesium

function initCesium(){
  viewer = new Cesium.Viewer("cesium-container",{ ...其他配置 });
}

初始化three

function initThree(){
    var fov = 45;
    var width = window.innerWidth;
    var height = window.innerHeight;
    var aspect = width / height;
    var near = 1;
    var far = 10*1000*1000; // needs to be far to support Cesium's world-scale rendering
    var ThreeContainer= document.getElementById(“cesium-container”);
    
    three.scene = new THREE.Scene();
    three.camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
    three.renderer = new THREE.WebGLRenderer({alpha: true});
    ThreeContainer.appendChild(three.renderer.domElement);  
}

添加模型

/**
 * 添加GLTF模型
 * @param {object} three - 3d场景
 * @param {object} config - 加载模型配置项
 * @param {string} config.url - 模型地址
 * @param {object} config.set - {x,z,y} 模型xzy轴的缩放
 * @param {object} config.position -  {x,z,y} 模型xyz轴的移动
 * @param {object} config.rotation -  {x,z,y} 模型xyz轴的旋转
 * @param {object} config.data -  {name,id,} 模型其他信息
 * @param {array} minWGS - 经纬度
 * @param {array} maxWGS - 经纬度
 * @returns {object}  _3DOB Promise
 */
function addGLTFModelThree(three, config) {
  const {
    url,
    set,
    position,
    rotation,
    data,
    minWGS = null,
    maxWGS = null,
  } = config;
  return new Promise((rs) => {
    // 外部模型加载
    const loader = new GLTFLoader();
    loader.load(url, (gltf) => {
      const { x: sX, y: sY, z: sZ } = set;
      const { x: pX, y: pY, z: pZ } = position;
      const { x: rX, y: rY, z: rZ } = rotation;
      const modelss = gltf.scene;

      modelss.name = "modalSelf"; //模型本身  因为点击事件获取模型是获取物体 可能只获取到平
      modelss.data = data; //模型其他信息
      console.log(modelss, "加载到模型");
      modelss.scale.set(sX, sY, sZ); // 缩放相关参数 scale object to be visible at planet scale
      // z方向移动一段距离
      modelss.position.x = pX; //
      modelss.position.y = pY; //
      modelss.position.z = pZ; //

      modelss.rotation.x = rX; //
      modelss.rotation.y = rY; //
      modelss.rotation.z = rZ; //
      //   分组
      let dodecahedronMeshYup = new THREE.Group();
      dodecahedronMeshYup.add(modelss);
      // 添加场景当中
      three.scene.add(dodecahedronMeshYup); // don’t forget to add it to the Three.js scene manually
      let _3DOB = {
        threeMesh: dodecahedronMeshYup,
        minWGS84: minWGS, //可以配置经纬度
        maxWGS84: maxWGS, // 可以配置经纬度
      };
      rs({
        data: _3DOB,
        animations: [...gltf.animations],
      });
    });
  });
}


addGLTFModelThree(three, {
        url: monkey,
        set: { x: 500, y: 500, z: 500 },
        position: { x: 0, y: 0, z: 100 },
        rotation: { x: Cesium.Math.PI / 2, y: 0, z: 0 },
        data: { name: "猴子", type: "猴子" },
        minWGS: [112.49906435282986, 28.245222057984655],
        maxWGS: [112.50194276815414, 28.249573397766703],
      })

2.视角同步

克隆 Three.js 的相机来与 Cesium 的相机保持同步,因此不需要为 Three.js 单独设置鼠标控制。由于 Three.js 的渲染画布(canvas)在 Cesium 的上方,确保用户交互不会影响到 Three.js 的画布,这可以通过给 Three.js 的渲染器添加 CSS 属性 pointer-events: none 来实现,这样用户点击或移动鼠标时就不会触发 Three.js 画布上的任何事件。

为了将 Three.js 中的对象正确地显示在 Cesium 的地球上,我们需要进行坐标转换。这主要包括将地理坐标(纬度/经度)转换为笛卡尔坐标系中的 XYZ 坐标。同时,我们还需要设置正确的上向量(up vector),这通常是从地球表面某点指向天空的方向,以确保对象能够正确地指向远离地球中心。这个上向量可以通过将 WGS84 坐标系中的方向(如从左下角到左上角)转换为局部笛卡尔坐标系(如东-北-上或北-东-下)中的向量来得到。

function renderCameraThreeCesium(three, viewer, container, arr3DModal) {
  if (typeof container === "string") {
    container = document.getElementById(container);
  }
  let minWGS84 = [];
  let maxWGS84 = [];
  // register Three.js scene with Cesium
  // 镜头同步
  three.camera.fov = CesiumMath.toDegrees(viewer.camera.frustum.fovy); // ThreeJS FOV is vertical
  //three.camera.updateProjectionMatrix();
  let cartToVec = function (cart) {
    return new THREE.Vector3(cart.x, cart.y, cart.z);
  };
  // 将Three.js网格配置为相对于地球仪中心位置向上
  for (let id in arr3DModal) {
    minWGS84 = arr3DModal[id].minWGS84;
    maxWGS84 = arr3DModal[id].maxWGS84;
    // convert lat/long center position to Cartesian3
    let center = Cartesian3.fromDegrees(
      (minWGS84[0] + maxWGS84[0]) / 2,
      (minWGS84[1] + maxWGS84[1]) / 2
    );
    // get forward direction for orienting model
    let centerHigh = Cartesian3.fromDegrees(
      (minWGS84[0] + maxWGS84[0]) / 2,
      (minWGS84[1] + maxWGS84[1]) / 2,
      1
    );
    // use direction from bottom left to top left as up-vector
    let bottomLeft = cartToVec(
      Cartesian3.fromDegrees(minWGS84[0], minWGS84[1])
    );
    let topLeft = cartToVec(Cartesian3.fromDegrees(minWGS84[0], maxWGS84[1]));
    let latDir = new THREE.Vector3()
      .subVectors(bottomLeft, topLeft)
      .normalize();
    // configure entity position and orientation
    // 配置实体位置和方向
    arr3DModal[id].threeMesh.position.copy(center); // 控制更新后的模型位置
    // if(arr3DModal[id].myType) arr3DModal[id].threeMesh.position.y += 10.0;

    arr3DModal[id].threeMesh.lookAt(centerHigh.x, centerHigh.y, centerHigh.z);
    arr3DModal[id].threeMesh.up.copy(latDir);
  }
  // Clone Cesium Camera projection position so the
  // Three.js Object will appear to be at the same place as above the Cesium Globe
  // 克隆铯相机的投影位置,使Three.js对象看起来与铯地球仪上方的位置相同
  three.camera.matrixAutoUpdate = false;
  let cvm = viewer.camera.viewMatrix;
  let civm = viewer.camera.inverseViewMatrix;

  // 注意这里,经大神博客得知,three高版本这行代码需要放在 three.camera.matrixWorld 之前
  three.camera.lookAt(0, 0, 0);

  three.camera.matrixWorld.set(
    civm[0],
    civm[4],
    civm[8],
    civm[12],
    civm[1],
    civm[5],
    civm[9],
    civm[13],
    civm[2],
    civm[6],
    civm[10],
    civm[14],
    civm[3],
    civm[7],
    civm[11],
    civm[15]
  );

  three.camera.matrixWorldInverse.set(
    cvm[0],
    cvm[4],
    cvm[8],
    cvm[12],
    cvm[1],
    cvm[5],
    cvm[9],
    cvm[13],
    cvm[2],
    cvm[6],
    cvm[10],
    cvm[14],
    cvm[3],
    cvm[7],
    cvm[11],
    cvm[15]
  );

  // 设置three宽高
  let width = container.clientWidth;
  let height = container.clientHeight;
  let aspect = width / height;
  three.camera.aspect = aspect;
  three.camera.updateProjectionMatrix();
  three.renderer.setSize(width, height);
  three.renderer.clear();
  three.renderer.render(three.scene, three.camera);
}

function loop() {
  requestAnimationFrame(loop);
  renderCesium(viewer);
  renderCameraThreeCesium(three, viewer, "cesium-container", arr3DModal);
}

三、我的实现

1.引入库

https://github.com/mantoudebaba/cesium-three
npm install 
npm run dev

2.使用示例* 重点查看本代码

<!--
 * @Author: LXL
 * @Date: 2024-06-14 16:15:38
 * @LastEditTime: 2024-08-20 09:30:27
 * @Description: 示例
 * @FastButton: ctrl+win+i, ctrl+win+t
-->
<template>
  <div class="container-integrate">
    <div id="cesium-container"></div>
    <div class="list-btn">
      <button v-for="item in btnList" @click="item.fun()">
        {{ item.text }}
      </button>
      <br />
      <div style="color: #fff">绘图 注:左键开始,点击鼠标滚轮结束</div>

      <button v-for="item in drawList" @click="item.fun()">
        {{ item.text }}
      </button>
    </div>
    <div id="mapModal">
      经度:{{ LngLat.longitude }}, 纬度:{{ LngLat.latitude }}
      <button
        @click="
          () => {
            CT.hideShowLayerModalCesium(mapData.mapModal, false);
          }
        "
      >
        关闭
      </button>
    </div>
  </div>
</template>
<script setup>
import { onMounted, reactive } from "vue";
import * as Cesium from "cesium";
import * as CT from "@/utils/cesium-three.js";
import Draw from "@/utils/draw-cesium.js";
import fill from "@/assets/fill.png";
import wall from "@/assets/wall.png";
import rain from "@/assets/rain.png";
import snow from "@/assets/snow.png";
let viewer = null;
let three = null;
let arr3DModal = [];
let draw = null;
const LngLat = reactive({
  longitude: 0,
  latitude: 0,
});
const mapData = {
  GDImageryProvider: null, //地图 其他图源
  LeftHandler: null, //点击事件
  Billboard: null, //图形
  Polygon: null, //图形
  Line: null, //图形
  Wall: null, //图形
  PolygonHoles: null, //图形
  Rain: null, //降雨
  Snow: null, //降雪
  mapModal: null, //弹窗
};

const btnList = [
  {
    text: "切换视角",
    fun: () => {
      CT.viewerCameraCesium(viewer, {
        longitude: 112.77232203811953,
        latitude: 28.061197706159664,
      });
    },
  },
  {
    text: "飞跃视角",
    fun: () => {
      CT.viewerCameraFlyToCesium(viewer, {
        longitude: 112.77232203811953,
        latitude: 28.061197706159664,
        height: 1000,
      });
    },
  },
  {
    text: "加载高德地图",
    fun: () => {
      mapData.GDImageryProvider = CT.initUrlTemplateCesium(viewer, {
        url: "https://webst{s}.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&style=7",
      });
    },
  },
  {
    text: "删除高德地图",
    fun: () => {
      CT.removeImageryMapCesium(viewer, mapData.GDImageryProvider);
    },
  },
  {
    text: "左击查看经纬度",
    fun: () => {
      // eventLeftClickCesium,eventRightClickCesium,eventCenterClickCesium一样
      // eventMouseMoveCesium 移入移出,返回移入经纬度,二维坐标,移入经纬度 二维坐标
      mapData.LeftHandler = CT.eventLeftClickCesium(viewer, (e) => {
        LngLat.longitude = e.longitude;
        LngLat.latitude = e.latitude;

        mapData.mapModal = CT.addLayerModalCesium(viewer, {
          position: [e.longitude, e.latitude],
          offset: [0, 20],
          domId: "mapModal",
        });
        // alert(
        //   `经度:${e.longitude},纬度:${e.latitude}
        //   二维坐标:x-${e.position.x},y-${e.position.y}`
        // );
      });
    },
  },
  {
    text: "添加广告牌",
    fun: () => {
      mapData.Billboard = CT.addEntityBillboardCesium(
        viewer,
        { image: fill }, //广告牌配置
        { text: "我是广告牌" }, //文字配置
        {
          positions: [-94.2796076843326, 40.47465136950101],
          data: { name: "任意参数", age: "188" },
        } //实体对象配置
      );
      //   任意参数
      console.log(mapData.Billboard.data);
    },
  },
  {
    text: "添加多边形",
    fun: () => {
      mapData.Polygon = CT.addEntityPolygonCesium(viewer, {
        positions: [
          -104.44583395715667, 41.22017373826037, -95.76214386385325,
          41.8553937536503, -94.88829950200348, 35.88038223987908,
          -103.59556059849743, 35.34628124489838,
        ],
      });
    },
  },
  {
    text: "添加线",
    fun: () => {
      mapData.Line = CT.addEntityLineCesium(viewer, {
        positions: [
          -106.40886526265746, 37.67972275221243, -82.28169305307992,
          32.43268260385166, -99.77832896758429, 21.32940323740564,
          -85.92307008109772, 12.88555635151695,
        ],
      });
    },
  },
  {
    text: "添加围墙",
    fun: () => {
      mapData.Wall = CT.addEntityWallCesium(viewer, {
        wallImg: wall,
        positions: [
          -104.44583395715667, 41.22017373826037, -95.76214386385325,
          41.8553937536503, -94.88829950200348, 35.88038223987908,
          -103.59556059849743, 35.34628124489838,
        ],
        maximumHeights: 100000,
      });

      console.log(mapData.Wall);
    },
  },
  {
    text: "添加洞多边形",
    fun: () => {
      mapData.PolygonHoles = CT.addEntityPolygonHolesCesium(viewer, {
        material: Cesium.Color.DARKSLATEGRAY.withAlpha(0.8),
        hierarchyPositions: [
          -125.36713999731785, 43.94176698635193, -58.25864950050107,
          55.9704150622827, -55.596694287244475, 24.05842666657082,
          -107.72612752252512, 5.8703131629483165,
        ],
        holesPositions: [
          [
            -106.90106711666269, 41.670009664744704, -97.5850968239922,
            43.056927858600886, -96.45397355407029, 36.83247225217504,
          ],
        ],
      });
    },
  },
  {
    text: "清除图形",
    fun: () => {
      const entityData = [
        mapData.Billboard,
        mapData.Polygon,
        mapData.Line,
        mapData.Wall,
        mapData.PolygonHoles,
      ];
      // CT.removeEntitiesCesium(viewer,mapData.Billboard) //可以传单个  删除单个
      CT.removeEntitiesCesium(viewer, entityData); //也可以传数组 删除多个
      // CT.removeEntitiesCesium(viewer) //可以传空 删除所有
    },
  },
  {
    text: "隐藏图形",
    fun: () => {
      const entityData = [
        mapData.Billboard,
        mapData.Polygon,
        mapData.Line,
        mapData.Wall,
        mapData.PolygonHoles,
      ];
      // CT.hideShowEntitiesCesium(mapData.Billboard,false) //可以传单个  隐藏显示单个
      CT.hideShowEntitiesCesium(entityData, false); //也可以传数组隐藏显示多个
    },
  },
  {
    text: "显示图形",
    fun: () => {
      const entityData = [
        mapData.Billboard,
        mapData.Polygon,
        mapData.Line,
        mapData.Wall,
        mapData.PolygonHoles,
      ];
      // CT.hideShowEntitiesCesium(mapData.Billboard,true) //可以传单个  隐藏显示单个
      CT.hideShowEntitiesCesium(entityData, true); //也可以传数组 隐藏显示多个
    },
  },
  {
    text: "下雨",
    fun: () => {
      mapData.Rain = CT.addPrimitivesRainCesium(viewer, { image: rain });
    },
  },
  {
    text: "下雪",
    fun: () => {
      mapData.Snow = CT.addPrimitivesSnowCesium(viewer, { image: snow });
    },
  },
  {
    text: "清除雨/雪",
    fun: () => {
      CT.removePrimitivesCesium(viewer, [mapData.Snow, mapData.Rain]);
    },
  },
  {
    text: "加载模型",
    fun: () => {
      const monkey = new URL("@/assets/monkey.glb", import.meta.url).href;
      CT.addGLTFModelThree(three, {
        url: monkey,
        set: { x: 500, y: 500, z: 500 },
        position: { x: 0, y: 0, z: 100 },
        rotation: { x: Cesium.Math.PI / 2, y: 0, z: 0 },
        data: { name: "猴子", type: "猴子" },
        minWGS: [112.49906435282986, 28.245222057984655],
        maxWGS: [112.50194276815414, 28.249573397766703],
      }).then((res) => {
        arr3DModal.push(res.data);
        console.log("addGLTFModelThree", res);
        CT.viewerCameraCesium(viewer, {
          longitude: 112.49906435282986,
          latitude: 28.245222057984655,
          height: 5000,
        });
      });
    },
  },
];
const drawList = [
  {
    text: "开始绘图",
    fun: () => {
      draw = new Draw(viewer);
    },
  },
  {
    text: "点",
    fun: () => {
      draw.addEntity("point");
    },
  },
  {
    text: "线",
    fun: () => {
      draw.addEntity("line");
    },
  },
  {
    text: "多边形",
    fun: () => {
      draw.addEntity("polygon");
    },
  },
  {
    text: "圆",
    fun: () => {
      draw.addEntity("circle");
    },
  },
  {
    text: "矩形",
    fun: () => {
      draw.addEntity("rectangle");
    },
  },
  {
    text: "测距",
    fun: () => {
      draw.addEntity("range");
    },
  },
  {
    text: "面积",
    fun: () => {
      draw.addEntity("area");
    },
  },
  {
    text: "导出至控制台",
    fun: () => {
      draw.exportEntities();
    },
  },
  {
    text: "清空绘图",
    fun: () => {
      draw.removeAll();
    },
  },
];

// 加载地图
const initMap = () => {
  const viewerConfig = {
    shouldAnimate: true,
    terrain: false,
  };
  viewer = CT.initCesium("cesium-container", viewerConfig);
};

const init3DThree = () => {
  three = CT.initThree("cesium-container");
};

// 渲染
function loop() {
  requestAnimationFrame(loop);
  CT.renderCesium(viewer);
  CT.renderCameraThreeCesium(three, viewer, "cesium-container", arr3DModal);
}
onMounted(() => {
  initMap();
  init3DThree();
  loop();
});
</script>

<style>
* {
  margin: 0;
  padding: 0;
}

#cesium-container,
.container-integrate {
  position: fixed;
  top: 0px;
  width: 100vw;
  height: 100vh;
  overflow: hidden;
}
#cesium-container > canvas {
  position: absolute;
  top: 0;
  left: 0;
  /* 设置鼠标事件穿透 */
  pointer-events: none;
}
.list-btn {
  position: fixed;
  z-index: 99999999;
}
</style>

3. initCesium, //加载地图

// 加载地图
const initMap = () => {
  const viewerConfig = {
    shouldAnimate: true,
    terrain: false,
  };
  viewer = initCesium("cesium-container", viewerConfig,{Viewer其他配置});
};

4. initWebMapTileServiceCesium, //加载WebMapTile类型底图

 initWebMapTileServiceCesium(viewer, {
    url: ",
    layer: "",
    maximumLevel: 18,
  },{WebMapTileServiceImageryProvider其他配置});

5. initUrlTemplateCesium, //加载UrlTemplate类型底图

CT.initUrlTemplateCesium(viewer, {
        url: "",
      },{UrlTemplateImageryProvider其他配置});

6. viewerCameraFlyToCesium, //飞跃视角

 CT.viewerCameraFlyToCesium(viewer, {
        longitude: 11.11,
        latitude: 11.11,
        height: 1000,
      },{flyTo其他配置});

7. viewerCameraCesium, //切换视角

 CT.viewerCameraCesium(viewer, {
        longitude: 111.11,
        latitude: 111.11,
      },{setView其他配置});

8. viewerFlyToCesium, //聚焦指定实体

viewerFlyToCesium(viewer, Point)

9. eventLeftClickCesium, //鼠标左键

eventLeftClickCesium(viewer, (e) => {
        alert(
          `经度:${e.longitude},纬度:${e.latitude}
          二维坐标:x-${e.position.x},y-${e.position.y}`
         );
      });

10. eventRightClickCesium, //鼠标右键

eventRightClickCesium(viewer, (e) => {
        alert(
          `经度:${e.longitude},纬度:${e.latitude}
          二维坐标:x-${e.position.x},y-${e.position.y}`
         );
      });

11. eventCenterClickCesium, //滚轮

eventCenterClickCesium(viewer, (e) => {
        alert(
          `经度:${e.longitude},纬度:${e.latitude}
          二维坐标:x-${e.position.x},y-${e.position.y}`
         );
      });

12. eventMouseMoveCesium, //鼠标移入移出

eventMouseMoveCesium(viewer, (e) => {
  e.startLongitude;
 e.startLongitude;
 e.startPosition.x;
 e.startPosition.y;
  e.endLongitude;
  e.endLatitude;
  e.endPosition.x;
  e.endPosition.y;
      });

13. addEntityBillboardCesium, //添加实体 点

addEntity支持entities所有配置项 规则如下
所有函数都有entityConfig 选填。
function addEntityBillboardCesium(viewer,billboardConfig,labelConfig,entityConfig = {})
function addEntityPolygonCesium(viewer, polygonConfig, entityConfig = {})
function addEntityLineCesium(viewer, polylineConfig, entityConfig = {})

billboardConfig : { image: “图片地址”,billboardOtherConfig:{billboard其他配置}}, //广告牌配置
labelConfig:{ text: “我是广告牌” ,labelOtherConfig:{label其他配置}}, //文字配置
polygonConfig:{positions: [ 经度,纬度,经度,纬度,经度,纬度],polygonOtherConfig:{polygon配置项}}
polylineConfig:{positions: [ 经度,纬度,经度,纬度,经度,纬度],polylineOtherConfig:{polyline配置项}}

entityConfig :{ data: { name: “任意参数”, age: “188” },entitiesOtherConfig:{entities其他配置项}}
源码示例

/**
 * 添加一个包含图标和标签的广告牌。
 * 
 * @param {Cesium.Viewer} viewer - Cesium Viewer 实例
 * @param {Object} billboardConfig - 图标配置对象。
 * @param {string} [billboardConfig.image=null] - 图标的图片 URL 或者路径。
 * @param {number} [billboardConfig.scale=1] - 图标的缩放比例。
 * @param {number[]} [billboardConfig.pixelOffset=[0, 0]] - 图标的像素偏移量 [x, y]。
 * @param {number[]} [billboardConfig.distanceDisplayCondition=[0, 999999999]] - 图标的显示距离条件 [最小距离, 最大距离]。
 * @param {Object} [billboardConfig.billboardOtherConfig={}] - 其他图标相关的配置。
 * 
 * @param {Object} labelConfig - 标签配置对象。
 * @param {string} [labelConfig.text=null] - 标签的文本内容。
 * @param {boolean} [labelConfig.show=Boolean(text)] - 标签是否显示。
 * @param {number} [labelConfig.scale=1] - 标签的缩放比例。
 * @param {string} [labelConfig.fillColor="RED"] - 标签文本的填充颜色(Cesium.Color 的有效颜色名)。
 * @param {string} [labelConfig.backgroundColor="BLUE"] - 标签背景色(Cesium.Color 的有效颜色名)。
 * @param {number[]} [labelConfig.pixelOffset=[0, 0]] - 标签的像素偏移量 [x, y]。
 * @param {number[]} [labelConfig.distanceDisplayCondition=[0, 999999999]] - 标签的显示距离条件 [最小距离, 最大距离]。
 * @param {Object} [labelConfig.labelOtherConfig={}] - 其他标签相关的配置。
 * 
 * @param {Object} entityConfig - 实体配置对象。
 * @param {string} [entityConfig.name=null] - 实体的名称。
 * @param {Object} [entityConfig.data={}] - 实体的附加数据。
 * @param {number[]} [entityConfig.positions=null] - 实体的位置坐标 [经度, 纬度]。必须有至少两个值。
 * @param {Object} [entityConfig.entitiesOtherConfig={}] - 其他实体相关的配置。
 * 
 * @returns {Cesium.Entity} 返回创建的 Cesium 实体对象。
 * @see {@link https://cesium.com/learn/cesiumjs/ref-doc/Entity.html?classFilter=Entity|Cesium Entity 文档}
 
 * 
 * @throws {Error} 如果 positions 不存在或者长度小于 2,将抛出错误。
 * 
 * @example
 * addEntityPointCesium(
 *   viewer,
 *   {
 *     image: 'image.png',
 *     scale: 1.5,
 *     pixelOffset: [10, 10],
 *     distanceDisplayCondition: [100, 1000],
 *     billboardOtherConfig: { ... }
 *   },
 *   {
 *     text: 'Sample Label',
 *     show: false,
 *     scale: 1.2,
 *     fillColor: 'WHITE',
 *     backgroundColor: 'BLACK',
 *     pixelOffset: [5, 5],
 *     distanceDisplayCondition: [50, 500],
 *     labelOtherConfig: { ... }
 *   },
 *   {
 *     name: 'Sample Entity',
 *     data: { someData: 'value' },
 *     positions: [120.0, 30.0],
 *     entitiesOtherConfig: { ... }
 *   }
 * );
 * 
 */
function addEntityBillboardCesium(
  viewer,
  billboardConfig,
  labelConfig,
  entityConfig = {}
) {
  // 常用配置
  const {
    image = null,
    scale: billboardScale = 1,
    pixelOffset = [0, 0],
    distanceDisplayCondition = [0, 999999999],
    billboardOtherConfig, //不常用配置
  } = billboardConfig;
  // 常用配置
  const {
    name = null,
    data = {},
    positions = null, // [经度,纬度]
    entitiesOtherConfig, //不常用配置
  } = entityConfig;
  // 常用配置
  const {
    text = null,
    show = Boolean(text),
    scale: labelScale = 1,
    fillColor = "WHITE",
    backgroundColor = "BLUE",
    pixelOffset: labelPixelOffset = [0, 0],
    distanceDisplayCondition: labeldistanceDisplayCondition = [0, 999999999],
    labelOtherConfig, //不常用配置
  } = labelConfig;

  if (!positions || positions.length < 1) {
    throw new Error("必须输入经纬度");
  }
  if (typeof positions[0] == "string" || typeof positions[1] == "string") {
    positions[0] = Number(positions[0]);
    positions[1] = Number(positions[1]);
  }
  // 实体
  const entityData = viewer.entities.add({
    name,
    data,
    position: Cartesian3.fromDegrees(positions[0], positions[1]),
    billboard: {
      image,
      heightReference: HeightReference.CLAMP_TO_GROUND,
      scale: billboardScale,
      // 平面 x,y的偏移
      pixelOffset: new Cartesian2(pixelOffset[0], pixelOffset[1]),
      // 在高度多少以内显示  最小-最大
      distanceDisplayCondition: new DistanceDisplayCondition(
        distanceDisplayCondition[0],
        distanceDisplayCondition[1]
      ),
      ...billboardOtherConfig,
    },
    label: {
      show,
      text,
      scale: labelScale,
      heightReference: HeightReference.CLAMP_TO_GROUND,
      fillColor: Color[fillColor],
      showBackground: Boolean(backgroundColor),
      backgroundColor: Color[backgroundColor],
      // 平面 x,y的偏移
      pixelOffset: new Cartesian2(labelPixelOffset[0], labelPixelOffset[1]),
      // 在高度多少以内显示  最小-最大
      distanceDisplayCondition: new DistanceDisplayCondition(
        labeldistanceDisplayCondition[0],
        labeldistanceDisplayCondition[1]
      ),
      ...labelOtherConfig,
    },
    ...entitiesOtherConfig,
  });

  return entityData;
}
addEntityBillboardCesium(
        viewer,
        { image: "图片地址",billboardOtherConfig:{billboard其他配置}}, //广告牌配置
        { text: "我是广告牌" ,labelOtherConfig:{label其他配置}}, //文字配置
        {
          positions: [经度, 纬度],
          data: { name: "任意参数", age: "188" },
          entitiesOtherConfig:{entities其他配置项}
        } //实体对象配置
      );

14. addEntityPolygonCesium, //添加实体 多边形

addEntityPolygonCesium(viewer, {positions: [ 经度,纬度,经度,纬度,经度,纬度]});

15. addEntityLineCesium, //添加实体 线


addEntityLineCesium(viewer, {positions: [经度,纬度,经度,纬度,经度,纬度]});

16. addEntityWallCesium, //添加实体 围墙

addEntityWallCesium(viewer, {
        wallImg: "图片",
        positions: [经度,纬度,经度,纬度,经度,纬度],
       });

17. addEntityPolygonHolesCesium, //添加实体 带洞多边形

addEntityPolygonHolesCesium(viewer, {
        material: Cesium.Color.DARKSLATEGRAY.withAlpha(0.8),
        hierarchyPositions: [
         经度,纬度,经度,纬度,经度,纬度
        ],
        holesPositions: [
          [
           经度,纬度,经度,纬度,经度,纬度
          ],
           [
           经度,纬度,经度,纬度,经度,纬度
          ],
        ],
      });

18. getEntityByPosition, //根据二维坐标获取地图上的实体

   eventLeftClickCesium(viewer, (e) => {
   		const entity = getEntityByPosition(viewer,e.position);
   });

19. addPrimitiveWarterCesium, //添加增加水流材质

/**
 * 增加水流材质
 * @param {Viewer} viewer  - 视图对象
 * @param {Object} config - 配置对象,用于定义水流材质的属性。
 * @param {Array<number>} config.polygonPosition - 多边形顶点的经纬度数组,格式为 [经度1, 纬度1, 经度2, 纬度2, ...]。
 * @param {Color} [config.uniformsBaseWaterColor=new Color(151 / 255.0, 201 / 255.0, 185 / 255.0, 0.8)] - 水的基础颜色。
 * @param {string} config.uniformsNormalMap - 水流的法线贴图。
 * @param {number} [config.uniformsFrequency=500.0] - 水流的频率。
 * @param {number} [config.uniformsAnimationSpeed=0.01] - 水流的动画速度。
 * @param {number} [config.uniformsAmplitude=10.0] - 水流的振幅。
 * @param {Object} [config.uniformsOtherConfig] - 其他自定义的 uniform 配置。
 * @returns {Primitive} - 返回一个包含指定配置的 `Primitive` 对象。
 * @see {@link https://cesium.com/learn/cesiumjs/ref-doc/Material.html?classFilter=Material|Cesium 材质 文档}
 */
function addPrimitiveWarterCesium(viewer, config){代码}
使用
addPrimitiveWarterCesium(viewer,{polygonPosition:[ 经度,纬度,经度,纬度,经度,纬度],uniformsNormalMap:"图片"})

20. addPrimitivesRainCesium, // 添加下雨

addPrimitivesRainCesium(viewer, { image: "图片",size:1});

21. addPrimitivesSnowCesium, //添加下雪

addPrimitivesSnowCesium(viewer, { image: "图片",size:1});

22. addLayerModalCesium, //添加弹窗

const LayerModal = addLayerModalCesium(viewer, {
          position: [longitude, latitude],
          offset: [0, 20],
          domId: "mapModal",
});

23. removeLayerModalCesium, //删除弹窗

LayerModal 由 addLayerModalCesium()返回

removeLayerModalCesium(LayerModal );//可以传单个  删除单个
removeLayerModalCesium([LayerModal1,LayerModal2]); //也可以传数组 删除多个

24. removeEntitiesCesium, //删除实体

entity 由 addEntityxxx()返回


removeEntitiesCesium(viewer,entity) //可以传单个  删除单个
removeEntitiesCesium(viewer, [entity1,entity2,entity3]); //也可以传数组 删除多个
removeEntitiesCesium(viewer) //可以传空 删除所有

25. removeImageryMapCesium, //删除地图其他底图对象

ImageryProvider由 initWebMapTileServiceCesium(), initUrlTemplateCesium(),返回

removeImageryMapCesium(viewer, ImageryProvider); //可以传单个  删除单个
removeImageryMapCesium(viewer, [ImageryProvider1,ImageryProvider2]);//也可以传数组 删除多个
removeImageryMapCesium(viewer);//可以传空 删除所有

26. removePrimitivesCesium, //删除动态效果 如下雨 河流

primitive 由 addPrimitivexxx()返回

removePrimitivesCesium(viewer,primitive); //可以传单个  删除单个
removePrimitivesCesium(viewer,[primitive1,primitive2,primitive3]);//也可以传数组 删除多个
removePrimitivesCesium(viewer);//可以传空 删除所有

27. hideShowEntitiesCesium, //显示或者隐藏实体对象

entity 由 addEntityxxx()返回

hideShowEntitiesCesium([entity1,entity2,entity3], false); //数组隐藏显示多个  通过第二个参数显示隐藏
hideShowEntitiesCesium(entity, true); //可以传单个

28. hideShowLayerModalCesium, //显示或者隐藏弹窗

LayerModal 由 addLayerModalCesium()返回
hideShowLayerModalCesium([LayerModal1 ,LayerModal2 ,LayerModal3 ], false); //数组隐藏显示多个  通过第二个参数显示隐藏
hideShowLayerModalCesium(LayerModal, true); //可以传单个

29. GeoJsonDataSourceCesium, //获取genjson文件

GeoJsonDataSourceCesium("genjson",{ GeoJsonDataSource.load:其他配置})

30. GeoJsonLocaToPositionsCesium, //把本地genjson文件 整理为【经,纬度】

GeoJsonLocaToPositionsCesium("genjson")

31. renderCesium, //渲染

renderCesium(viewer)

32. initThree, //初始化3D场景

initThree("domID");

33. addSpriteMaterialThree, //增加精灵模型

忘记写了

34. addGLTFModelThree, //增加模型

      const monkey = new URL("@/assets/monkey.glb", import.meta.url).href;
  addGLTFModelThree(three, {
        url: monkey,
        set: { x: 500, y: 500, z: 500 },
        position: { x: 0, y: 0, z: 100 },
        rotation: { x: Cesium.Math.PI / 2, y: 0, z: 0 },
        data: { name: "猴子", type: "猴子" },
        minWGS: [经度, 纬度],
        maxWGS: [经度, 纬度],
      }).then((res) => {
       arr3DModal.push(res.data);
       viewerCameraCesium(viewer, {
          longitude: 经度 ,
          latitude: 纬度,
          height: 5000,
        });
      });

35. renderCameraThreeCesium, //视角同步

renderCameraThreeCesium(three, viewer, "domID", arr3DModal);

36. 渲染

// 渲染
function loop() {
  requestAnimationFrame(loop);
  renderCesium(viewer);
  renderCameraThreeCesium(three, viewer, "domID", arr3DModal);
}

总结

欢迎各位大佬提出指导性意见

  • 15
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值