可视域分析-源代码示例 运行 重置

                    <!DOCTYPE html>

<html>
<head>
    <meta charset='UTF-8'/>
    <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no'/>
    <link href='http://bigemap.com:9000/bigemap-gl.js/v1.1.0/Widgets/widgets.css' rel='stylesheet'/>
    <script src='http://bigemap.com:9000/bigemap-gl.js/v1.1.0/bigemap-gl.js'></script>
    <style>
        body {
            margin: 0;
            padding: 0;
        }
        #container {
            position: absolute;
            top: 0;
            bottom: 0;
            width: 100%;
        }
        .info{
            position: absolute;
            top:0;
            left: 0;
            right: 0;
            z-index: 9;
            text-align: center;
            height: 30px;
            line-height: 30px;
            color: #909399;
            background: #f4f4f5;
        }
    </style>
    <title>part_test</title>
</head>
<body>
    <div class="info">
    点击地图可以获取当前位置的可视域分析(绿色表示可见,红色不为可见)
</div>
<div id='container'></div>
<script>
    bmgl.Config.HTTP_URL = 'http://bigemap.com:9000';
    var viewer = new bmgl.Viewer('container', {mapId: 'bigemap.googlemap-satellite',requestRenderMode:false,terrainId: 'bigemap.9af15d8e'});
    //设置初始位置
    viewer.camera.setView({
        destination: bmgl.Cartesian3.fromDegrees(103.59526245619938,30.9814012061604,3837.4144546),
        orientation: {"heading":6.282150327905171,"roll":6.279635689524259,"pitch":-0.6993902253931052}
    });
    //当前的视点坐标
    var startPoint={
        lng:103.5898409037154,
        lat:31.012823472619534
    };
    var clickAble=true;
    viewer.screenSpaceEventHandler.setInputAction(function (e) {
        var ray=viewer.camera.getPickRay(e.position);
        var c=viewer.scene.globe.pick(ray,viewer.scene);
        if (!clickAble||!bmgl.defined(c))return;
        clickAble=false;
        setTimeout(()=>{
            clickAble=true;
        },1000);
        c=bmgl.Cartographic.fromCartesian(c);
        startPoint.lng=bmgl.Math.toDegrees(c.longitude)
        startPoint.lat=bmgl.Math.toDegrees(c.latitude);
        drawLine();
    },bmgl.ScreenSpaceEventType.LEFT_CLICK);
    var pointArr=[];
    viewer.scene.globe.depthTestAgainstTerrain=true;
    setTimeout(function () {
        //1秒后开始画视角
        drawLine();
    },1000);
    function drawLine() {
        pointArr.map(v=>v.remove());
        pointArr.length=0;
        var viewHeight = 1.5;//视角高度
        var cartographicCenter = bmgl.Cartographic.fromDegrees(startPoint.lng, startPoint.lat);
        var cartesianCenterH0 = bmgl.Cartesian3.fromRadians(cartographicCenter.longitude, cartographicCenter.latitude);
        var cartesianPointH0 = bmgl.Cartesian3.fromDegrees(startPoint.lng+0.02, startPoint.lat+0.01);
        var ab = bmgl.Cartesian3.distance(cartesianCenterH0, cartesianPointH0);
        var eopt = {};
        eopt.semiMinorAxis = ab;
        eopt.semiMajorAxis = ab;
        eopt.rotation = 0;
        eopt.center = cartesianCenterH0;
        eopt.granularity = Math.PI / 20;//间隔
        var ellipse = computeEllipseEdgePositions(eopt);
        for (var i = 0; i < ellipse.outerPositions.length; i += 3) {
            //逐条计算可视域
            var cartesian = new bmgl.Cartesian3(ellipse.outerPositions[i], ellipse.outerPositions[i + 1], ellipse.outerPositions[i + 2]);
            var cartographic = bmgl.Cartographic.fromCartesian(cartesian);
            var deltaRadian = 0.00005 * Math.PI / 180.0;
            var cartographicArr = InterpolateLineCartographic(cartographicCenter, cartographic, deltaRadian);
            getTerrain(cartographicArr,terrainData=>{
                try {
                    if (terrainData.length > 0) {
                        var preVisible = true;
                        var cartesiansLine = [];
                        var colors = [];
                        for (var j = 1; j < terrainData.length; j++) {
                            //逐点计算可见性
                            var visible = true;//该点可见性
                            if (j > 1) {
                                var cartographicCenterHV = new bmgl.Cartographic(terrainData[0].longitude, terrainData[0].latitude, terrainData[0].height + viewHeight);
                                //
                                if (preVisible) {
                                    //
                                    var curPoint = InterpolateIndexLineHeightCartographic(cartographicCenterHV, terrainData[j], j, j - 1);
                                    if (curPoint.height >= terrainData[j - 1].height) {
                                        preVisible = true;
                                        visible = true;
                                    } else {
                                        preVisible = false;
                                        visible = false;
                                    }
                                } else {
                                    //插值到当前
                                    var curPointArr = Interpolate2IndexLineHeightCartographic(cartographicCenterHV, terrainData[j], j, j - 1);
                                    for (var k = 0; k < curPointArr.length; k++) {
                                        if (curPointArr[k].height >= terrainData[k].height) {
                                            preVisible = true;
                                            visible = true;
                                        } else {
                                            preVisible = false;
                                            visible = false;
                                            break;
                                        }
                                    }
                                }
                            }
                            var cartesianTemp = bmgl.Cartesian3.fromRadians(terrainData[j].longitude, terrainData[j].latitude, terrainData[j].height + 0.10);
                            cartesiansLine.push(cartesianTemp);
                            //绘制点
                            if (visible) {
                                colors.push(0);
                                colors.push(0);
                                colors.push(1);
                                colors.push(1);
                            } else {
                                colors.push(1);
                                colors.push(0);
                                colors.push(0);
                                colors.push(1);
                            }
                        }
                        //绘制结果
                        var pointsKSY = new PrimitivePoints({ 'viewer': viewer, 'Cartesians': cartesiansLine, 'Colors': colors });
                        pointArr.push(pointsKSY);
                    } else {
                        console.log("高程异常!");
                    }
                }catch (e) {
                    console.log(e);
                }
            })
        }
    }


    function getTerrain(arr,callback) {
        bmgl.sampleTerrainMostDetailed(viewer.terrainProvider,arr).then(data=>{
            callback(data);
        })
    }

    /**
     * options.semiMinorAxis:短半轴
     * options.semiMajorAxis:长半轴
     * options.rotation:旋转角度 弧度
     * options.center:中心点 笛卡尔坐标
     * options.granularity:粒度 弧度
     * Returns an array of positions that make up the ellipse.
     * @private
     */
    function  computeEllipseEdgePositions(options) {
        var unitPosScratch = new bmgl.Cartesian3();
        var eastVecScratch = new bmgl.Cartesian3();
        var northVecScratch = new bmgl.Cartesian3();
        var scratchCartesian1 = new bmgl.Cartesian3();
        var semiMinorAxis = options.semiMinorAxis;
        var semiMajorAxis = options.semiMajorAxis;
        var rotation = options.rotation;//法线
        var center = options.center;
        var granularity = options.granularity && (typeof options.granularity === "number") ? options.granularity : (Math.PI / 180.0);// 角度间隔
        if (granularity > Math.PI / 12.0) { granularity = Math.PI / 12.0; }//最小分24
        if (granularity < Math.PI / 180.0) { granularity = Math.PI / 180.0; }//最大分360
        var aSqr = semiMinorAxis * semiMinorAxis;
        var bSqr = semiMajorAxis * semiMajorAxis;
        var ab = semiMajorAxis * semiMinorAxis;
        var mag = bmgl.Cartesian3.magnitude(center);//
        var unitPos = bmgl.Cartesian3.normalize(center, unitPosScratch);
        var eastVec = bmgl.Cartesian3.cross(bmgl.Cartesian3.UNIT_Z, center, eastVecScratch);
        eastVec = bmgl.Cartesian3.normalize(eastVec, eastVec);
        var northVec = bmgl.Cartesian3.cross(unitPos, eastVec, northVecScratch);
        var numPts = Math.ceil(bmgl.Math.PI*2 / granularity);
        var deltaTheta = granularity;
        var theta = 0;

        var position = scratchCartesian1;
        var i;
        var outerIndex = 0;
        var outerPositions = [];
        for (i = 0; i < numPts; i++) {
            theta = i * deltaTheta;
            position = pointOnEllipsoid(theta, rotation, northVec, eastVec, aSqr, ab, bSqr, mag, unitPos, position);

            outerPositions[outerIndex++] = position.x;
            outerPositions[outerIndex++] = position.y;
            outerPositions[outerIndex++] = position.z;
        }

        var r = {};
        r.numPts = numPts;
        r.outerPositions = outerPositions;
        return r;
    };
    /*
        线段插值
        经纬度坐标插值
        Cartographic start.longitude start.latitude 单位:弧度
        return [Cartographic,...]
        */
     function InterpolateLineCartographic(start, end, _Delta) {
        if (start && end) { } else { return null; }
        if (start.longitude && start.latitude && end.longitude && end.latitude) { } else { return null; }
        var result = [];
        //开始点
        result.push(new bmgl.Cartographic(start.longitude, start.latitude));
        var interval = Math.sqrt(Math.pow((end.longitude - start.longitude), 2) + Math.pow((end.latitude - start.latitude), 2));
        var delta = _Delta && (typeof _Delta === 'number') ? _Delta : DeltaRadian;
        if (interval <= delta) {
            //小于最小间隔
            result.push(new bmgl.Cartographic(end.longitude, end.latitude));
            return result;
        } else {
            var num = interval / delta;
            var stepLon = (end.longitude - start.longitude) / num;
            var stepLat = (end.latitude - start.latitude) / num;
            for (var i = 0; i < num; i++) {
                var lon = start.longitude + (i + 1) * stepLon;
                var lat = start.latitude + (i + 1) * stepLat;
                result.push(new bmgl.Cartographic(lon, lat));//与最后一个点有偏差
            }
            result.push(new bmgl.Cartographic(end.longitude, end.latitude, end.height));
        }
        return result;
    }
    function InterpolateIndexLineHeightCartographic(start, end, num, index) {
        if (start && end) { } else { return null; }
        if (start.longitude && start.latitude && end.longitude && end.latitude) { } else { return null; }
        //var delta = _Delta && (typeof _Delta === 'number') ? _Delta : DeltaRadian;
        var stepLon = (end.longitude - start.longitude) / num;
        var stepLat = (end.latitude - start.latitude) / num;
        var stepHeight = (end.height - start.height) / num;
        var lon = start.longitude + index * stepLon;
        var lat = start.latitude + index * stepLat;
        var hieght = start.height + index * stepHeight;
        var result = new bmgl.Cartographic(lon, lat, hieght);
        return result;
    }
    
    /*
       线段插值
       经纬度高程插值
       Cartographic start.longitude start.latitude 单位:弧度 start.height 高程单位m
       num:分总段数  传入数组长度-1
       index:获取到第index点的所有插值 0点是开始点
       return [Cartographic,...]
       */
    function Interpolate2IndexLineHeightCartographic(start, end, num, curIndex) {
        if (start && end) { } else { return null; }
        if (start.longitude && start.latitude && end.longitude && end.latitude) { } else { return null; }
        var result = [];
        result.push(new bmgl.Cartographic(start.longitude, start.latitude, start.height));
        var stepLon = (end.longitude - start.longitude) / num;
        var stepLat = (end.latitude - start.latitude) / num;
        var stepHeight = (end.height - start.height) / num;
        for (var i = 0; i < curIndex; i++) {
            var lon = start.longitude + (i + 1) * stepLon;
            var lat = start.latitude + (i + 1) * stepLat;
            var hieght = start.height + (i + 1) * stepHeight;
            result.push(new bmgl.Cartographic(lon, lat, hieght));
        }
        //result.push(new bmgl.Cartographic(end.longitude, end.latitude, end.height));
        return result;
    }
    function pointOnEllipsoid(theta, rotation, northVec, eastVec, aSqr, ab, bSqr, mag, unitPos, result) {
        var rotAxis = new bmgl.Cartesian3();
        var tempVec = new bmgl.Cartesian3();
        var unitQuat = new bmgl.Quaternion();
        var rotMtx = new bmgl.Matrix3();

        var azimuth = theta + rotation;

        bmgl.Cartesian3.multiplyByScalar(eastVec, Math.cos(azimuth), rotAxis);
        bmgl.Cartesian3.multiplyByScalar(northVec, Math.sin(azimuth), tempVec);
        bmgl.Cartesian3.add(rotAxis, tempVec, rotAxis);

        var cosThetaSquared = Math.cos(theta);
        cosThetaSquared = cosThetaSquared * cosThetaSquared;

        var sinThetaSquared = Math.sin(theta);
        sinThetaSquared = sinThetaSquared * sinThetaSquared;

        var radius = ab / Math.sqrt(bSqr * cosThetaSquared + aSqr * sinThetaSquared);
        var angle = radius / mag;

        // Create the quaternion to rotate the position vector to the boundary of the ellipse.
        bmgl.Quaternion.fromAxisAngle(rotAxis, angle, unitQuat);
        bmgl.Matrix3.fromQuaternion(unitQuat, rotMtx);

        bmgl.Matrix3.multiplyByVector(rotMtx, unitPos, result);
        bmgl.Cartesian3.normalize(result, result);
        bmgl.Cartesian3.multiplyByScalar(result, mag, result);
        return result;
    }

    var PrimitivePoints = (
        function () {
            var vertexShader;
            var fragmentShader;
            var geometry;
            var appearance;
            var viewer;
            function _(options) {
                viewer = options.viewer;
                vertexShader = VSPolylie();
                fragmentShader = FSPolyline();
                if (options.Cartesians && options.Cartesians.length >= 2) {
                    var postionsTemp = [];
                    var colorsTemp = [];
                    var indicesTesm = [];
                    if (options.Colors && options.Colors.length === options.Cartesians.length * 4) {
                        for (var i = 0; i < options.Cartesians.length; i++) {
                            postionsTemp.push(options.Cartesians[i].x);
                            postionsTemp.push(options.Cartesians[i].y);
                            postionsTemp.push(options.Cartesians[i].z);
                        }
                        colorsTemp = options.Colors;
                    } else {
                        for (var i = 0; i < options.Cartesians.length; i++) {
                            postionsTemp.push(options.Cartesians[i].x);
                            postionsTemp.push(options.Cartesians[i].y);
                            postionsTemp.push(options.Cartesians[i].z);
                            //
                            colorsTemp.push(0.0);
                            colorsTemp.push(0.0);
                            colorsTemp.push(1.0);
                            colorsTemp.push(1.0);
                        }
                    }
                    for (var i = 0; i < options.Cartesians.length; i++) {
                        indicesTesm.push(i);
                    }
                    this.positionArr = new Float64Array(postionsTemp);
                    this.colorArr = new Float32Array(colorsTemp);
                    this.indiceArr = new Uint16Array(indicesTesm);

                } else { // if (options.Cartesians && options.Cartesians.length >= 2) {
                    var p1 = bmgl.Cartesian3.fromDegrees(0, 0, -10);
                    var p2 = bmgl.Cartesian3.fromDegrees(0, 0.001, -10);
                    this.positionArr = new Float64Array([
                        p1.x, p1.y, p1.z,
                        p2.x, p2.y, p2.z
                    ]);
                    //默认蓝色
                    this.colorArr = new Float32Array([
                        0.0, 0.0, 1.0, 1.0,
                        0.0, 0.0, 1.0, 1.0
                    ]);
                    this.indiceArr = new Uint16Array([0, 1]);
                }

                geometry = CreateGeometry(this.positionArr, this.colorArr, this.indiceArr);
                appearance = CreateAppearence(fragmentShader, vertexShader);

                this.primitive = viewer.scene.primitives.add(new bmgl.Primitive({
                    geometryInstances: new bmgl.GeometryInstance({
                        geometry: geometry
                    }),
                    appearance: appearance,
                    asynchronous: false
                }));
            }

            function CreateGeometry(positions, colors, indices) {
                return new bmgl.Geometry({
                    attributes: {
                        position: new bmgl.GeometryAttribute({
                            componentDatatype: bmgl.ComponentDatatype.DOUBLE,
                            componentsPerAttribute: 3,
                            values: positions
                        }),
                        color: new bmgl.GeometryAttribute({
                            componentDatatype: bmgl.ComponentDatatype.FLOAT,
                            componentsPerAttribute: 4,
                            values: colors
                        })
                    },
                    indices: indices,
                    primitiveType: bmgl.PrimitiveType.POINTS,
                    boundingSphere: bmgl.BoundingSphere.fromVertices(positions)
                });
            }

            function CreateAppearence(fs, vs) {
                return new bmgl.Appearance({
                    renderState: {
                        blending: bmgl.BlendingState.PRE_MULTIPLIED_ALPHA_BLEND,
                        depthTest: { enabled: true },
                        depthMask: true
                    },
                    fragmentShaderSource: fs,
                    vertexShaderSource: vs
                });
            }

            function VSPolylie() {
                return "attribute vec3 position3DHigh;\
                        attribute vec3 position3DLow;\
                        attribute vec4 color;\
                        varying vec4 v_color;\
                        attribute float batchId;\
                        void main()\
                        {\
                            vec4 p = czm_computePosition();\
                            v_color =color;\
                            p = czm_modelViewProjectionRelativeToEye * p;\
                            gl_Position = p;\
                            gl_PointSize=4.0;\
                        }\
                        ";
            }

            function FSPolyline() {
                return "varying vec4 v_color;\
            void main()\
            {\
                 float d = distance(gl_PointCoord, vec2(0.5,0.5));\
                 if(d < 0.5){\
                    gl_FragColor = v_color;\
                 }else{\
                    discard;\
                 }\
            }\
            ";
            }

            _.prototype.remove = function () {
                if (this.primitive != null) {
                    viewer.scene.primitives.remove(this.primitive);
                    this.primitive = null;
                }
            }
            _.prototype.updateCartesianPosition = function (cartesians) {
                if (this.primitive != null) {
                    viewer.scene.primitives.remove(this.primitive);
                    if (cartesians && cartesians.length < 2) { return; }
                    if (cartesians.length === this.positionArr.length / 3) {
                        var p1 = cartesians[0];
                        var p2 = cartesians[1];
                        this.positionArr = new Float64Array([
                            p1.x, p1.y, p1.z,
                            p2.x, p2.y, p2.z
                        ]);
                        geometry = CreateGeometry(this.positionArr, this.colorArr, this.indiceArr);
                    } else {
                        //默认蓝色
                        var postionsTemp = [];
                        var colorsTemp = [];
                        var indicesTesm = [];
                        for (var i = 0; i < cartesians.length; i++) {
                            postionsTemp.push(cartesians[i].x);
                            postionsTemp.push(cartesians[i].y);
                            postionsTemp.push(cartesians[i].z);

                            colorsTemp.push(0.0);
                            colorsTemp.push(0.0);
                            colorsTemp.push(1.0);
                            colorsTemp.push(1.0);
                        }
                        for (var i = 0; i < cartesians.length; i++) {
                            indicesTesm.push(i);
                        }
                        this.positionArr = new Float64Array(postionsTemp);
                        this.colorArr = new Float32Array(colorsTemp);
                        this.indiceArr = new Uint16Array(indicesTesm);

                        geometry = CreateGeometry(this.positionArr, this.colorArr, this.indiceArr);
                        appearance = CreateAppearence(fragmentShader, vertexShader);
                    }

                    this.primitive = viewer.scene.primitives.add(new bmgl.Primitive({
                        geometryInstances: new bmgl.GeometryInstance({
                            geometry: geometry
                        }),
                        appearance: appearance,
                        asynchronous: false
                    }));
                } else { return; }
            }
            _.prototype.updateCartesianPositionColor = function (cartesians, colors) {
                if (colors.length === cartesians.length * 4) { } else { return; }
                if (this.primitive != null) {
                    viewer.scene.primitives.remove(this.primitive);
                    if (cartesians && cartesians.length < 2) { return; }
                    if (cartesians.length === this.positionArr.length / 3) {
                        var p1 = cartesians[0];
                        var p2 = cartesians[1];
                        this.positionArr = new Float64Array([
                            p1.x, p1.y, p1.z,
                            p2.x, p2.y, p2.z
                        ]);

                        this.colorArr = new Float32Array(colors);

                        geometry = CreateGeometry(this.positionArr, this.colorArr, this.indiceArr);
                    } else {
                        var postionsTemp = [];
                        var indicesTesm = [];

                        for (var i = 0; i < cartesians.length; i++) {
                            postionsTemp.push(cartesians[i].x);
                            postionsTemp.push(cartesians[i].y);
                            postionsTemp.push(cartesians[i].z);
                        }
                        for (var i = 0; i < cartesians.length; i++) {
                            indicesTesm.push(i);
                        }
                        this.positionArr = new Float64Array(postionsTemp);
                        this.colorArr = new Float32Array(colors);
                        this.indiceArr = new Uint16Array(indicesTesm);

                        geometry = CreateGeometry(this.positionArr, this.colorArr, this.indiceArr);
                        appearance = CreateAppearence(fragmentShader, vertexShader);
                    }

                    this.primitive = viewer.scene.primitives.add(new bmgl.Primitive({
                        geometryInstances: new bmgl.GeometryInstance({
                            geometry: geometry
                        }),
                        appearance: appearance,
                        asynchronous: false
                    }));
                } else { return; }
            }
            return _;
        })();
</script>
</body>
</html>
                                                                                            
源码