• cesium之平面裁切


    初学者,原理可能没这么深入,不过基本了解实现的步骤的逻辑

    基本的原理就是切面发法线方向为显示的部分,法线的反方向为裁切掉的部分

    动态的改变distance来实现模型的裁切

    实现主要用到的api有,ClippingPlaneCollection,ClippingPlane

    以下奉上具体实现步骤

    1.定义裁切平面数组

     var planesDistance = [];//用于存放多个裁切面距离模型原点的距离
     var clippingPlanesArray = [
                    new Cesium.ClippingPlane(new Cesium.Cartesian3(0.0, 0.0, -1.0), 0.0),//往下为裁切
                     new Cesium.ClippingPlane(new Cesium.Cartesian3(-1.0, 0.0, 0.0), 0.0),//侧面裁切
                    
                ];
    2.定义裁切平面集合
     //debugger;
                //定义裁切平面集合                      
                clippingPlanes = new Cesium.ClippingPlaneCollection({
                    planes: clippingPlanesArray,//定义的切面数组//变成undid
                    edgeColor: Cesium.Color.WHITE, // 平面切割时模型的边缘颜色
                    edgeWidth: viewModel.edgeStylingEnabled ? 1.0 : 0.0,//边缘的宽度y 
                    unionClippingRegions: true, //true 才能多个切割  
                    enabled: true,//裁切平面是否处于活动
                   clippingPlanes
                });
    3.加载模型并制定裁切平面
     var tileset = viewer.scene.primitives.add(new Cesium.Cesium3DTileset({
                        url: url,
                        luminanceAtZenith: 0.2,
                        lightColor: new Cesium.Cartesian3(0.3, 0.3, 0.3),
                       clippingPlanes:clippingPlanes
                    }));
    4.创建可视化裁切平面           
                tileset.debugShowBoundingVolume = viewModel.debugBoundingVolumesEnabled;
                boundingSphere = tileset.boundingSphere;//3d模型的中心和半径
                var radius = boundingSphere.radius;//
                viewer.zoomTo(tileset, new Cesium.HeadingPitchRange(0.5, -0.2, radius * 4.0));
                //加载plane可视化裁切平面
                if (!Cesium.Matrix4.equals(tileset.root.transform, Cesium.Matrix4.IDENTITY)) {
                    // The clipping plane is initially positioned at the tileset's root transform.
                    // Apply an additional matrix to center the clipping plane on the bounding sphere center.
                    var transformCenter = Cesium.Matrix4.getTranslation(tileset.root.transform, new Cesium.Cartesian3());//获取矩阵的平移部分
                    var transformCartographic = Cesium.Cartographic.fromCartesian(transformCenter);//结果对象中的值将以弧度表示。
                    var boundingSphereCartographic = Cesium.Cartographic.fromCartesian(tileset.boundingSphere.center);
                    var boundingSphereCartographicradius = Cesium.Cartographic.fromCartesian(radius);
                    var height = boundingSphereCartographic.height - transformCartographic.height;
                    console.log(boundingSphereCartographicradius);
                    var longitude = boundingSphereCartographic.longitude - transformCartographic.longitude;//经度
                    console.log(longitude * 111000);
                    var latitude = boundingSphereCartographic.latitude - transformCartographic.latitude;//维度
                    //下面决定了是否在中心点
                    clippingPlanes.modelMatrix = Cesium.Matrix4.fromTranslation(new Cesium.Cartesian3(40, 50, height));

                }
                //创建可视化对象
                for (var i = 0; i < clippingPlanes.length; ++i) {
                    var plane = clippingPlanes.get(i);
                    viewer.entities.add({
                        name: i,
                        position: boundingSphere.center,//设置裁切面的位置,offset, 根据3dtiles同步调整裁切面高度 
                        //PlaneGraphics.html
                        plane: {//每个裁切对象(distance为裁切面距离远点的高度)
                            dimensions: new Cesium.Cartesian2(radius, radius),//调整裁切面的长和宽
                            material: Cesium.Color.WHITE.withAlpha(0.1),//裁切面的颜色和透明度
                            plane: new Cesium.CallbackProperty(createPlaneUpdateFunction(plane, radius, i), false),
                            outline: true,//是否显示边框
                            outlineColor: Cesium.Color.WHITE,//边框颜色
                        }
                    });//add
                }
            }
    5.写一个方法动态改变ClippingPlane距离原点的距离
            function createPlaneUpdateFunction(plane, radius, name) {
                return function () {
                    plane.distance = planesDistance[name] + (radius * 0.5);//切面距离原点的距离就等于移动的距离+模型的半径的一半
                    return plane;
                };
            }
     
    6.定义鼠标事件
     var ellipsoid = viewer.scene.globe.ellipsoid;
                // 注册鼠标事件
                var downHandler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);//鼠标点击事件
                downHandler.setInputAction(function (movement) {
                    var position = viewer.scene.camera.pickEllipsoid(movement.position, viewer.scene.globe.ellipsoid);
                    //console.log(position);
                    var pickObject = scene.pick(movement.position);
                    //debugger;
                    if (Cesium.defined(pickObject) && Cesium.defined(pickObject.id) && Cesium.defined(pickObject.id.plane)) {
                        selectedPlane = pickObject.id.plane;//将entities
                        selectedPlane.name = pickObject.id.name//将name赋予selectedPlane
                        selectedPlane.material = Cesium.Color.WHITE.withAlpha(0.05);
                        selectedPlane.outlineColor = Cesium.Color.WHITE;//更换切面的颜色
                        selectedPlane.startPosition = movement.position;//
                        selectedPlane.startPosition1 = Cesium.Math.toDegrees((ellipsoid.cartesianToCartographic(position).longitude));//初始位置维度
                        scene.screenSpaceCameraController.enableInputs = false; // 取消默认的鼠标一切输入事件
                    }
                }, Cesium.ScreenSpaceEventType.LEFT_DOWN);


                // 注册鼠标松开事件
                var upHandler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);//鼠标点击向上事件
                upHandler.setInputAction(function () {

                    if (Cesium.defined(selectedPlane)) {//如果存在这个对象
                        selectedPlane.material = Cesium.Color.WHITE.withAlpha(0.6); // 恢复选中的切面颜色
                        selectedPlane.outlineColor = Cesium.Color.blue;//
                        selectedPlane = undefined;
                    }
                    scene.screenSpaceCameraController.enableInputs = true; // 恢复默认的鼠标一切输入事件
                }, Cesium.ScreenSpaceEventType.LEFT_UP);

                // 注册鼠标移动事件,
                var moveHandler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);//鼠标点击移动事件
                moveHandler.setInputAction(function (movement) {
                    //通过指定的椭球或者地图对应的坐标系,将鼠标的二维坐标转换为对应椭球体三维坐标
                    var cartesianEnd = viewer.camera.pickEllipsoid(movement.endPosition, ellipsoid);//笛卡尔积,获取鼠标移动结束世界坐标
                    var cartesianStart = viewer.camera.pickEllipsoid(movement.startPosition, ellipsoid);//笛卡尔积,获取鼠标开始移动时世界坐标
                    if (Cesium.defined(selectedPlane)) {
                       
                      //  console.log(selectedPlane.name);//做判断哪个面
                        if (selectedPlane.name == 0) {//往下
                            var deltaSize = movement.startPosition.y - movement.endPosition.y; // 计算鼠标移动的过程中产生的垂直高度距离
                            console.log("开始")
                            console.log("起始位置"+movement.startPosition.y);
                            console.log("结束为止"+movement.endPosition.y);
                            console.log("移动的幅度"+deltaSize);
                            planesDistance[selectedPlane.name] += deltaSize ;//更改鼠标移动的幅度//从初始位置开始算
                            console.log("结束")
                            
                        }

                        if (selectedPlane.name == 1) {//侧面
                            if (cartesianEnd&&cartesianStart) {//能获取
                                //将笛卡尔坐标转换为地理(地图)坐标
                                var cartographiEnd = ellipsoid.cartesianToCartographic(cartesianEnd);
                                var cartographicStart = ellipsoid.cartesianToCartographic(cartesianStart);
                                //console.log(cartographic);
                                //将弧度转为度的十进制度表示,因为差值很小,保留20位小数
                               var  longitudeStringEnd = (Cesium.Math.toDegrees(cartographiEnd.longitude).toFixed(20));/
                               var  longitudeStringStart = (Cesium.Math.toDegrees(cartographicStart.longitude).toFixed(20));/
                               var longitudeGap=(longitudeStringEnd-longitudeStringStart)*100000;
                
                               console.log("两者之间的差距"+longitudeGap);
                               console.log("++===");/获取经度往上变大
                                /
                                planesDistance[selectedPlane.name] +=longitudeGap;//原来的距离加上移动的距离(很重要,决定了裁切面的移动方向)
                            } else {
                                // mouse_state.innerText = "";
                            }

                        }
                        

                    }
                }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
     
     
    总结:侧面的裁切面不能以屏幕坐标作为移动的依据,因为当旋转模型时,正负值会发生改变,切面移动方向会和鼠标移动的方向相反,
    然后我个人的解决方案是获取地球坐标,然后再转换成经纬,再以鼠标移动时经纬度差作为侧面切面移动的依据,这样就可以解决以上的问题,如果大家有更好的解决方案欢迎跟我交流
     
    还有个问题,就是我侧面的裁切面还没触碰模型就开始裁切,需要我手动去调,现在还没解决,知道解决方案的大神也欢迎给我指点
     
  • 相关阅读:
    Java用户自定义函数
    JavaScript常用函数
    Javascript 流程控制
    Javascript基础
    CSS的继承和使用方式
    Python列表
    Python变量和简单数据类型
    CSS选择符
    CSS的基本语法
    Java环境变量搭建
  • 原文地址:https://www.cnblogs.com/superman-21/p/12832850.html
Copyright © 2020-2023  润新知