最近由于公司需要用的superMap相关的技术,本人之前也从未接触过这方面的东西,也是从零开始,边做边学。下面简单对本次项目进行一个技术总结,希望对没有经验的人有所帮助。
SuperMap iClient3D for WebGL 官方文档
http://support.supermap.com.cn:8090/webgl/web/index.html
Viewer是Cesium中用于显示3D场景的组件。它提供了创建和控制3D场景所需的所有基本功能,包括加载3D模型、添加图像覆盖物、设置相机位置和方向、处理用户输入等。
在创建Viewer时,可以指定要使用的HTML元素(例如canvas),该元素将用于呈现3D场景。一旦创建了Viewer对象,就可以通过调用其方法来添加实体、图像覆盖物和其他元素,并对相机进行操作。
new Cesium.Viewer(container, options):是用来创建一个新的 Cesium 视图器(Viewer)实例的构造函数。
container:必需,表示视图器容器元素的ID字符串或HTML元素。
options:{
geocoder: false, // 是否创建右上角的查询按钮(右上第一个)
homeButton: false, // 是否创建 home 按钮(右上第二个)
sceneModePicker: false, // 是否创建右上角的切换地图的按钮(右上第三个)
baseLayerPicker: false, // 是否创建右上角 BaseLayerPicker 小部件(右上第四个)
navigationHelpButton: false, // 是否创建右上角的导航帮助按钮(右上第五个
// vrButton: true, // 是否创建右下角的 VR 按钮,默认值为 true
animation: false, // 是否创建左下角的动画小部件
fullscreenButton: false, // 是否创建右下角全屏按钮
timeline: false, // 是否创建最下方的时间线
infoBox: false, // 点击实体是否展示详情
selectionIndicator: false, // 点击实体是否显示选中样式
// 左下方的 Cesium logo 使用 css 删除
terrainProvider: Cesium.createWorldTerrain(), // 加载地球椭球体
}
三维场景类,所有3D图形对象的容器(HTML canvas)。它是所有三维图形对象和状态的容器,通常不直接创建场景,而是由Widget隐式创建。
scene = viewer.scene
常用方法:
// 打开指定图层资源
scene.open(url, sceneName, options)
scene.open(
url, 必须,服务url 例如 http://{s}/iserver/services/3D-QX20230317-2/rest/realspace
sceneName, //工作空间中有多个场景,需要指定场景名称;设置为undefined,默认打开第一个
options: {
// 用于子域, 例如 ['192.168.2.1:8090', '192.168.2.1:8091']
subdomains: ['t1','t2'],
// 是否自动定位到场景, 默认为true
autoSetView: false
}
)
相机类,它由位置、方向和视锥体定义。 视锥体(viewing frustum)由6个(上、下、左、右、近、远)平面限定,每个平面可 由Cartesian4对象表示,其中x,y和z分量定义垂直于平面的单位向量,w分量是平面距原点/相机位置的距离。
camera = viewer.scene.camera;
常用方法:
// 设置相机位置、方向和变换。
1、camera.setView(options)
camera.setView({
// 相机在WGS84世界坐标系中的最终位置,或是自顶向下视图中可见的矩形区域。
destination : new Cesium.Cartesian3(-1590650.7796661195, 5331299.69368041, 3109890.2682378646),
orientation : {
// 方位角
heading : 1.4092244106070817,
// 俯仰角
pitch : -0.6060137107123218,
// 滚动角
roll : 3.055333763768431e-13
},
// 是否将相机最终位置从世界坐标转换为场景坐标,默认值True。
convert: true
});
// camera.flyTo(target, options): 使相机飞行到指定的目标位置,并设置相应的动画效果和参数。
2、camera.flyTo({
// 相机在WGS84世界坐标系中的最终位置,或是自顶向下视图中可见的矩形区域。
destination: SuperMap3D.Cartesian3.fromDegrees(Number(data.camera.longitude), Number(data.camera.latitude), Number(data.camera.hight)),
orientation: {
// 方位角
heading : 1.4092244106070817,
// 俯仰角
pitch : -0.6060137107123218,
// 滚动角
roll : 3.055333763768431e-13
},
// 动画持续时间
duration: 5,
// 飞行结束后的回调
complete: function () {
}
});
// 监听相机位置
3、 camera.moveEnd.addEventListener
camera.moveEnd.addEventListener(() => {
// 世界坐标系
const result = Cesium.Cartographic.fromCartesian(position)
// 纬度
const latitude = Cesium.Math.toDegrees(result.latitude)
// 经度
const longitude = Cesium.Math.toDegrees(result.longitude)
console.log(camera.position)
})
用的到一些方法说明
1、在地图上创建点线面
// 点实体
var boxEntity = viewer.entities.add({
position: position, // 格式为世界坐标的点位置
point: {
show: ture, // 点是否可见
pixelSize: Number, // 点的大小
color: color, // 点的颜色
outlineClor: color, // 边框颜色
outlineWidth: Number, // 轮廓宽度
},
});
// 线实体
var boxEntity = viewer.entities.add({
polyline: {
show: Boolean, // 线是否可见
positions: positions, // 格式为世界坐标的线位置数组
width: Number, // 线的宽度
material: color, // 线的颜色
clampToGround: Boolean, // 线是否固定在地面
},
});
// 面实体
var boxEntity = viewer.entities.add({
polygon: {
show: Boolean, // 面是否可见
hierarchy: positions, // 格式为世界坐标的面位置数组
height: Number, // 面相对于椭球表面的高度
fill: Boolean, // 面是否有填充
material: color, // 面的填充颜色
outline: Boolean, // 面是否有边框
outlinColor: color, // 边框的颜色
outlineWidth: Number, // 边框的宽度,无论设置为多少宽度始终只会显示为 1
perPositionHeight: Boolean, // 面是否使用每个位置的高度
},
});
2、移除某个绘制实体
var redBox = viewer.entities.add(boxEntity);
viewer.entities.remove(redBox )
3、移除全部绘制实体
viewer.entities.removeAll()
4、更换地图影像
viewer.imageryLayers.addImageryProvider(new Cesium.SuperMapImageryProvider({
url: ‘xxxx’
}));
5、查询所有矢量面数据
function doSqlQuery () {
let _this = this
var sqlParameter= {
// 具体的数据源+数据源列表
"datasetNames" : ["G65结构物数据库:结构物库"],
getFeatureMode : "SQL",
queryParameter : {
// 查询条件,smId 大于 0 的数据
attributeFilter : 'SmID > 0'
}
};
var queryData = JSON.stringify(sqlParameter);
// 要查询的数据服务地址
axios.post('http://183.64.62.11:9490/iserver/services/data-QX20230317/rest/data/featureResults.rjson?returnContent=true', queryData).then(res => {
const data = res.data.features
console.log(data, '所有矢量面详细数据')
})
}
// 具体可参考官方文档中的 查询/属性查询/SQL查询
6、根据具体的坐标查询矢量面
// 根据倾斜摄影ID查询建筑物
function queryByPoint (queryPoint) {
var queryObj = {
"getFeatureMode": "SPATIAL",
"spatialQueryMode": "INTERSECT",
// 要查询的数据源
"datasetNames": ["G65结构物数据库:结构物库"],
"geometry": {
id: 0,
parts: [1],
points: [queryPoint],
type: "POINT"
}
};
var queryObjJSON = JSON.stringify(queryObj); // 转化为JSON字符串作为查询参数
axios.post('http://183.64.62.11:9490/iserver/services/data-QX20230317/rest/data/featureResults.rjson?returnContent=true', queryObjJSON).then(res => {
if (res.data.features.length) {
const data = res.data.features[0]
console.log(data, ''单条矢量数据)
}
})
}
// 具体可参考官方文档中的 查询/属性查询/动态单体化
7、监听鼠标左键单击
var handler = new SuperMap3D.ScreenSpaceEventHandler(scene.canvas);
handler.setInputAction(function (e) {
// 首先移除之前添加标识实体
viewer.entities.removeById('identify-area');
// 获取点击位置笛卡尔坐标
var position = scene.pickPosition(e.position);
scenePosition = position;
// 从笛卡尔坐标获取经纬度
var cartographic = SuperMap3D.Cartographic.fromCartesian(position);
var longitude = SuperMap3D.Math.toDegrees(cartographic.longitude);
var latitude = SuperMap3D.Math.toDegrees(cartographic.latitude);
var queryPoint = { // 查询点对象
x: longitude,
y: latitude
};
console.log(queryPoint , '当前点击的具体方位坐标')
}, SuperMap3D.ScreenSpaceEventType.LEFT_CLICK);
开发的时候在网上用到的一下技术文献
1、不使用fpf文件实现漫游功能。可参考
https://blog.csdn.net/wo_buzhidao/article/details/102681925
如果使用fpf文件实现漫游,vue项目 注意fpf文件需放在public目录下
var fpfUrl = './SampleData/fpf/niaocao.fpf'; // 注意这里的./指的是public目录下
routes.fromFile(fpfUrl);
2、关于在地图上绘制点线面、经纬度坐标转换、具体的有哪些事件可参考
https://blog.csdn.net/m0_49788155/article/details/126966718