learning_cesium/clipping-3dtiles.html

511 lines
18 KiB
HTML
Raw Normal View History

2024-03-19 18:06:25 +08:00
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Use correct character set. -->
<meta charset="utf-8" />
<!-- Tell IE to use the latest, best version. -->
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<!-- Make the application on mobile take up the full browser screen and disable user scaling. -->
<meta
name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"
/>
<title>Learning Cesium!</title>
<script src="./Build/Cesium/Cesium.js"></script>
<style>
@import url(./Build/Cesium/Widgets/widgets.css);
html,
body,
#app,
#cesiumContainer {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
#geologyClipPlanDiv td {
padding: 4px 2px;
}
.closerGeologyClipPlan {
text-decoration: none;
position: absolute;
top: 20px;
right: 10px;
z-index: 20;
}
.closerGeologyClipPlan:after {
content: "\e60b";
font-family: "iconfont";
font-size: 22px;
color: rgba(gray, 0.8);
}
#geologyClipPlanDiv {
position: absolute;
top: 10px;
color: rgba(29, 164, 220, 0.9);
background: rgba(34, 69, 91, 0.7);
border-radius: 6px;
padding: 10px;
}
#geologyClipPlanDiv .closerGeologyClipPlan {
top: 1vh;
right: 0.6vw;
cursor: pointer;
}
</style>
<!-- 引入样式 -->
<link rel="stylesheet" href="./js/elementui/index.css" />
<!-- import Vue before Element -->
<script src="./js/vue2710.js"></script>
<!-- import JavaScript -->
<script src="./js/elementui/index.js"></script>
<script src="./js/turf.min.js"></script>
</head>
<body>
<div id="app">
<div id="cesiumContainer"></div>
<div id="geologyClipPlanDiv" v-if="geologyClipPlanIsShow">
<table style="text-align: right">
<tr>
<td colspan="2" style="text-align: left">
<span style="font-size: 18px; font-weight: 600"
>模型裁剪分析</span
>
<div
class="closerGeologyClipPlan"
@click="handCloserGeologyClipPlan"
></div>
</td>
</tr>
<tr>
<td colspan="2">
<div
style="
height: 4px;
background-color: rgba(29, 164, 220, 0.6);
margin: 4px;
"
></div>
</td>
</tr>
<tr>
<td>裁剪类型:</td>
<td>
<el-radio v-model="modelType" label="0">外部裁剪</el-radio>
<el-radio v-model="modelType" label="1">内部裁剪</el-radio>
</td>
</tr>
<tr>
<td colspan="2">
<el-button
size="mini"
:disabled="isDrawGeologyClipPlan"
@click="drawGeologyClipPlan"
>绘制裁剪范围</el-button
>
<el-button size="mini" @click="clearGeologyClipPlan"
>清除</el-button
>
</td>
</tr>
</table>
</div>
</div>
<script>
Cesium.Ion.defaultAccessToken =
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI5ZjRjNTZkNC01NDYxLTRhMjQtOGEwZC1kZjA3YzQ5YTJlZDkiLCJpZCI6MjYwODQsInNjb3BlcyI6WyJhc3IiLCJnYyJdLCJpYXQiOjE1ODcxOTMwODN9.prGsSKyAW_9Ow5zHYPhbm3LsQL-ApQw5-5PNJkDaHi8";
var geologyClipPlanObj = null;
var handlerGeologyClipPlan = null;
var floatingPointList = [];
var activeShapePoints = [];
var floatingPoint = undefined;
var activeShape = undefined;
var my3dtiles;
var drawList = [];
var inverseTransform = undefined;
var TilesetsList = [];
new Vue({
el: "#app",
data: {
geologyClipPlanIsShow: true,
isDrawGeologyClipPlan: false,
modelType: "0", // 开挖深度
},
methods: {
initViewer() {
var viewer = new Cesium.Viewer("cesiumContainer", {
geocoder: false, //位置查找
homeButton: false, //视图返回初始位置
sceneModePicker: false, //视角选择器
// baseLayerPicker:false,//底图选择器
navigationHelpButton: false, //导航帮助按钮
animation: false, //动画控制器
// creditContainer:"credit",//版权显示
timeline: false, //时间线
fullscreenButton: false, //全屏控件
vrButton: false,
infoBox: false,
selectionIndicator: false,
});
window.viewer = viewer;
this.addTiles();
},
addTiles() {
var tileset = new Cesium.Cesium3DTileset({
url: "./SampleData/cesiumlab/tileset.json",
dynamicScreenSpaceError: true,
dynamicScreenSpaceErrorDensity: 0.00278,
dynamicScreenSpaceErrorFactor: 4.0,
dynamicScreenSpaceErrorHeightFalloff: 0.25,
});
viewer.scene.primitives.add(tileset);
viewer.zoomTo(tileset);
tileset.readyPromise.then((palaceTileset) => {
this.my3dtiles = palaceTileset;
this.setTilesetHeightAndOffset(palaceTileset, -40);
});
},
setTilesetHeightAndOffset(tileset, height, x, y) {
x = x ? x : 0;
y = y ? y : 0;
let center;
if (tileset.boundingSphere) {
// 3dtiles
center = tileset.boundingSphere.center;
} else if (
tileset._boundingSpheres &&
tileset._boundingSpheres.length > 0
) {
// Primitive
center = tileset._boundingSpheres[0].center;
}
const cartographic = Cesium.Cartographic.fromCartesian(center);
const surface = Cesium.Cartesian3.fromRadians(
cartographic.longitude,
cartographic.latitude,
0.0
);
const offset = Cesium.Cartesian3.fromRadians(
cartographic.longitude + x,
cartographic.latitude + y,
height
);
const translation = Cesium.Cartesian3.subtract(
offset,
surface,
new Cesium.Cartesian3()
);
const modelMaxtrix = Cesium.Matrix4.fromTranslation(translation);
tileset.modelMatrix = modelMaxtrix;
},
openGeologyClipPlan() {
this.geologyClipPlanIsShow = true;
const pTileset = window.viewer.scene.primitives.add(
new Cesium.Cesium3DTileset({
url: "http://localhost/models/3dModels/dbjz/tileset.json",
maximumScreenSpaceError: 16, // 最大的屏幕空间误差
})
);
pTileset.readyPromise.then((palaceTileset) => {
my3dtiles = palaceTileset;
});
},
handCloserGeologyClipPlan() {
this.geologyClipPlanIsShow = false;
this.clearGeologyClipPlan();
},
drawGeologyClipPlan() {
this.clearGeologyClipPlan();
this.isDrawGeologyClipPlan = true;
inverseTransform = this.getInverseTransform(this.my3dtiles);
window.viewer._container.style.cursor = "pointer";
// 取消双击事件-追踪该位置
window.viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(
Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK
);
handlerGeologyClipPlan = new Cesium.ScreenSpaceEventHandler(
window.viewer.scene.canvas
);
handlerGeologyClipPlan.setInputAction((event) => {
if (
!this.my3dtiles.clippingPlanes ||
!this.my3dtiles.clippingPlanes._planes.length
) {
const pick = window.viewer.scene.pickPosition(event.position);
const pickWGS = this.cart3ToWGS(pick);
const pickModel = window.viewer.scene.pick(event.position);
if (pickModel) {
drawList.push(pickWGS);
if (activeShapePoints.length === 0) {
floatingPoint = this.createPoint(pick);
floatingPointList.push(floatingPoint);
activeShapePoints.push(pick);
var dynamicPositions = new Cesium.CallbackProperty(
function () {
return new Cesium.PolygonHierarchy(activeShapePoints);
},
false
);
activeShape = this.drawShape(dynamicPositions);
}
activeShapePoints.push(pick);
floatingPointList.push(this.createPoint(pick));
}
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
handlerGeologyClipPlan.setInputAction((event) => {
if (Cesium.defined(floatingPoint)) {
var newPosition = window.viewer.scene.pickPosition(
event.endPosition
);
if (Cesium.defined(newPosition)) {
floatingPoint.position.setValue(newPosition);
activeShapePoints.pop();
activeShapePoints.push(newPosition);
}
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
handlerGeologyClipPlan.setInputAction((event) => {
if (
!this.my3dtiles.clippingPlanes ||
!this.my3dtiles.clippingPlanes._planes.length
) {
if (drawList.length < 3) {
this.$message({
message: "提示:需要绘制三个以上点, 请继续绘制!",
type: "warning",
});
} else {
this.terminateShape();
const unionClippingRegions =
this.modelType === "0" ? true : false;
drawList = this.isDirRes(drawList, unionClippingRegions);
const Planes = [];
for (let i = 0; i < drawList.length; i++) {
if (i === drawList.length - 1) {
Planes.push(
this.createPlane(
drawList[i],
drawList[0],
inverseTransform
)
);
} else {
Planes.push(
this.createPlane(
drawList[i],
drawList[i + 1],
inverseTransform
)
);
}
}
console.log(Planes);
const PlaneCollection = new Cesium.ClippingPlaneCollection({
planes: Planes,
unionClippingRegions, // 再做优化
});
this.my3dtiles.clippingPlanes = PlaneCollection;
}
handlerGeologyClipPlan.removeInputAction(
Cesium.ScreenSpaceEventType.LEFT_CLICK
);
handlerGeologyClipPlan.removeInputAction(
Cesium.ScreenSpaceEventType.RIGHT_CLICK
);
handlerGeologyClipPlan.removeInputAction(
Cesium.ScreenSpaceEventType.MOUSE_MOVE
);
handlerGeologyClipPlan = null;
this.isDrawGeologyClipPlan = false;
window.viewer._container.style.cursor = "default";
}
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
},
getInverseTransform(tileSet) {
let transform;
const tmp = tileSet.root.transform;
if ((tmp && tmp.equals(Cesium.Matrix4.IDENTITY)) || !tmp) {
transform = Cesium.Transforms.eastNorthUpToFixedFrame(
tileSet.boundingSphere.center
);
} else {
transform = Cesium.Matrix4.fromArray(tileSet.root.transform);
}
return Cesium.Matrix4.inverseTransformation(
transform,
new Cesium.Matrix4()
);
},
cart3ToWGS(cart3) {
return {
lat: Cesium.Math.toDegrees(
Cesium.Cartographic.fromCartesian(cart3).latitude
),
lng: Cesium.Math.toDegrees(
Cesium.Cartographic.fromCartesian(cart3).longitude
),
};
},
createPlane(p1, p2, inverseTransform) {
// 将仅包含经纬度信息的p1,p2转换为相应坐标系的cartesian3对象
const p1C3 = this.getOriginCoordinateSystemPoint(
p1,
inverseTransform
);
const p2C3 = this.getOriginCoordinateSystemPoint(
p2,
inverseTransform
);
// 定义一个垂直向上的向量up
const up = new Cesium.Cartesian3(0, 0, 10);
// right 实际上就是由p1指向p2的向量
const right = Cesium.Cartesian3.subtract(
p2C3,
p1C3,
new Cesium.Cartesian3()
);
// 计算normal right叉乘up得到平面法向量这个法向量指向right的右侧
let normal = Cesium.Cartesian3.cross(
right,
up,
new Cesium.Cartesian3()
);
normal = Cesium.Cartesian3.normalize(normal, normal);
// 由于已经获得了法向量和过平面的一点因此可以直接构造Plane,并进一步构造ClippingPlane
const planeTmp = Cesium.Plane.fromPointNormal(p1C3, normal);
return Cesium.ClippingPlane.fromPlane(planeTmp);
},
getOriginCoordinateSystemPoint(point, inverseTransform) {
const val = Cesium.Cartesian3.fromDegrees(point.lng, point.lat);
return Cesium.Matrix4.multiplyByPoint(
inverseTransform,
val,
new Cesium.Cartesian3(0, 0, 0)
);
},
clearGeologyClipPlan() {
floatingPointList = [];
activeShapePoints = [];
if (geologyClipPlanObj) {
geologyClipPlanObj.clear();
geologyClipPlanObj = null;
}
this.isDrawGeologyClipPlan = false;
if (window.TilesetsList.length > 0) {
let tilestObj = window.TilesetsList[0].tileset;
tilestObj.clippingPlanes
? (tilestObj.clippingPlanes.removeAll(),
(tilestObj.clippingPlanes = undefined))
: "";
}
my3dtiles = undefined;
drawList = [];
},
isDirRes(polygon, isClockwise) {
debugger;
var lineStringList = [];
polygon.forEach((p) => {
lineStringList.push([p.lng, p.lat]);
});
var clockwiseRing = turf.lineString(lineStringList);
let isR = turf.booleanClockwise(clockwiseRing);
var points = [];
if (isClockwise) {
if (!isR) {
points = polygon;
} else {
var count = 0;
for (var ii = polygon.length - 1; ii >= 0; ii--) {
points[count] = polygon[ii];
count++;
}
}
} else {
if (isR) {
points = polygon;
} else {
var count = 0;
for (var ii = polygon.length - 1; ii >= 0; ii--) {
points[count] = polygon[ii];
count++;
}
}
}
return points;
},
drawShape(positionData) {
var shape = window.viewer.entities.add({
polygon: {
hierarchy: positionData,
material: new Cesium.ColorMaterialProperty(
Cesium.Color.BLUE.withAlpha(0.2)
),
},
});
return shape;
},
createPoint(worldPosition) {
var point = window.viewer.entities.add({
position: worldPosition,
point: {
color: Cesium.Color.RED,
pixelSize: 5,
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
},
});
return point;
},
terminateShape() {
activeShapePoints.pop();
var pol = this.drawShape(activeShapePoints);
floatingPointList.forEach((p) => {
window.viewer.entities.remove(p);
});
window.viewer.entities.remove(floatingPoint);
window.viewer.entities.remove(activeShape);
window.viewer.entities.remove(pol);
floatingPoint = undefined;
activeShape = undefined;
activeShapePoints = [];
},
},
mounted() {
this.initViewer();
},
});
</script>
</body>
</html>