CesiumJS+SuperMap3D.js混用实现通视分析

版本简介:

cesium:1.99;Supermap3D:SuperMap iClient JavaScript 11i(2023);

官方下载文档链家:SuperMap技术资源中心|为您提供全面的在线技术服务

示例参考:support.supermap.com.cn:8090/webgl/Cesium/examples/webgl/examples.html#analysis

support.supermap.com.cn:8090/webgl/examples/webgl/examples.html

概述:

代码中将Cesium用于场景渲染、光照效果和鼠标交互处理,而SuperMap3D则负责加载3D场景和实现通视分析功能。这种设计让Cesium负责基础的场景渲染,而SuperMap3D负责更高级的功能实现,例如加载特定的SCP文件和处理视线分析。

1. Cesium负责的部分:

场景的初始化与渲染
javascript 复制代码
Cesium.Ion.defaultAccessToken = 'your token';
var viewer = new Cesium.Viewer('Container', {
    selectionIndicator: false,
	infoBox: false,
	terrainProvider: Cesium.createWorldTerrain()
});

这段使用了Cesium来创建场景。Cesium.Viewer用于初始化Cesium的Viewer,并且指定了不显示选择指示器、信息框,同时使用了Cesium自带的世界地形Cesium.createWorldTerrain()

场景配置与光照
javascript 复制代码
scene.shadowMap.darkness = 1.275; 
scene.hdrEnabled = false;
scene.sun.show = true;
scene.lightSource.ambientLightColor = new Cesium.Color(0.65, 0.65, 0.65, 1);
var position1 = new Cesium.Cartesian3.fromDegrees(116.261209157595, 39.3042238956531, 480);

这段代码使用了Cesium的场景相关配置,包括设置阴影、光照、HDR效果等。另外,通过Cesium.Cartesian3.fromDegrees()将经纬度转换为三维笛卡尔坐标,添加了光源。

鼠标交互处理
javascript 复制代码
var handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
handler.setInputAction(function (e) {
    scene.pickPositionAsync(e.position).then((position)=>{
        addTarget(position);
    });
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);

Cesium的ScreenSpaceEventHandler用于处理鼠标事件,这里通过鼠标点击事件获取场景中的点,并调用pickPositionAsync()来计算点击位置的三维坐标。

2. SuperMap3D负责的部分:

场景加载与配置
javascript 复制代码
var promise = scene.open('http://www.supermapol.com/realspace/services/3D-CBD-2/rest/realspace');
SuperMap3D.when.all(promise, function (layer) {
    scene.camera.setView({
        destination: new SuperMap3D.Cartesian3.fromDegrees(116.44621857300415, 39.899281526734555, 216.7793905027196),
        orientation: {
            heading: 0.41348036210986194,
            pitch: -0.13636490404291735,
            roll: 6.283185307179563
        }
    });
    for (var i = 0; i < layer.length; i++) {
        layer[i].selectEnabled = false;
    }
    sightline.build();
}, function (e) {
    widget.showErrorPanel(title, undefined, e);
});

这里通过SuperMap3D的scene.open()加载了SuperMap的3D场景,并且通过SuperMap3D.Cartesian3.fromDegrees()设定相机视角。加载完成后,调用setView调整相机角度。

通视分析功能
javascript 复制代码
var sightline = new Cesium.Sightline(scene);
sightline.viewPosition = cartographic;
sightline.addTargetPoint({
    position: cartographic,
    name: name
});

虽然Sightline是通过Cesium创建的,但功能实现是通过SuperMap3D管理的,特别是addTargetPoint函数,该函数负责通视分析中添加目标点。

3.具体代码

javascript 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
    <meta name="viewport"
          content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
    <title>通视分析</title>
    <link href="../../public/SuperMap3D/Widgets/widgets.css" rel="stylesheet">
    <link href="../css/pretty.css" rel="stylesheet">
    <script type="text/javascript" src="../js/jquery.min.js"></script>
    <script src="../js/config.js"></script>
    <script type="text/javascript" src="../../public/SuperMap3D/SuperMap3D.js"></script>

    <script src="../../../Cesium-1.99/Build/Cesium/Cesium.js"></script>
	<link href="../../../Cesium-1.99/Build/Cesium/Widgets/widgets.css">
</head>
<body>
<div id="Container"></div>
<div id='loadingbar' class="spinner">
    <div class="spinner-container container1">
        <div class="circle1"></div>
        <div class="circle2"></div>
        <div class="circle3"></div>
        <div class="circle4"></div>
    </div>
    <div class="spinner-container container2">
        <div class="circle1"></div>
        <div class="circle2"></div>
        <div class="circle3"></div>
        <div class="circle4"></div>
    </div>
    <div class="spinner-container container3">
        <div class="circle1"></div>
        <div class="circle2"></div>
        <div class="circle3"></div>
        <div class="circle4"></div>
    </div>
</div>
<div id='toolbar' class="param-container tool-bar">
    <button type="button" id="addViewPoint" class="button black">添加观察点</button>
    <button type="button" id="addTargetPoint" class="button black">添加目标点</button>
    <button type="button" id="clear" class="button black">清除</button>
</div>

<script type="text/javascript">
    function onload(Cesium) {
        Cesium.Ion.defaultAccessToken = 'your token'
        var viewer = new Cesium.Viewer('Container', {
            selectionIndicator: false,
			infoBox: false,
			terrainProvider: Cesium.createWorldTerrain()
        });

        viewer.scenePromise.then(function(scene){
            init(Cesium, scene, viewer);
        });
    }

    function init(Cesium, scene, viewer) {
        viewer.resolutionScale = window.devicePixelRatio;

        if (!viewer.scene.pickPositionSupported) {
            alert('不支持深度纹理,通视分析功能无法使用(无法添加观测点目标点)!');
        }
        $("#toolbar").show();
        $('#loadingbar').remove();
        var scene = viewer.scene;
        scene.shadowMap.darkness = 1.275; //设置第二重烘焙纹理的效果(明暗程度)
        scene.debugShowFramesPerSecond = false;
        scene.hdrEnabled = false;
        scene.sun.show = true;
        // 01设置环境光的强度-新处理CBD场景
        scene.lightSource.ambientLightColor = new Cesium.Color(0.65, 0.65, 0.65, 1);
        // 添加光源
        var position1 = new Cesium.Cartesian3.fromDegrees(116.261209157595, 39.3042238956531, 480);
        //光源方向点

        var targetPosition1 = new Cesium.Cartesian3.fromDegrees(116.261209157595, 39.3042238956531, 430);
        var dirLightOptions = {
            targetPosition: targetPosition1,
            color: new Cesium.Color(1.0, 1.0, 1.0, 1),
            intensity: 0.55
        };
        directionalLight_1 = new Cesium.DirectionalLight(position1, dirLightOptions);
        scene.addLightSource(directionalLight_1);
        var sightline = new Cesium.Sightline(scene);

        var widget = viewer.cesiumWidget;
        try {

            var promise = scene.open('http://www.supermapol.com/realspace/services/3D-CBD-2/rest/realspace');
            SuperMap3D.when.all(promise, function (layer) {
                scene.camera.setView({
                    destination: new SuperMap3D.Cartesian3.fromDegrees(116.44621857300415, 39.899281526734555, 216.7793905027196),
                    orientation: {
                        heading: 0.41348036210986194,
                        pitch: -0.13636490404291735,
                        roll: 6.283185307179563
                    }
                });
                for (var i = 0; i < layer.length; i++) {
                    layer[i].selectEnabled = false;
                }

                sightline.build();
            }, function (e) {
                if (widget._showRenderLoopErrors) {
                    var title = '加载SCP失败,请检查网络连接状态或者url地址是否正确?';
                    widget.showErrorPanel(title, undefined, e);
                }
            });
        } catch (e) {
            if (widget._showRenderLoopErrors) {
                var title = '渲染时发生错误,已停止渲染。';
                widget.showErrorPanel(title, undefined, e);
            }
        }


        var addViewFlag = false;//当前点击状态是否是 添加观察点
        var addTargetFlag = false;//当前点击状态是否是 添加目标点

        var num = 0;//添加的目标点的点号
        var couldRemove = false;//是否能移除目标点

        var handlerPoint = new SuperMap3D.DrawHandler(viewer, SuperMap3D.DrawMode.Point);
        handlerPoint.drawEvt.addEventListener(function (result) {
            //添加观察点
            if (addViewFlag) {
                var point = result.object;
                // point.show = false;
                var position = result.object.position;

                //将获取的点的位置转化成经纬度
                var cartographic = Cartesian2toDegrees(position);

                //设置观察点
                sightline.viewPosition = cartographic;
                addViewFlag = false;
            }
            handlerPoint.deactivate();
        });


        var handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);

        //添加通视点
        function addTarget(CartesianPosition) {
            if (addViewFlag === false && addTargetFlag) {
                num += 1;
                //将获取的点的位置转化成经纬度
                var cartographic = Cartesian2toDegrees(CartesianPosition);
                //添加目标点
                var name = "point" + num;
                var flag = sightline.addTargetPoint({
                    position: cartographic,
                    name: name
                });
                couldRemove = true;
            }
        }

        //笛卡尔转换为经纬度
        function Cartesian2toDegrees(position) {
            var cartographic = Cesium.Cartographic.fromCartesian(position);
            var longitude = Cesium.Math.toDegrees(cartographic.longitude);
            var latitude = Cesium.Math.toDegrees(cartographic.latitude);
            var height = cartographic.height;

            return [longitude, latitude, height];
        }

        $("#addViewPoint").on("click", function () {
            handler.removeInputAction(SuperMap3D.ScreenSpaceEventType.MOUSE_MOVE);
            handler.removeInputAction(SuperMap3D.ScreenSpaceEventType.LEFT_CLICK);
            addViewFlag = true;
            if (handlerPoint.active) {
                return;
            }
            viewer.entities.removeAll();
            if (couldRemove) {
                sightline.removeAllTargetPoint();
            }
            handlerPoint.activate();

            if (addViewFlag || addTargetFlag) {
                viewer.enableCursorStyle = false;
                viewer._element.style.cursor = '';
                $('body').removeClass('drawCur').addClass('drawCur');
            }
        })

        $("#addTargetPoint").on("click", function () {
            addViewFlag = false;
            addTargetFlag = true;

            if (addViewFlag || addTargetFlag) {
                viewer.enableCursorStyle = false;
                viewer._element.style.cursor = '';
                $('body').removeClass('drawCur').addClass('drawCur');
            }

            //鼠标点击事件,添加点
            handler.setInputAction(function (e) {
                scene.pickPositionAsync(e.position).then((position)=>{
                    addTarget(position);
                })
            }, Cesium.ScreenSpaceEventType.LEFT_CLICK);

            //鼠标移动事件,更新点
            handler.setInputAction(function (evt) {
                //鼠标移动,更新最后一次添加的目标点的位置
                scene.pickPositionAsync(evt.endPosition).then((position)=>{
                    if (num > 0) {
                        sightline.removeTargetPoint("point0");

                        var cartographic = Cartesian2toDegrees(position);

                        var flag = sightline.addTargetPoint({
                            position: cartographic,
                            name: "point0"
                        });
                    }
                })
            }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

            //鼠标右键事件,结束
            handler.setInputAction(function () {
                viewer.enableCursorStyle = true;
                $('body').removeClass('drawCur');

                handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE);
                handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
            }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
        
        })


        $("#clear").on("click", function () {
            addViewFlag = false;
            addTargetFlag = false;
            handlerPoint.clear();
            num = 0;
            viewer.entities.removeAll();
            if (couldRemove) {
                sightline.removeAllTargetPoint();
                couldRemove = false;
            }
            viewer.enableCursorStyle = true;
            $('body').removeClass('drawCur');
        })

    }

    if (typeof SuperMap3D !== 'undefined') {
        window.startupCalled = true;
        onload(SuperMap3D);
    }
</script>
</body>
</html>

记得更改成自己的token

4.实现效果展示:

相关推荐
崔庆才丨静觅1 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60612 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了2 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅2 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅2 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅3 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment3 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅3 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊3 小时前
jwt介绍
前端
爱敲代码的小鱼3 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax