cesium包围盒的创建和显示尝试
0. 包围盒的概念
- 点集、面、实体都可以用一个长方形将它们包围起来,应用方面有很多,比如碰撞检测,最大最小边界确定。
- cesium提供了两种三种包围盒、一种包围球的计算方式,分别是
AxisAlignedBoundingBox、 BoundingRectangle、 BoundingSphere、 和OrientedBoundingBox
1. cesium中的包围盒的简单解释
BoundingRectangle
由角、宽度和高度构成的包围框。
虽然是盒子有高度,但它主要用于二维点集、矩形的包围盒创建,高度可以任意指定,无法包围空间上z值不同的点。
BoundingSphere
有中心和半径的包围球。
包围球又很多方法,文档比较详细,本文主要讨论包围盒的显示,故不作太多说明。
AxisAlignedBoundingBox
从沿x、y和z轴的最小和最大点创建AxisAlignedBoundingBox的实例。
参数分别是center、maximum 、minimum
分别表示包围盒中心、最大位置点、最小位置点
OrientedBoundingBox
创建一个OrientedBoundingBox实例。 在许多情况下,它可以提供比BoundingSphere或AxisAlignedBoundingBox更紧密的(tighter)包围盒。 一个物体的OrientedBoundingBox是一个封闭的、凸的长方体。
参数是center、halfAxes
分别表示包围盒中心点、仿射矩阵。
2. 包围盒显示
分别采用轴向包围盒AxisAlignedBoundingBox
和朝向包围盒OrientedBoundingBox
,通过一些点集来计算包围盒,最后显示。
- 采用
AxisAlignedBoundingBox
,利用viewer.entities.add()
添加实体
let boundingBox = Cesium.AxisAlignedBoundingBox.fromPoints(this._positions, new Cesium.AxisAlignedBoundingBox())
let dimensions = Cesium.Cartesian3.subtract(boundingBox.maximum, boundingBox.minimum, new Cesium.Cartesian3())
this._delegate.position = center;
this._delegate.box.dimensions = dimensions;
this.overlayLayer.add(this.delegate)
其中_positions
是世界笛卡尔坐标,最后显示的包围盒存在问题,不能完全包围,如下图
2. 采用 AxisAlignedBoundingBox
,利用scene.primitives.add()
添加实体,利用Cesium.BoxGeometry.fromAxisAlignedBoundingBox()
函数将AxisAlignedBoundingBox
转化为BoxGeometry
核心代码是:
let ms = this._buildModelCoor(this._positions[0])
let m = this._xlBox._modelMatrix
let boundingBox = Cesium.AxisAlignedBoundingBox.fromPoints(ms, new Cesium.AxisAlignedBoundingBox())
let newBox = Cesium.BoxGeometry.fromAxisAlignedBoundingBox(boundingBox);
viewer.scene.primitives.add(new Cesium.Primitive({
geometryInstances : new Cesium.GeometryInstance({
geometry :newBox,
modelMatrix : m,
id : 'ellipsoid',
attributes : {
color : Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.AQUA.withAlpha(0.5))
},
}),
appearance : new Cesium.PerInstanceColorAppearance({
flat : true,
})
}))
可以看到这种方法显示出的包围盒是正确的。
OrientedBoundingBox
使用viewer.entities.add()
添加
有一个问题想了好久,类OrientedBoundingBox
中的halfAxes
的理解,应该是包围盒的长度、宽度、和高度。
但是halfAxes
又是一个3*3的矩阵,我的理解是矩阵的每一列的平方根就是包围盒每一段的边长
主要显示代码:
this.boundingBox = Cesium.OrientedBoundingBox.fromPoints(this._positions, Cesium.OrientedBoundingBox());
let dimensions = Cesium.Matrix3.getScale(this.boundingBox.halfAxes , new Cesium.Cartesian3());
Cesium.Cartesian3.multiplyByScalar(dimensions, 2 , dimensions);
let center = this._xlBox.computerWorldPosition(this.boundingBox.center, this._xlBox._modelMatrix)
this._delegate.position = center;
this._delegate.box.dimensions = dimensions;
return this
使用Cesium.Matrix3.getScale()
函数获取长、宽、高
加载出的结果有错误,如下
3. 包围盒显示纠正
上述三种显示方法,只有一种是正确的,就是通过在一点上建立空间直角坐标系,将所有点都转化到这个坐标系下,后构建包围盒,进行显示。
- 测试一,
AxisAlignedBoundingBox
构成包围盒
加载代码:
let ms = this._buildModelCoor(this._positions[0])
let boundingBox = Cesium.AxisAlignedBoundingBox.fromPoints(ms, new Cesium.AxisAlignedBoundingBox())
let dimensions = Cesium.Cartesian3.subtract(boundingBox.maximum, boundingBox.minimum, new Cesium.Cartesian3())
let center = this._xlBox.computerWorldPosition(boundingBox.center, this._xlBox._modelMatrix)
this._delegate.position = center;
this._delegate.box.dimensions = dimensions;
return this
结果正确
- 测试二,
OrientedBoundingBox
构成包围盒
加载代码:
let ms = this._buildModelCoor(this._positions[0])
this.boundingBox = Cesium.OrientedBoundingBox.fromPoints(ms, Cesium.OrientedBoundingBox());
let dimensions = Cesium.Matrix3.getScale(this.boundingBox.halfAxes , new Cesium.Cartesian3());
Cesium.Cartesian3.multiplyByScalar(dimensions, 2 , dimensions);
let center = this._xlBox.computerWorldPosition(this.boundingBox.center, this._xlBox._modelMatrix)
this._delegate.position = center;
this._delegate.box.dimensions = dimensions;
return this
结果错误
4. 结论
- 尝试了许多次,需要将包围盒转化成某点的特定坐标系才能正确显示。
AxisAlignedBoundingBox
的primitive
、entity
两种加载方法都可以使用,且都加载正确。OrientedBoundingBox
尝试不成功,无论是否将点集转化为特定坐标系与否,总是显示错误,之后有时间弄清楚后再更新,若有大神知道怎么回事,还望告知。(后续研读朝向包围盒计算论文再更新)