版本简介:
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
1. Cesium的使用
-
场景初始化与渲染
function onload(Cesium) {
Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI...';
var viewer = new Cesium.Viewer('Container');
viewer.scenePromise.then(function(scene){
init(Cesium, scene, viewer);
});
}
Cesium.Ion.defaultAccessToken
: Cesium Ion是用于访问Cesium中的3D地形、卫星影像等服务。在这里,初始化时提供了Ion的访问密钥。Cesium.Viewer
: 创建Cesium的3D场景,并绑定到Container
这个div元素。这个viewer负责加载Cesium的地形、影像等基础资源。scenePromise
:Cesium.Viewer
会返回一个scene
对象,表示当前Cesium的场景。之后我们通过init
函数进一步对场景进行设置。
-
影像图层添加
var labelImagery = new Cesium.TiandituImageryProvider({ mapStyle: Cesium.TiandituMapsStyle.CIA_C, token: '04e319956d6385dcdf25089104eb8b5b' });
- 这里使用了Cesium的
TiandituImageryProvider
来添加天地图中文标注图层,配合Cesium的地形渲染,使地图更加丰富。
- 这里使用了Cesium的
-
光源和环境光设置
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);
- 设置了环境光和定向光(
DirectionalLight
)以增强场景的光照效果。
- 设置了环境光和定向光(
-
天际线分析和场景状态判断
if (!scene.pickPositionSupported) { alert('不支持深度纹理,天际线分析功能无法使用!'); }
- 使用Cesium的
pickPositionSupported
来判断浏览器是否支持深度纹理,这对天际线分析是必须的。
- 使用Cesium的
2. SuperMap的使用
-
天际线分析功能(Skyline)
var skyline = new SuperMap3D.Skyline(scene);
- 使用
SuperMap3D.Skyline
来初始化SuperMap的天际线分析工具,这是SuperMap提供的高级空间分析功能,用于分析城市建筑物等的天际线轮廓。
- 使用
-
绘制限高体
var polygonHandler = new SuperMap3D.DrawHandler(viewer, SuperMap3D.DrawMode.Polygon); polygonHandler.drawEvt.addEventListener(function (result) { skyline.removeLimitbody("limitBody"); var polygon = result.object; polygon.show = false; var pos = polygon.positions; var positions = []; for (var i = 0, len = pos.length; i < len; i++) { var cartographic = Ceisum.Cartographic.fromCartesian(pos[i]); var longitude = Ceisum.Math.toDegrees(cartographic.longitude); var latitude = Ceisum.Math.toDegrees(cartographic.latitude); positions.push([longitude, latitude]); } positions = unique(positions); var arr = []; for (var i = 0, len = positions.length; i < len; i++) { arr.push(positions[i][0]); arr.push(positions[i][1]); } skyline.addLimitbody({ position: arr, name: "limitBody" }); });
- 这里使用了
SuperMap3D.DrawHandler
来进行多边形绘制,完成后调用skyline.addLimitbody
来添加限高体,这是SuperMap提供的另一个分析功能。
- 这里使用了
-
加载S3M场景
var promise = scene.open(URL_CONFIG.SCENE_CBD); SuperMap3D.when(promise, function (layers) { scene.camera.setView({ destination: SuperMap3D.Cartesian3.fromDegrees(116.4465, 39.9066, 47.9552), orientation: { heading: 0.34395448573153864, pitch: -0.0538346996932666, roll: 6.2831853071795685 } }); for (var i = 0; i < layers.length; i++) { layers[i].selectEnabled = false; } }, function (e) { var title = '加载SCP失败,请检查网络连接状态或者url地址是否正确?'; widget.showErrorPanel(title, undefined, e); });
- 使用
scene.open()
加载SuperMap的S3M模型数据,并在加载完成后通过Cesium的setView
来调整相机位置。
- 使用
3. 前端按钮交互
-
通过按钮与用户交互,调用不同的功能。
-
提取天际线
$('#chooseView').click(function () { var cartographic = scene.camera.positionCartographic; var longitude = Ceisum.Math.toDegrees(cartographic.longitude); var latitude = Ceisum.Math.toDegrees(cartographic.latitude); var height = cartographic.height; skyline.viewPosition = [longitude, latitude, height]; skyline.pitch = Ceisum.Math.toDegrees(scene.camera.pitch); skyline.direction = Ceisum.Math.toDegrees(scene.camera.heading); skyline.radius = 10000; skyline.build(); });
- 点击
chooseView
按钮后,会获取当前相机的经纬度和高度,并使用SuperMap的skyline
对象来构建天际线分析。
- 点击
-
绘制限高体
$('#setLimitBody').click(function () { if (polygonHandler.active) { return; } polygonHandler.activate(); });
- 通过点击
setLimitBody
按钮,激活多边形绘制功能(由SuperMap提供),绘制完成后会自动调用skyline.addLimitbody
来添加限高体。
- 通过点击
-
清除
$('#clear').click(function () { viewer.entities.removeAll(); skyline.clear(); polygonHandler.clear(); });
- 通过
clear
按钮清除场景中的所有实体(Cesium)和天际线分析数据(SuperMap)。
- 通过
-
二维天际线
$('#getSkyline2D').click(function () { skyline.getSkyline2DAsync().then(object => { var myChart = echarts.init(document.getElementById("map")); var option = { ... }; myChart.setOption(option); }); });
- 获取天际线的二维数据(由SuperMap提供),并使用
Echarts
库在前端绘制图表。
- 获取天际线的二维数据(由SuperMap提供),并使用
6.代码部分:
<!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">
<link href="../css/skyline.css" rel="stylesheet">
<script type="text/javascript" src="../js/jquery.min.js"></script>
<script type="text/javascript" src="../js/echarts.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="chooseView" class="button black">提取天际线</button>
<button type="button" id="getSkyline2D" class="button black">二维天际线</button>
<button type="button" id="setLimitBody" class="button black">绘制限高体</button>
<button type="button" id="getSkylineArea" class="button black">拉伸闭合体</button>
<button type="button" id="clear" class="button black">清除</button>
</div>
<div id="map" style="position : absolute;right : 5%; bottom : 5%;width:450px;height:400px;"></div>
<script type="text/javascript">
function onload(Cesium) {
Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJlZjRiNDQyMi1mZDBhLTQxYTAtYWU4NC1hZDY4YzhjNWU3ZGEiLCJpZCI6MjMyMDI3LCJpYXQiOjE3MjI1MDEzMTd9.3lFzziTrt3ggC3pfiVmNRbSidI52EL4CsOqWKgYxHkM'
var viewer = new Cesium.Viewer('Container');
viewer.scenePromise.then(function(scene){
init(Cesium, scene, viewer);
});
}
function init(Cesium, scene, viewer) {
viewer.resolutionScale = window.devicePixelRatio;
var labelImagery = new Cesium.TiandituImageryProvider({
mapStyle: Cesium.TiandituMapsStyle.CIA_C,//天地图全球中文注记服务
token: '04e319956d6385dcdf25089104eb8b5b' //由天地图官网申请的密钥
});
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);
if (!scene.pickPositionSupported) {
alert('不支持深度纹理,天际线分析功能无法使用!');
}
var skyline = new SuperMap3D.Skyline(scene);//创建天际线分析对象
var polygonHandler = new SuperMap3D.DrawHandler(viewer, SuperMap3D.DrawMode.Polygon);
var widget = viewer.Widget;
try {
var promise = scene.open(URL_CONFIG.SCENE_CBD);
SuperMap3D.when(promise, function (layers) {
scene.camera.setView({//图层加载完成,设置相机位置
destination: SuperMap3D.Cartesian3.fromDegrees(116.4465, 39.9066, 47.9552),
orientation: {
heading: 0.34395448573153864,
pitch: -0.0538346996932666,
roll: 6.2831853071795685
}
});
for (var i = 0; i < layers.length; i++) {
layers[i].selectEnabled = false;
}
}, 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);
}
}
try {
// 绘制多边形结束的回调事件
polygonHandler.drawEvt.addEventListener(function (result) {
// 清除之前的限高体对象
skyline.removeLimitbody("limitBody");
var polygon = result.object;
polygon.show = false;
var pos = polygon.positions;
var positions = [];
// 遍历多边形,取出所有点
for (var i = 0, len = pos.length; i < len; i++) {
//转化为经纬度,并加入至临时数组
var cartographic = Cesium.Cartographic.fromCartesian(pos[i]);
var longitude = Cesium.Math.toDegrees(cartographic.longitude);
var latitude = Cesium.Math.toDegrees(cartographic.latitude);
positions.push([longitude, latitude]);
}
//去除重复点
positions = unique(positions);
var arr = [];
//再次遍历转化为接口所需的数组格式
for (var i = 0, len = positions.length; i < len; i++) {
arr.push(positions[i][0]);
arr.push(positions[i][1]);
}
//添加限高体对象
skyline.addLimitbody({
position: arr,
name: "limitBody"
});
});
//去重函数
unique = function (arr) {
var res = [];
var json = {};
for (var i = 0; i < arr.length; i++) {
if (!json[arr[i]]) {
res.push(arr[i]);
json[arr[i]] = 1;
}
}
return res;
};
function mousestyle() { //鼠标样式
viewer.enableCursorStyle = false;
viewer._element.style.cursor = '';
$('body').removeClass('drawCur').addClass('drawCur');
}
$('#chooseView').click(function () {
var cartographic = scene.camera.positionCartographic;
var longitude = Cesium.Math.toDegrees(cartographic.longitude);
var latitude = Cesium.Math.toDegrees(cartographic.latitude);
var height = cartographic.height;
//天际线分析的视口位置设置成当前相机位置
skyline.viewPosition = [longitude, latitude, height];
//设置俯仰和方向
skyline.pitch = Ceisum.Math.toDegrees(scene.camera.pitch);
skyline.direction = Ceisum.Math.toDegrees(scene.camera.heading);
skyline.radius = 10000; // 天际线分析半径设置为10000米
skyline.build();
$("#getSkyline2D").show();
$("#setLimitBody").show();
$("#map").hide();
});
$('#setLimitBody').click(function () {
mousestyle();
if (polygonHandler.active) {
return;
}
polygonHandler.activate();
});
$('#clear').click(function () {
viewer.entities.removeAll();
skyline.clear();
polygonHandler.clear();
$("#map").hide();
});
$('#getSkylineArea').click(function () {
var cartographic = scene.camera.positionCartographic;
var longitude = SuperMap3D.Math.toDegrees(cartographic.longitude);
var latitude = SuperMap3D.Math.toDegrees(cartographic.latitude);
var height = cartographic.height;
var points = skyline.getSkyline3D();
var pointArr = new Array();
var cameraPoint = SuperMap3D.Cartesian3.fromDegrees(longitude, latitude, height);
pointArr.push(cameraPoint);
for (var i = 0; i < points.x.length; i++) {
var point = SuperMap3D.Cartesian3.fromDegrees(points.x[i], points.y[i], points.z[i]);
pointArr.push(point);
}
viewer.entities.add({
polygon: {
extrudedHeight: 30,
hierarchy: pointArr,
perPositionHeight: true,
material: SuperMap3D.Color.ORANGE.withAlpha(1.0)
}
})
});
$('#getSkyline2D').click(function () {
//获取二维天际线对象,兼容webgpu
skyline.getSkyline2DAsync().then(object=>{
//用echarts绘制二维天际线
var myChart = echarts.init(document.getElementById("map"));
var option = {
backgroundColor: "rgba(73,139,156,0.9)",
title: {
text: "二维天际线"
},
tooltip: {
trigger: "axis"
},
calculable: true,
xAxis: [
{
type: "category",
boundaryGap: false,
data: object.x,
show: false
}
],
yAxis: [
{
type: "value",
min: 0,
max: 1
}
],
series: [
{
name: "",
type: "line",
data: object.y
}
]
};
myChart.setOption(option);
$("#map").show();
});
});
}
catch (e) {
if (scene.context.depthTexture) {
swal("天际线分析", "该浏览器不支持深度纹理检测", "warning");
}
}
$("#toolbar").show();
$('#loadingbar').remove();
}
if (typeof SuperMap3D !== 'undefined') {
window.startupCalled = true;
onload(SuperMap3D);
}
</script>
</body>
</html>