1. 程式人生 > 實用技巧 >Cesium測量距離和麵積、位置座標

Cesium測量距離和麵積、位置座標

Cesium測量距離和麵積

直接上程式碼,下面兩個函式已經封裝好,可以直接呼叫;有疑問請加群討論:1047907561

//線長度測量
function measureLine(viewer) {
    var handler = new Cesium.ScreenSpaceEventHandler(viewer.scene._imageryLayerCollection);
    var positions = [];
    var poly = null;
    var distance = 0;
    var cartesian = null;
    var floatingPoint;
    var labelPt;
    handler.setInputAction(function (movement) {
        let ray = viewer.camera.getPickRay(movement.endPosition);
        cartesian = viewer.scene.globe.pick(ray, viewer.scene);
        if (!Cesium.defined(cartesian)) //跳出地球時異常
            return;
        if (positions.length >= 2) {
            if (!Cesium.defined(poly)) {
                poly = new PolyLinePrimitive(positions);
            } else {
                positions.pop();
                positions.push(cartesian);
            }
        }
    }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

    handler.setInputAction(function (movement) {
        let ray = viewer.camera.getPickRay(movement.position);
        cartesian = viewer.scene.globe.pick(ray, viewer.scene);
        if (!Cesium.defined(cartesian)) //跳出地球時異常
            return;
        if (positions.length == 0) {
            positions.push(cartesian.clone());
        }
        positions.push(cartesian);
        //記錄滑鼠單擊時的節點位置,非同步計算貼地距離
        labelPt = positions[positions.length - 1];
        if (positions.length > 2) {
            getSpaceDistance(positions);
        } else if (positions.length == 2) {
            //在三維場景中新增Label
            floatingPoint = viewer.entities.add({
                name: '空間距離',
                position: labelPt,
                point: {
                    pixelSize: 5,
                    color: Cesium.Color.RED,
                    outlineColor: Cesium.Color.WHITE,
                    outlineWidth: 2,
                }
            });
        }
    }, Cesium.ScreenSpaceEventType.LEFT_CLICK);

    handler.setInputAction(function (movement) {
        handler.destroy(); //關閉事件控制代碼
        handler = undefined;
        positions.pop(); //最後一個點無效
        if (positions.length == 1)
            viewer.entities.remove(floatingPoint);

    }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);

    var PolyLinePrimitive = (function () {
        function _(positions) {
            this.options = {
                name: '直線',
                polyline: {
                    show: true,
                    positions: [],
                    material: Cesium.Color.CHARTREUSE,
                    width: 5,
                    clampToGround: true
                }
            };
            this.positions = positions;
            this._init();
        }

        _.prototype._init = function () {
            var _self = this;
            var _update = function () {
                return _self.positions;
            };
            //實時更新polyline.positions
            this.options.polyline.positions = new Cesium.CallbackProperty(_update, false);
            var addedEntity = viewer.entities.add(this.options);
        };

        return _;
    })();

    //空間兩點距離計算函式
    function getSpaceDistance(positions) {
        console.log(22)
        //只計算最後一截,與前面累加
        //因move和滑鼠左擊事件,最後兩個點座標重複
        var i = positions.length - 3;
        var point1cartographic = Cesium.Cartographic.fromCartesian(positions[i]);
        var point2cartographic = Cesium.Cartographic.fromCartesian(positions[i + 1]);
        getTerrainDistance(point1cartographic, point2cartographic);
    }

    function getTerrainDistance(point1cartographic, point2cartographic) {
        var geodesic = new Cesium.EllipsoidGeodesic();
        geodesic.setEndPoints(point1cartographic, point2cartographic);
        var s = geodesic.surfaceDistance;
        var cartoPts = [point1cartographic];
        for (var jj = 1000; jj < s; jj += 1000) {  //分段取樣計算距離
            var cartoPt = geodesic.interpolateUsingSurfaceDistance(jj);
            cartoPts.push(cartoPt);
        }
        cartoPts.push(point2cartographic);
        //返回兩點之間的距離
        var promise = Cesium.sampleTerrain(viewer.terrainProvider, 8, cartoPts);
        Cesium.when(promise, function (updatedPositions) {
            for (var jj = 0; jj < updatedPositions.length - 1; jj++) {
                var geoD = new Cesium.EllipsoidGeodesic();
                geoD.setEndPoints(updatedPositions[jj], updatedPositions[jj + 1]);
                var innerS = geoD.surfaceDistance;
                innerS = Math.sqrt(Math.pow(innerS, 2) + Math.pow(updatedPositions[jj + 1].height - updatedPositions[jj].height, 2));
                distance += innerS;
            }
            //在三維場景中新增Label
            var lon1 = viewer.scene.globe.ellipsoid.cartesianToCartographic(labelPt).longitude;
            var lat1 = viewer.scene.globe.ellipsoid.cartesianToCartographic(labelPt).latitude;
            var lonLat = "(" + Cesium.Math.toDegrees(lon1).toFixed(2) + "," + Cesium.Math.toDegrees(lat1).toFixed(2) + ")";
            var textDisance = distance.toFixed(2) + "米";
            if (distance > 10000)
                textDisance = (distance / 1000.0).toFixed(2) + "千米";
            floatingPoint = viewer.entities.add({
                name: '貼地距離',
                position: labelPt,
                point: {
                    pixelSize: 5,
                    color: Cesium.Color.RED,
                    outlineColor: Cesium.Color.WHITE,
                    outlineWidth: 2,
                },
                label: {
                    text: lonLat + textDisance,
                    font: '18px sans-serif',
                    fillColor: Cesium.Color.GOLD,
                    style: Cesium.LabelStyle.FILL_AND_OUTLINE,
                    outlineWidth: 2,
                    verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
                    pixelOffset: new Cesium.Cartesian2(20, -20),
                }
            });
        });
    }
}

//面積測量
function measurePolygn(viewer) {
    // 滑鼠事件
    var handler = new Cesium.ScreenSpaceEventHandler(viewer.scene._imageryLayerCollection);
    var positions = [];
    var tempPoints = [];
    var polygon = null;
    var cartesian = null;
    var floatingPoint;//浮動點
    handler.setInputAction(function (movement) {
        let ray = viewer.camera.getPickRay(movement.endPosition);
        cartesian = viewer.scene.globe.pick(ray, viewer.scene);
        positions.pop();//移除最後一個
        positions.push(cartesian);
        if (positions.length >= 2) {
            var dynamicPositions = new Cesium.CallbackProperty(function () {
                return new Cesium.PolygonHierarchy(positions);
                return positions;
            }, false);
            polygon = PolygonPrimitive(dynamicPositions);
        }
    }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

    handler.setInputAction(function (movement) {
        let ray = viewer.camera.getPickRay(movement.position);
        cartesian = viewer.scene.globe.pick(ray, viewer.scene);
        if (positions.length == 0) {
            positions.push(cartesian.clone());
        }
        positions.push(cartesian);
        //在三維場景中新增點
        var cartographic = Cesium.Cartographic.fromCartesian(positions[positions.length - 1]);
        var longitudeString = Cesium.Math.toDegrees(cartographic.longitude);
        var latitudeString = Cesium.Math.toDegrees(cartographic.latitude);
        var heightString = cartographic.height;
        var labelText = "(" + longitudeString.toFixed(2) + "," + latitudeString.toFixed(2) + ")";
        tempPoints.push({ lon: longitudeString, lat: latitudeString, hei: heightString });
        floatingPoint = viewer.entities.add({
            name: '多邊形面積',
            position: positions[positions.length - 1],
            point: {
                pixelSize: 5,
                color: Cesium.Color.RED,
                outlineColor: Cesium.Color.WHITE,
                outlineWidth: 2,
                heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
            },
            label: {
                text: labelText,
                font: '18px sans-serif',
                fillColor: Cesium.Color.GOLD,
                style: Cesium.LabelStyle.FILL_AND_OUTLINE,
                outlineWidth: 2,
                verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
                pixelOffset: new Cesium.Cartesian2(20, -20),
            }
        });
    }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
    handler.setInputAction(function (movement) {
        handler.destroy();
        positions.pop();
        var textArea = getArea(tempPoints) + "平方公里";
        viewer.entities.add({
            name: '多邊形面積',
            position: positions[positions.length - 1],
            label: {
                text: textArea,
                font: '18px sans-serif',
                fillColor: Cesium.Color.GOLD,
                style: Cesium.LabelStyle.FILL_AND_OUTLINE,
                outlineWidth: 2,
                verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
                pixelOffset: new Cesium.Cartesian2(20, -40),
                heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
            }
        });
    }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
    var radiansPerDegree = Math.PI / 180.0;//角度轉化為弧度(rad)
    var degreesPerRadian = 180.0 / Math.PI;//弧度轉化為角度
    //計算多邊形面積
    function getArea(points) {
        var res = 0;
        //拆分三角曲面
        for (var i = 0; i < points.length - 2; i++) {
            var j = (i + 1) % points.length;
            var k = (i + 2) % points.length;
            var totalAngle = Angle(points[i], points[j], points[k]);
            var dis_temp1 = distance(positions[i], positions[j]);
            var dis_temp2 = distance(positions[j], positions[k]);
            res += dis_temp1 * dis_temp2 * Math.abs(Math.sin(totalAngle));
        }
        return (res / 1000000.0).toFixed(4);
    }

    /*角度*/
    function Angle(p1, p2, p3) {
        var bearing21 = Bearing(p2, p1);
        var bearing23 = Bearing(p2, p3);
        var angle = bearing21 - bearing23;
        if (angle < 0) {
            angle += 360;
        }
        return angle;
    }
    /*方向*/
    function Bearing(from, to) {
        var lat1 = from.lat * radiansPerDegree;
        var lon1 = from.lon * radiansPerDegree;
        var lat2 = to.lat * radiansPerDegree;
        var lon2 = to.lon * radiansPerDegree;
        var angle = -Math.atan2(Math.sin(lon1 - lon2) * Math.cos(lat2), Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(lon1 - lon2));
        if (angle < 0) {
            angle += Math.PI * 2.0;
        }
        angle = angle * degreesPerRadian;//角度
        return angle;
    }

    function PolygonPrimitive(positions) {
        polygon = viewer.entities.add({
            polygon: {
                hierarchy: positions,
                material: Cesium.Color.GREEN.withAlpha(0.1),
            }
        });

    }

    function distance(point1, point2) {
        var point1cartographic = Cesium.Cartographic.fromCartesian(point1);
        var point2cartographic = Cesium.Cartographic.fromCartesian(point2);
        /**根據經緯度計算出距離**/
        var geodesic = new Cesium.EllipsoidGeodesic();
        geodesic.setEndPoints(point1cartographic, point2cartographic);
        var s = geodesic.surfaceDistance;
        //返回兩點之間的距離
        s = Math.sqrt(Math.pow(s, 2) + Math.pow(point2cartographic.height - point1cartographic.height, 2));
        return s;
    }
}

measureLine(viewer)
measurePolygn(viewer) 



//獲取座標點 //handler.setInputAction(function(event){ //viewer.scene.globe.depthTestAgainstTerrain=true; //varearthPosition=viewer.scene.pickPosition(event.position); //console.log(earthPosition) ////3.地標座標:獲取點選處地球表面的世界座標,不包括模型、傾斜攝影表面 //varray=viewer.camera.getPickRay(event.position); //varearthPosition=viewer.scene.globe.pick(ray,viewer.scene);
//if(Cesium.defined(earthPosition)){ //console.log(earthPosition); //} //},Cesium.ScreenSpaceEventType.LEFT_CLICK);


/* vue中整理好 */
////距離計算 //measureLine(viewer){ //varhandler=newCesium.ScreenSpaceEventHandler( //this.viewer.scene._imageryLayerCollection //); //varpositions=[]; //varpoly=null; //vardistance=0; //varcartesian=null;
//varfloatingPoint; //varlabelPt; //varthat=this; //handler.setInputAction(function(movement){ //letray=that.viewer.camera.getPickRay(movement.endPosition); //cartesian=that.viewer.scene.globe.pick(ray,that.viewer.scene); //if(!Cesium.defined(cartesian)) ////跳出地球時異常 //return; //if(positions.length>=2){ //if(!Cesium.defined(poly)){ //poly=newPolyLinePrimitive(positions); //}else{ //positions.pop(); //positions.push(cartesian); //} //} //},Cesium.ScreenSpaceEventType.MOUSE_MOVE); //handler.setInputAction(function(movement){ //letray=that.viewer.camera.getPickRay(movement.position); //cartesian=that.viewer.scene.globe.pick(ray,that.viewer.scene); //if(!that.Cesium.defined(cartesian)) ////跳出地球時異常 //return; //if(positions.length==0){ //positions.push(cartesian.clone()); //} //positions.push(cartesian); ////記錄滑鼠單擊時的節點位置,非同步計算貼地距離 //labelPt=positions[positions.length-1]; //if(positions.length>2){ //getSpaceDistance(positions); //}elseif(positions.length==2){ ////在三維場景中新增Label //floatingPoint=that.viewer.entities.add({ //name:"空間距離", //position:labelPt, //point:{ //pixelSize:5, //color:Cesium.Color.RED, //outlineColor:Cesium.Color.WHITE, //outlineWidth:2 //} //}); //} //},Cesium.ScreenSpaceEventType.LEFT_CLICK); //handler.setInputAction(function(movement){ //handler.destroy();//關閉事件控制代碼 //handler=undefined; //positions.pop();//最後一個點無效 //if(positions.length==1)that.viewer.entities.remove(floatingPoint); //},Cesium.ScreenSpaceEventType.RIGHT_CLICK); //varPolyLinePrimitive=(function(){ //function_(positions){ //this.options={ //name:"直線", //polyline:{ //show:true, //positions:[], //material:Cesium.Color.CHARTREUSE, //width:5, //clampToGround:true //} //}; //this.positions=positions; //this._init(); //} //_.prototype._init=function(){ //var_self=this; //var_update=function(){ //return_self.positions; //}; ////實時更新polyline.positions //this.options.polyline.positions=newCesium.CallbackProperty( //_update, //false //); //varaddedEntity=that.viewer.entities.add(this.options); //}; //return_; //})(); ////空間兩點距離計算函式 //functiongetSpaceDistance(positions){ ////只計算最後一截,與前面累加 ////因move和滑鼠左擊事件,最後兩個點座標重複 //vari=positions.length-3; //varpoint1cartographic=that.Cesium.Cartographic.fromCartesian( //positions[i] //); //varpoint2cartographic=that.Cesium.Cartographic.fromCartesian( //positions[i+1] //); //getTerrainDistance(point1cartographic,point2cartographic); //} //functiongetTerrainDistance(point1cartographic,point2cartographic){ //vargeodesic=newCesium.EllipsoidGeodesic(); //geodesic.setEndPoints(point1cartographic,point2cartographic); //vars=geodesic.surfaceDistance; //varcartoPts=[point1cartographic]; //for(varjj=1000;jj<s;jj+=1000){ ////分段取樣計算距離 //varcartoPt=geodesic.interpolateUsingSurfaceDistance(jj); //cartoPts.push(cartoPt); //} //cartoPts.push(point2cartographic); ////返回兩點之間的距離 //varpromise=that.Cesium.sampleTerrain( //that.viewer.terrainProvider, //8, //cartoPts //); //Cesium.when(promise,function(updatedPositions){ //for(varjj=0;jj<updatedPositions.length-1;jj++){ //vargeoD=newCesium.EllipsoidGeodesic(); //geoD.setEndPoints(updatedPositions[jj],updatedPositions[jj+1]); //varinnerS=geoD.surfaceDistance; //innerS=Math.sqrt( //Math.pow(innerS,2)+ //Math.pow( //updatedPositions[jj+1].height-updatedPositions[jj].height, //2 //) //); //distance+=innerS; //} ////在三維場景中新增Label //varlon1=that.viewer.scene.globe.ellipsoid.cartesianToCartographic( //labelPt //).longitude; //varlat1=that.viewer.scene.globe.ellipsoid.cartesianToCartographic( //labelPt //).latitude; //varlonLat= //"("+ //Cesium.Math.toDegrees(lon1).toFixed(2)+ //","+ //Cesium.Math.toDegrees(lat1).toFixed(2)+ //")"; //vartextDisance=distance.toFixed(2)+"米"; //if(distance>10000) //textDisance=(distance/1000.0).toFixed(2)+"千米"; //floatingPoint=that.viewer.entities.add({ //name:"貼地距離", //position:labelPt, //point:{ //pixelSize:5, //color:Cesium.Color.RED, //outlineColor:Cesium.Color.WHITE, //outlineWidth:2 //}, //label:{ //text:lonLat+textDisance, //font:"18pxsans-serif", //fillColor:Cesium.Color.GOLD, //style:Cesium.LabelStyle.FILL_AND_OUTLINE, //outlineWidth:2, //verticalOrigin:Cesium.VerticalOrigin.BOTTOM, //pixelOffset:newCesium.Cartesian2(20,-20) //} //}); //}); //} //}, ////面積計算 //measurePolygn(viewer){ ////滑鼠事件 //varhandler=newCesium.ScreenSpaceEventHandler( //viewer.scene._imageryLayerCollection //); //varpositions=[]; //vartempPoints=[]; //varpolygon=null; //varcartesian=null; //varfloatingPoint;//浮動點 //varthat=this; //handler.setInputAction(function(movement){ //letray=that.viewer.camera.getPickRay(movement.endPosition); //cartesian=that.viewer.scene.globe.pick(ray,that.viewer.scene); //positions.pop();//移除最後一個 //positions.push(cartesian); //if(positions.length>=2){ //vardynamicPositions=newCesium.CallbackProperty(function(){ //returnnewCesium.PolygonHierarchy(positions); //returnpositions; //},false); //polygon=PolygonPrimitive(dynamicPositions); //} //},Cesium.ScreenSpaceEventType.MOUSE_MOVE); //handler.setInputAction(function(movement){ //letray=that.viewer.camera.getPickRay(movement.position); //cartesian=that.viewer.scene.globe.pick(ray,viewer.scene); //if(positions.length==0){ //positions.push(cartesian.clone()); //} //positions.push(cartesian); ////在三維場景中新增點 //varcartographic=that.Cesium.Cartographic.fromCartesian( //positions[positions.length-1] //); //varlongitudeString=that.Cesium.Math.toDegrees( //cartographic.longitude //); //varlatitudeString=that.Cesium.Math.toDegrees(cartographic.latitude); //varheightString=cartographic.height; //varlabelText= //"("+ //longitudeString.toFixed(2)+ //","+ //latitudeString.toFixed(2)+ //")"; //tempPoints.push({ //lon:longitudeString, //lat:latitudeString, //hei:heightString //}); //floatingPoint=that.viewer.entities.add({ //name:"多邊形面積", //position:positions[positions.length-1], //point:{ //pixelSize:5, //color:Cesium.Color.RED, //outlineColor:Cesium.Color.WHITE, //outlineWidth:2, //heightReference:Cesium.HeightReference.CLAMP_TO_GROUND //}, //label:{ //text:labelText, //font:"18pxsans-serif", //fillColor:Cesium.Color.GOLD, //style:Cesium.LabelStyle.FILL_AND_OUTLINE, //outlineWidth:2, //verticalOrigin:Cesium.VerticalOrigin.BOTTOM, //pixelOffset:newCesium.Cartesian2(20,-20) //} //}); //},Cesium.ScreenSpaceEventType.LEFT_CLICK); //handler.setInputAction(function(movement){ //handler.destroy(); //positions.pop(); //vartextArea=getArea(tempPoints)+"平方公里"; //that.viewer.entities.add({ //name:"多邊形面積", //position:positions[positions.length-1], //label:{ //text:textArea, //font:"18pxsans-serif", //fillColor:Cesium.Color.GOLD, //style:Cesium.LabelStyle.FILL_AND_OUTLINE, //outlineWidth:2, //verticalOrigin:Cesium.VerticalOrigin.BOTTOM, //pixelOffset:newCesium.Cartesian2(20,-40), //heightReference:Cesium.HeightReference.CLAMP_TO_GROUND //} //}); //},Cesium.ScreenSpaceEventType.RIGHT_CLICK); //varradiansPerDegree=Math.PI/180.0;//角度轉化為弧度(rad) //vardegreesPerRadian=180.0/Math.PI;//弧度轉化為角度 ////計算多邊形面積 //functiongetArea(points){ //varres=0; ////拆分三角曲面 //for(vari=0;i<points.length-2;i++){ //varj=(i+1)%points.length; //vark=(i+2)%points.length; //vartotalAngle=Angle(points[i],points[j],points[k]); //vardis_temp1=distance(positions[i],positions[j]); //vardis_temp2=distance(positions[j],positions[k]); //res+=dis_temp1*dis_temp2*Math.abs(Math.sin(totalAngle)); //} //return(res/1000000.0).toFixed(4); //} ///*角度*/ //functionAngle(p1,p2,p3){ //varbearing21=Bearing(p2,p1); //varbearing23=Bearing(p2,p3); //varangle=bearing21-bearing23; //if(angle<0){ //angle+=360; //} //returnangle; //} ///*方向*/ //functionBearing(from,to){ //varlat1=from.lat*radiansPerDegree; //varlon1=from.lon*radiansPerDegree; //varlat2=to.lat*radiansPerDegree; //varlon2=to.lon*radiansPerDegree; //varangle=-Math.atan2( //Math.sin(lon1-lon2)*Math.cos(lat2), //Math.cos(lat1)*Math.sin(lat2)- //Math.sin(lat1)*Math.cos(lat2)*Math.cos(lon1-lon2) //); //if(angle<0){ //angle+=Math.PI*2.0; //} //angle=angle*degreesPerRadian;//角度 //returnangle; //} //functionPolygonPrimitive(positions){ //polygon=that.viewer.entities.add({ //polygon:{ //hierarchy:positions, //material:Cesium.Color.GREEN.withAlpha(0.1) //} //}); //} //functiondistance(point1,point2){ //varpoint1cartographic=that.Cesium.Cartographic.fromCartesian(point1); //varpoint2cartographic=that.Cesium.Cartographic.fromCartesian(point2); ///**根據經緯度計算出距離**/ //vargeodesic=newCesium.EllipsoidGeodesic(); //geodesic.setEndPoints(point1cartographic,point2cartographic); //vars=geodesic.surfaceDistance; ////返回兩點之間的距離 //s=Math.sqrt( //Math.pow(s,2)+ //Math.pow(point2cartographic.height-point1cartographic.height,2) //); //returns; //} //}