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);
 
 
總結:側面的裁切面不能以屏幕坐標作為移動的依據,因為當旋轉模型時,正負值會發生改變,切面移動方向會和鼠標移動的方向相反,
然后我個人的解決方案是獲取地球坐標,然后再轉換成經緯,再以鼠標移動時經緯度差作為側面切面移動的依據,這樣就可以解決以上的問題,如果大家有更好的解決方案歡迎跟我交流
 
還有個問題,就是我側面的裁切面還沒觸碰模型就開始裁切,需要我手動去調,現在還沒解決,知道解決方案的大神也歡迎給我指點
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM