learning_cesium/Clipping压平.html

353 lines
13 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="./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>