下面是通过前端 VUE 框架加载 Cesium 3D 模型(3dtiles)并计算 3dtiles 面积的参考代码:
首先在 Vue 组件中引入 Cesium 库和相关组件,需要使用 npm install cesium --save
命令来安装 Cesium 包。然后在组件中开始编写加载 3dtiles 和计算面积的逻辑:
<template>
<div class="cesium-container">
<div
ref="cesiumContainer"
class="cesium-viewer full"
id="cesiumContainer"
></div>
<div>模型面积:{{area}}㎡</div>
</div>
</template>
<script>
import * as Cesium from "cesium/Cesium";
import "cesium/Widgets/widgets.css";
export default {
name: "CesiumDemo",
data() {
return {
viewer: null,
modelViewer: null,
tileset: null,
area: 0,
};
},
mounted() {
this.initCesium();
},
methods: {
initCesium() {
const self = this;
// 创建地球场景
const viewer = new Cesium.Viewer("cesiumContainer", {});
self.viewer = viewer;
Cesium.Ion.defaultAccessToken =
"your_token_here"; // 如果需要访问 Cesium Ion 资源则需要填写 token
// 加载 3dtiles 模型
let tileset = new Cesium.Cesium3DTileset({
url: "/static/tileset.json",
});
tileset.readyPromise
.then(function (tileset) {
self.tileset = tileset;
viewer.scene.primitives.add(tileset);
})
.otherwise(function (error) {
console.log(error);
reject();
});
// 计算 3dtiles 面积
viewer.camera.changed.addEventListener(() => {
let tilesToProcess = [];
getTilesInitial(delta + cameraHeight, tilesToProcess, self.tileset.root);
for (let i = 0; i < tilesToProcess.length; ++i) {
calculateTileArea(tilesToProcess[i], projections)
}
let tempArea = 0;
for (const obj in projections) {
tempArea += projections[obj];
}
const area = Math.abs(tempArea).toFixed(2); // 保留两位小数
if (self.area !== area && !isNaN(area)) {
self.area = area;
}
})
},
},
};
/**
* 获取根节点下所有细分瓦片,放入数组中
* @param {*} currentDelta 当前维度
* @param {*} tilesToProcess 存储的所有瓦片组成的数组
* @param {*} currentNode 瓦片对象
*/
function getTilesInitial(currentDelta, tilesToProcess, currentNode) {
if (!currentNode.content || !currentNode.allTilesLoaded) {
return;
}
let refinedTiles = Array.from(currentNode.children);
while (refinedTiles.length > 0) {
let thisTile = refinedTiles.pop();
if (thisTile.imageryLayers) {
thisTile.imageryLayers = undefined;
thisTile.readyImageryLayersPromise = undefined;
thisTile.readyPromise = undefined;
}
if ((thisTile.refine === Cesium.Cesium3DTileRefine.NONE && !(thisTile instanceof Cesium.Cesium3DTilePointCloud)) ||
(thisTile.refine === Cesium.Cesium3DTileRefine.ADD || thisTile.refine === Cesium.Cesium3DTileRefine.REPLACE)) {
let distance = currentDelta / thisTile._geometricError;
let tileDistance = Math.sqrt(Cesium.Cartesian3.magnitudeSquared(thisTile.boundingSphere.center) + thisTile.state.renderedBB) - (Cesium.Ellipsoid.WGS84.maximumRadius * 2.0);
// 缩放系数
const scaleCoefitient = (tileDistance / distance) > 1 ? (tileDistance / distance) : 1;
var boundingBox = new Cesium.BoundingRectangle();
boundingBox.minimum.x = 0;
boundingBox.minimum.y = 0;
boundingBox.maximum.x = 256 / scaleCoefitient;
boundingBox.maximum.y = 256 / scaleCoefitient;
tilesToProcess.push({
"boundingBox": boundingBox,
"content": thisTile.content
});
} else {
refinedTiles.push.apply(refinedTiles, Array.from(thisTile.children));
}
}
}
// 计算瓦片面积
function calculateTileArea(tileInfo, projections) {
const boxXLength = tileInfo.boundingBox.width;
const tileHeight = tileInfo.boundingBox.height;
let arrayBuffer = tileInfo.content.positions;
tileInfo.content._batchTable.properties.areas.values.length = 0;
while (arrayBuffer && arrayBuffer.length > 0) {
const positionsLength = readPositionsLength(arrayBuffer);
if (!positionsLength) {
break;
}
const positions = readPositions(arrayBuffer, positionsLength);
if (!positions) {
break;
}
for (let i = 0; i < positionsLength; ++i) {
positions[i].z += tileHeight;
}
let area = calculateEllipsoidRegionArea(positions);
// Project a position onto the map and creates a plane in WGS84 normal space.
const centerPosition = calculateCenterPosition(positions);
const carto = Cesium.Cartographic.fromCartesian(centerPosition);
const n = calculateNormal(carto);
projections[tileInfo.content.url] += area * (boxXLength / 256.0) * Math.sqrt(1 + n.z * n.z);
}
}
以上代码仅供参考,具体实现会根据业务需求而有所不同。