learning_cesium/Clipping压平.html

353 lines
13 KiB
HTML
Raw Permalink 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="./Build168/Cesium/Cesium.js"></script>
<script src="./js/turf.min.js"></script>
<style>
@import url(./Build/Cesium/Widgets/widgets.css);
html,
body,
#cesiumContainer {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
</style>
</head>
<body>
<div id="cesiumContainer"></div>
<script>
Cesium.Ion.defaultAccessToken =
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI5ZjRjNTZkNC01NDYxLTRhMjQtOGEwZC1kZjA3YzQ5YTJlZDkiLCJpZCI6MjYwODQsInNjb3BlcyI6WyJhc3IiLCJnYyJdLCJpYXQiOjE1ODcxOTMwODN9.prGsSKyAW_9Ow5zHYPhbm3LsQL-ApQw5-5PNJkDaHi8";
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,
selectionIndicator: false, //是否显示选中的矩形框
});
// var viewer = new Cesium.Viewer('cesiumContainer', {
// terrainProvider: Cesium.createWorldTerrain()
// });
// var tileset = viewer.scene.primitives.add(
// new Cesium.Cesium3DTileset({
// url: Cesium.IonResource.fromAssetId(115448),
// })
// );
// viewer.zoomTo(tileset)
// let url = "./SampleData/cesiumlab/tileset.json";
let url = 'http://localhost:8078/3dtiles/zhudian/tileset.json'
let tileset = loadTileset(url);
// 创建切面平面集合
// var planes = [];
// var clippingPlanes = new Cesium.ClippingPlaneCollection({
// // planes: [
// // new Cesium.ClippingPlane(new Cesium.Cartesian3(0, 0, -1), 0) // 平面的方向(x,y,z) 以及 平面到原点的距离
// // ],
// planes: planes,
// edgeColor: Cesium.Color.WHITE, // 平面切割时模型的边缘颜色
// edgeWidth: 0, // 平面切割时模型的边缘宽度
// });
function loadTileset(tilesetUrl) {
let vm = this;
let tileset = new Cesium.Cesium3DTileset({
url: tilesetUrl,
// clippingPlanes: clippingPlanes,
maximumScreenSpaceError: 8,
dynamicScreenSpaceError: true,
dynamicScreenSpaceErrorDensity: 0.00278,
dynamicScreenSpaceErrorFactor: 4.0,
dynamicScreenSpaceErrorHeightFalloff: 0.25,
});
viewer.scene.primitives.add(tileset);
viewer.zoomTo(tileset);
tileset.readyPromise.then(function (tileset_) {
console.log("tileset_", tileset_);
setTilesetHeightAndOffset(tileset_, -40);
});
return tileset;
}
function 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;
}
/**
* 根据文档中的介绍可知ClippingPlane所位于的坐标系应该是以3DTiles原点为坐标原点
* 该点正东为x轴正方向该点正北为y轴正方向该点的地球椭球体法线为z轴远离地心的那一端为z轴正方向。
*/
function getInverseTransform(tileSet) {
let transform;
let tmp =
(tileSet.root && tileSet.root.transform) || tileSet.modelMatrix;
if ((tmp && tmp.equals(Cesium.Matrix4.IDENTITY)) || !tmp) {
// 如果root.transform不存在则3DTiles的原点变成了boundingSphere.center
transform = Cesium.Transforms.eastNorthUpToFixedFrame(
tileSet.boundingSphere.center
);
} else {
transform = Cesium.Matrix4.fromArray(tileSet.root.transform);
}
return Cesium.Matrix4.inverseTransformation(
transform,
new Cesium.Matrix4()
);
}
/**
* 对点进行坐标转换的方法
*
*/
function getOriginCoordinateSystemPoint(point, inverseTransform) {
let val = Cesium.Cartesian3.fromDegrees(point.lng, point.lat);
return Cesium.Matrix4.multiplyByPoint(
inverseTransform,
val,
new Cesium.Cartesian3(0, 0, 0)
);
}
/**
* 下面就构造了一个由地平面两点p1,p2定义的剪裁面这个剪裁面始终剪裁掉位于p1指向p2的向量的左侧。
*
*/
function createPlane(p1, p2, inverseTransform) {
// 将仅包含经纬度信息的p1,p2转换为相应坐标系的cartesian3对象
let p1C3 = getOriginCoordinateSystemPoint(p1, inverseTransform);
let p2C3 = getOriginCoordinateSystemPoint(p2, inverseTransform);
// 定义一个垂直向上的向量up
let up = new Cesium.Cartesian3(0, 0, 10);
// right 实际上就是由p1指向p2的向量
let 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
let planeTmp = Cesium.Plane.fromPointNormal(p1C3, normal);
return Cesium.ClippingPlane.fromPlane(planeTmp);
}
// 需要裁剪的面的四个点,由3可以得到一个剪裁面了。那么对于数组[p1,p2,p3…pN]
// 当该数组中的点是按照顺时针排序时(因为3中叉乘的方向是right × up)相邻点两两构成一个剪裁面就可以达到如上图2的效果
// 顺时针数组
// var coords = [
// [114.792694, 32.276356],
// [114.792761, 32.276744],
// [114.793105, 32.276702],
// [114.793045, 32.276312],
// ];
// 逆时针数组
// var coords = [
// [114.79271634627476,32.2763556665484],
// [114.79304073862163,32.27632363445024],
// [114.79309289472988,32.27668610700086],
// [114.79276024896451,32.27672647537516]
// ]
// 顺时针
var coords = [
[114.90848378, 32.3870309],
[114.90946223, 32.38700814],
[114.90944923, 32.38673509],
[114.90847078, 32.38676434],
[114.90848378, 32.3870309]
];
// coords = coords.reverse()
// tileset.readyPromise.then(function (tileset_) {
// console.log("tileset_", tileset_);
// // clippingTileset(tileset_)
// });
function clippingTileset(coords){
let tilesetMap = {}
coords.forEach(item=>{
let position = Cesium.Cartesian3.fromDegrees(item[0],item[1])
let cartesian2 = Cesium.SceneTransforms.wgs84ToWindowCoordinates(viewer.scene, position)
console.log(position)
let primitives = viewer.scene.drillPick(cartesian2)
primitives.forEach(instance=>{
if(instance.primitive instanceof Cesium.Cesium3DTileset){
// 用tiles的URL作为标识记录模型和点
if(!tilesetMap[instance.primitive._url]){
tilesetMap[instance.primitive._url] = {
tilesSet:instance.primitive,
points:[]
}
}
tilesetMap[instance.primitive._url]["points"].push(item)
}
})
})
if(Object.keys(tilesetMap).length){
for(let key in tilesetMap){
let item = tilesetMap[key];
this.clippingTiles(item.points,item.tilesSet)
}
}else{
layer.msg("没有找到与之匹配的模型!")
}
}
function clippingTiles(points,tileset_){
console.log(points,tileset_)
// 构造裁切面 clippingPanel
// 1.计算转换需要的用到的矩阵
let matrix = getInverseTransform(tileset_);
let modelType = "1";//外部裁剪为"0",内部裁剪为"1"
const unionClippingRegions = modelType === "0" ? true : false;
points = isDirRes(points,unionClippingRegions)
const Planes = [];
for (let i = 0; i < points.length-1; i++) {
let p1 = { lng: points[i][0], lat: points[i][1] };
let p2 = { lng: points[i+1][0], lat: points[i+1][1] };
let plane = createPlane(p1, p2, matrix);
Planes.push(plane);
}
console.log(Planes);
if(!tileset_.clippingPlanes){
const PlaneCollection = new Cesium.ClippingPlaneCollection({
planes: Planes,
unionClippingRegions,
});
tileset_.clippingPlanes = PlaneCollection;
}else{
tileset_.clippingPlanes.removeAll();
Planes.forEach(plane=>{
tileset_.clippingPlanes.add(plane)
})
}
}
/**
* ring 为闭合的环
* isClockwise 需要返回的数组方向
*/
function isDirRes(ring, isClockwise) {
debugger;
var lineStringList = [];
ring.forEach((p) => {
lineStringList.push([p[0], p[1]]);
});
var clockwiseRing = turf.lineString(lineStringList);
let isR = turf.booleanClockwise(clockwiseRing);
console.log("isR",isR);
var points = [];
if(!isClockwise){// 需要逆时针
points = isR?[...ring.reverse()]:[...ring]
}else{// 需要顺时针
points = isR?[...ring]:[...ring.reverse()]
}
return points;
}
// viewer.scene.primitives.add(
// new Cesium.Primitive({
// geometryInstances: new Cesium.GeometryInstance({
// geometry: new Cesium.PolygonGeometry({
// polygonHierarchy: new Cesium.PolygonHierarchy(
// Cesium.Cartesian3.fromDegreesArray(coords.flat())
// ),
// vertexFormat: Cesium.EllipsoidSurfaceAppearance.VERTEX_FORMAT,
// height: 6,
// }),
// }),
// appearance: new Cesium.EllipsoidSurfaceAppearance({
// material: new Cesium.Material({
// fabric: {
// type: "Image",
// uniforms: {
// image: "./images/贴图/草坪/草坪1.jpg",
// },
// },
// }),
// }),
// })
// );
let handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
handler.setInputAction(function (movement) {
//捕获椭球体,将笛卡尔二维平面坐标转为椭球体的笛卡尔三维坐标,返回球体表面的点
var cartesian3 = viewer.camera.pickEllipsoid(movement.position);
if (cartesian3) {
//将笛卡尔三维坐标转为地图坐标(弧度)
var cartographic =
viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian3);
//将地图坐标(弧度)转为十进制的度数
var lat_String = Cesium.Math.toDegrees(cartographic.latitude).toFixed(
6
);
var log_String = Cesium.Math.toDegrees(
cartographic.longitude
).toFixed(6);
var alti_String = (
viewer.camera.positionCartographic.height / 1000
).toFixed(2);
console.log(log_String + "," + lat_String);
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
</script>
</body>
</html>