cesium与three结合使用
文章目录
- cesium与three结合使用
- 前言
- 一、Cesium是什么?
- 二、Three是什么?
- 三、怎么结合使用
- 三、我的实现
- 1.引入库
- 2.使用示例* 重点查看本代码
- 3. initCesium, //加载地图
- 4. initWebMapTileServiceCesium, //加载WebMapTile类型底图
- 5. initUrlTemplateCesium, //加载UrlTemplate类型底图
- 6. viewerCameraFlyToCesium, //飞跃视角
- 7. viewerCameraCesium, //切换视角
- 8. viewerFlyToCesium, //聚焦指定实体
- 9. eventLeftClickCesium, //鼠标左键
- 10. eventRightClickCesium, //鼠标右键
- 11. eventCenterClickCesium, //滚轮
- 12. eventMouseMoveCesium, //鼠标移入移出
- 13. addEntityBillboardCesium, //添加实体 点
- 14. addEntityPolygonCesium, //添加实体 多边形
- 15. addEntityLineCesium, //添加实体 线
- 16. addEntityWallCesium, //添加实体 围墙
- 17. addEntityPolygonHolesCesium, //添加实体 带洞多边形
- 18. getEntityByPosition, //根据二维坐标获取地图上的实体
- 19. addPrimitiveWarterCesium, //添加增加水流材质
- 20. addPrimitivesRainCesium, // 添加下雨
- 21. addPrimitivesSnowCesium, //添加下雪
- 22. addLayerModalCesium, //添加弹窗
- 23. removeLayerModalCesium, //删除弹窗
- 24. removeEntitiesCesium, //删除实体
- 25. removeImageryMapCesium, //删除地图其他底图对象
- 26. removePrimitivesCesium, //删除动态效果 如下雨 河流
- 27. hideShowEntitiesCesium, //显示或者隐藏实体对象
- 28. hideShowLayerModalCesium, //显示或者隐藏弹窗
- 29. GeoJsonDataSourceCesium, //获取genjson文件
- 30. GeoJsonLocaToPositionsCesium, //把本地genjson文件 整理为【经,纬度】
- 31. renderCesium, //渲染
- 32. initThree, //初始化3D场景
- 33. addSpriteMaterialThree, //增加精灵模型
- 34. addGLTFModelThree, //增加模型
- 35. renderCameraThreeCesium, //视角同步
- 36. 渲染
- 总结
前言
提示:已开源
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);
}
总结
欢迎各位大佬提出指导性意见