i3s定向边界盒(OBB)前端实例化与转换方法
分享
背景知识
首先了解一下i3s的基本概念以及树状结构的介绍。参考资料:https://github.com/Esri/i3s-spec
索引3D场景图层(i3s)格式是一种开放的3D内容交付格式,用于快速流式传输和分发大量3D GIS数据到移动、Web和桌面客户端。ArcGIS场景层和场景服务使用i3s基础结构。场景图层为客户提供了一种结构化的方式来存储和可视化大量3D数据。i3s将信息组织到节点层次结构中,这些节点层次结构包含具有几何,纹理和属性的要素。
树状结构:为确保可视化3D内容时的高性能,数据在空间上分为节点。递归地重复分组过程以创建节点树。给定节点的空间范围包含其所有子级,以创建边界体积层次结构。支持数据的空间规则(例如四叉树)和空间不规则(例如R树)组织。
边界体积定义为最小边界球(MBS)或定向边界盒(OBB)表示。
包围在最小边界球中的3D对象。
包围在smalles边界盒中的3D对象
OBB是更理想的表示形式,建议实现者以OBB格式输出节点边界量。点云配置文件仅支持OBB表示。
为了提供原始数据的可伸缩表示,父节点包含其子级的简化表示,从而创建了Level of Details(LOD)。
空间分布数据的示意图以及将节点递归分组为包围的体积层次结构的示意图
表示为节点树的包围卷层次结构的示例
定向边界盒(Oriented Bounding Box)
定向边界盒(OBB)是紧凑的边界体积表示形式,与它所表示的几何形状紧密匹配。OBB对平移和旋转的不变性使其成为i3s中最佳和默认边界体积表示形式的理想选择。
构造供i3s使用的OBB时,需要基于该层的坐标参考系统(CRS)来考虑实现者两个方面:
为全球场景图层构造OBB
在WGS84地理坐标系的一个i3s图层中,被称为全球场景图层和通过的4326的WKID值标识:
为全局场景层构造OBB时,必须执行以下步骤:
为本地场景图层构造OBB
对于i3s层,具有CRS 其他比4326 WKID值,被称为本地场景图层:
上面的全局场景层用例中描述的OBB构造步骤也适用于此。但是,对于局部场景层,顶点,OBB计算和所得的OBB分量都保留在该层的CRS中。OBB组件的单位与图层的单位相同。
OBB对象的属性
示例
<pre>
定向边界盒(OBB)前端实体类
由于定向边界盒(OBB)决定着模型的整体位置、朝向。为了能让用户在网页端进行场景图层的平移、旋转、改变高度等交互式操作,选择作为定向边界盒(OBB)的前端实体类的条件为:
由于需要实现一个盒(Box),最初尝试使用ArcGIS API for JavaScript的Mesh几何类型的Box来实现Oriented Bounding Box。
<pre>
<pre>
但是发现Mesh的Box盒没有方向属性,无法模拟"定向"边界盒。并且没有现成的交互编辑微件。所以几何类型Mesh是无法胜任这项工作的。
然后,在示例Edit features in 3D with the Editor widget中,我找到了灵感。点要素Graphic在三维中通过设置PointSymbol3D并进一步设置为ObjectSymbol3DLayer可以被编辑、可以作为三维盒可视化。
ObjectSymbol3DLayer
ObjectSymbol3DLayer用于在SceneView中使用带有PointSymbol3D的体积3D形状(例如,球体或圆柱体)来渲染Point几何。列举一下用到的属性。
示例
<pre>
ObjectSymbol3DLayer满足功能需求,接下来就是转换问题了。
i3s obb 转换为ObjectSymbol3DLayer的Graphic
想要将一个obb对象变为前端带有立方体样式的Graphic。分为位置转换、形状转换、角度转换(四元数转欧拉角)。
位置转换
将i3s obb的center(中心点)赋值一个Point对象即可,坐标系取场景图层的坐标系。
<pre>
形状转换
将i3s obb的halfSize(半长)乘2,分别赋值给ObjectSymbol3DLayer的width、depth、height即可。
<pre>
角度转换
将i3s obb的quaternion(四元数)转换为欧拉角再由弧度转角度。赋值给ObjectSymbol3DLayer的tilt、roll、heading。这里引入three.js的四元数转欧拉角的方法。
<pre>
汇总上述三个属性的转换,完整代码如下:
<pre>
ObjectSymbol3DLayer的Graphic转换为i3s obb
在前端对obb进行各种变换(如旋转、平移、拉高)的业务结束后,i3s obb最终还是需要以center、halfSize、quaternion的三个属性入库来持久化obb的变更。这时就需要把Graphic对象反向转换回i3s obb json对象里去。和上面同理但过程相反。
<pre>
总结
将obb在前端实例化,然后持久化,是实现index 3D SceneLayer在前端整体交互操作的前提。后续我还将介绍如何在Web端交互操作i3s obb 实现已发布的场景图层通过web端进行平移旋转拉高等编辑功能。
文章来源:https://www.jianshu.com/p/be15f785c401
背景知识
首先了解一下i3s的基本概念以及树状结构的介绍。参考资料:https://github.com/Esri/i3s-spec
索引3D场景图层(i3s)格式是一种开放的3D内容交付格式,用于快速流式传输和分发大量3D GIS数据到移动、Web和桌面客户端。ArcGIS场景层和场景服务使用i3s基础结构。场景图层为客户提供了一种结构化的方式来存储和可视化大量3D数据。i3s将信息组织到节点层次结构中,这些节点层次结构包含具有几何,纹理和属性的要素。
树状结构:为确保可视化3D内容时的高性能,数据在空间上分为节点。递归地重复分组过程以创建节点树。给定节点的空间范围包含其所有子级,以创建边界体积层次结构。支持数据的空间规则(例如四叉树)和空间不规则(例如R树)组织。
边界体积定义为最小边界球(MBS)或定向边界盒(OBB)表示。
包围在最小边界球中的3D对象。
包围在smalles边界盒中的3D对象
OBB是更理想的表示形式,建议实现者以OBB格式输出节点边界量。点云配置文件仅支持OBB表示。
为了提供原始数据的可伸缩表示,父节点包含其子级的简化表示,从而创建了Level of Details(LOD)。
空间分布数据的示意图以及将节点递归分组为包围的体积层次结构的示意图
表示为节点树的包围卷层次结构的示例
定向边界盒(Oriented Bounding Box)
定向边界盒(OBB)是紧凑的边界体积表示形式,与它所表示的几何形状紧密匹配。OBB对平移和旋转的不变性使其成为i3s中最佳和默认边界体积表示形式的理想选择。
构造供i3s使用的OBB时,需要基于该层的坐标参考系统(CRS)来考虑实现者两个方面:
为全球场景图层构造OBB
在WGS84地理坐标系的一个i3s图层中,被称为全球场景图层和通过的4326的WKID值标识:
- OBB应该在与图层的CRS等效的地心固定地球坐标系(ECEF)中构建。
- OBB的中心部分指定为经度,纬度(以十进制度度)和以米为单位的高程(z)。
- OBB的halfSize组件以米为单位指定。
- 四元数分量参考ECEF坐标系。
为全局场景层构造OBB时,必须执行以下步骤:
- 将感兴趣的顶点投影到ECEF。
- 在ECEF中计算OBB。
- 仅将OBB的中心从ECEF转换回该图层的CRS。
为本地场景图层构造OBB
对于i3s层,具有CRS 其他比4326 WKID值,被称为本地场景图层:
- OBB应该在与图层相同的CRS中构建。
- OBB的center和halfSize组件的单位应为CRS的单位。
- 参考该图层的CRS来指定中心和四元数。
上面的全局场景层用例中描述的OBB构造步骤也适用于此。但是,对于局部场景层,顶点,OBB计算和所得的OBB分量都保留在该层的CRS中。OBB组件的单位与图层的单位相同。
OBB对象的属性
示例
<pre>
/*局部场景图层 (Lambert, Wkid: 2227)*/
{
"center": [
6011913.2692229711,
2117599.0498975096,
441.1241036703866
],
"halfSize": [
100.45386505126953,
91.120384216308594,
426.03338623046875
],
"quaternion": [
0.64432936906814575,
0.76474469900131226,
-0.0020481476094573736,
0.0010012148413807154
]
}
/*全球场景图层 (WSG84, wkid: 4326)*/
{
"center": [
-122.40277014424709,
37.795204290863012,
134.5439856108278
],
"halfSize": [
30.701572418212891,
27.71544075012207,
129.72760009765625
],
"quaternion": [
-0.50688880681991577,
0.74475228786468506,
0.1719556450843811,
0.39854612946510315
]
}
</pre> 定向边界盒(OBB)前端实体类
由于定向边界盒(OBB)决定着模型的整体位置、朝向。为了能让用户在网页端进行场景图层的平移、旋转、改变高度等交互式操作,选择作为定向边界盒(OBB)的前端实体类的条件为:
- 可视化
- 可交互
- 可转换
由于需要实现一个盒(Box),最初尝试使用ArcGIS API for JavaScript的Mesh几何类型的Box来实现Oriented Bounding Box。
<pre>
require(["esri/geometry/Mesh"], function(Mesh) { /* code goes here */ });
</pre> <pre>
// Create a box mesh geometry
var mesh = Mesh.createBox(location, {
size: {
width: 100,
height: 50,
depth: 50
},
material: {
color: "red"
}
});
// Create a graphic and add it to the view
var graphic = new Graphic({
geometry: mesh,
symbol: {
type: "mesh-3d",
symbolLayers: [ { type: "fill" } ]
}
});
</pre> 但是发现Mesh的Box盒没有方向属性,无法模拟"定向"边界盒。并且没有现成的交互编辑微件。所以几何类型Mesh是无法胜任这项工作的。
然后,在示例Edit features in 3D with the Editor widget中,我找到了灵感。点要素Graphic在三维中通过设置PointSymbol3D并进一步设置为ObjectSymbol3DLayer可以被编辑、可以作为三维盒可视化。
ObjectSymbol3DLayer
ObjectSymbol3DLayer用于在SceneView中使用带有PointSymbol3D的体积3D形状(例如,球体或圆柱体)来渲染Point几何。列举一下用到的属性。
示例
<pre>
let graphic = new Graphic({
geometry: point,
symbol: {
type: "point-3d", // autocasts as new PointSymbol3D()
symbolLayers: [{
type: "object", // autocasts as new ObjectSymbol3DLayer()
width: 5, // diameter of the object from east to west in meters
height: 20, // height of the object in meters
depth: 15, // diameter of the object from north to south in meters
resource: { primitive: "cube" },
material: { color: [255,0,0,0.5] }, //0.5 transparent
tilt:45,//around x axis degrees
roll:0,// around the y axis degrees
heading:90,//around z degrees
}]
},
attributes: {
ObjectId: nodepage[i].index,
all:nodepage[i]
}
});
</pre> ObjectSymbol3DLayer满足功能需求,接下来就是转换问题了。
i3s obb 转换为ObjectSymbol3DLayer的Graphic
想要将一个obb对象变为前端带有立方体样式的Graphic。分为位置转换、形状转换、角度转换(四元数转欧拉角)。
位置转换
将i3s obb的center(中心点)赋值一个Point对象即可,坐标系取场景图层的坐标系。
<pre>
var point=new Point({
type: "point", // autocasts as new Point()
x: obb.center[0],
y: obb.center[1],
z: obb.center[2],
spatialReference:{wkid:wkid}
});
</pre> 形状转换
将i3s obb的halfSize(半长)乘2,分别赋值给ObjectSymbol3DLayer的width、depth、height即可。
<pre>
width: obb.halfSize[0]*2, // diameter of the object from east to west in meters
depth: obb.halfSize[1]*2, // diameter of the object from north to south in meters
height: obb.halfSize[2]*2, // height of the object in meters
</pre> 角度转换
将i3s obb的quaternion(四元数)转换为欧拉角再由弧度转角度。赋值给ObjectSymbol3DLayer的tilt、roll、heading。这里引入three.js的四元数转欧拉角的方法。
<pre>
//Three.js四元数转欧拉角
var vectorQuaternion = new THREE.Quaternion();
vectorQuaternion.w = obb.quaternion[3];
vectorQuaternion.x = obb.quaternion[0];
vectorQuaternion.y = obb.quaternion[1];
vectorQuaternion.z = obb.quaternion[2];
var vectorEuler = new THREE.Euler(0, 0, 0, eulerOrder);
vectorEuler.setFromQuaternion(vectorQuaternion, eulerOrder);
//弧度转角度degree的方法
function radToSpecific(radiansIn) {
if (eulerAngleFormat == "Radians") {return radiansIn;}
return THREE.Math.radToDeg(radiansIn);
}
//样式赋值
symbol:{
tilt:radToSpecific(vectorEuler.x),//around x axis
roll:radToSpecific(vectorEuler.y),
heading:radToSpecific(vectorEuler.z),
}
</pre> 汇总上述三个属性的转换,完整代码如下:
<pre>
//将i3s obb转换为Graphic的完整代码
const obb=nodepage[i].obb;
var point=new Point({
type: "point", // autocasts as new Point()
x: obb.center[0],
y: obb.center[1],
z: obb.center[2],
spatialReference:{wkid:wkid}
});
var vectorQuaternion = new THREE.Quaternion();
vectorQuaternion.w = obb.quaternion[3];
vectorQuaternion.x = obb.quaternion[0];
vectorQuaternion.y = obb.quaternion[1];
vectorQuaternion.z = obb.quaternion[2];
var vectorEuler = new THREE.Euler(0, 0, 0, eulerOrder);
vectorEuler.setFromQuaternion(vectorQuaternion, eulerOrder);
if (point !== null) {
let graphic = new Graphic({
geometry: satelliteLoc,
symbol: {
type: "point-3d", // autocasts as new PointSymbol3D()
symbolLayers: [{
type: "object", // autocasts as new ObjectSymbol3DLayer()
width: obb.halfSize[0]*2, // diameter of the object from east to west in meters
height: obb.halfSize[2]*2, // height of the object in meters
depth: obb.halfSize[1]*2, // diameter of the object from north to south in meters
resource: { primitive: "cube" },
material: { color: [255,0,0,0.5] },
tilt:radToSpecific(vectorEuler.x),//around x axis
roll:radToSpecific(vectorEuler.y),// around the y axis
heading:radToSpecific(vectorEuler.z),//around z
}]
},
attributes: {
ObjectId: nodepage[i].index,
all:nodepage[i]
}
});
satelliteLayer.add(graphic);
}
</pre> ObjectSymbol3DLayer的Graphic转换为i3s obb
在前端对obb进行各种变换(如旋转、平移、拉高)的业务结束后,i3s obb最终还是需要以center、halfSize、quaternion的三个属性入库来持久化obb的变更。这时就需要把Graphic对象反向转换回i3s obb json对象里去。和上面同理但过程相反。
<pre>
//角度转弧度方法
function specificToRad(DegreesIn) {
if (eulerAngleFormat == "Radians") {return DegreesIn;}
return THREE.Math.degToRad(DegreesIn);
}
//将名叫grf的graphic赋值给obb
let grf=grfs[k];
let symbolLayer=grf.symbol.symbolLayers.items[0]
let vectorQuaternionresp = new THREE.Quaternion();
let vectorEulerresp = new THREE.Euler(specificToRad(symbolLayer.tilt),
specificToRad(symbolLayer.roll),
specificToRad(symbolLayer.heading),
eulerOrder);
vectorQuaternionresp.setFromEuler(vectorEulerresp);
let obbresp={
"center":[grf.geometry.x, grf.geometry.y, grf.geometry.z],
"halfSize":[symbolLayer.width/2, symbolLayer.height/2, symbolLayer.depth/2],
"quaternion":[vectorQuaternionresp.x, vectorQuaternionresp.y,vectorQuaternionresp.z,vectorQuaternionresp.w]
}
</pre> 总结
将obb在前端实例化,然后持久化,是实现index 3D SceneLayer在前端整体交互操作的前提。后续我还将介绍如何在Web端交互操作i3s obb 实现已发布的场景图层通过web端进行平移旋转拉高等编辑功能。
文章来源:https://www.jianshu.com/p/be15f785c401
0 个评论
相关问题
- 用ArcMap输入7参数,从wgs84坐标系转西安80坐标系,转后误差较大,4米左右,请问这是正常的吗?如何能提高转换精度?
- 如何使用脚本或其他方法,将图层属性中属性域原值内容替换为属性域描述?
- 相同投影带有/无带号的栅格转换,“平移”与“重投影”是不是等效的?
- 基于ArcGIS的CAD数据向GIS数据转换方法
- geometryEngine.simplify方法是做图形简化的吗,简化机制是什么,为什么调用后没效果?
- arcmap中.shp文件如何转换为geojson文件
- 栅格数据集怎样转换为图层啊(通过modelbuilder)??
- ArcMap中提取波段信息的方法
- 投影坐标系转换:Beijing_1954_GK_Zone_19N转换至GCS_China_Geodetic_Coordinate_System_2000
- 如何利用python提取大量点的边界?
- 求助,使用arcgis api for js,有哪些方法可以获取图层的字段别名