learning_cesium/clipping-3dtiles.html

511 lines
18 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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>