Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Crash when 3D Tiles bounding region has 0 volume #7945

Merged
merged 16 commits into from
Sep 19, 2019
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ Change Log
* 3D Tiles geometric error now scales with transform. [#8182](https://github.com/AnalyticalGraphicsInc/cesium/pull/8182)
* Fixed per-feature post processing from sometimes selecting the wrong feature. [#7929](https://github.com/AnalyticalGraphicsInc/cesium/pull/7929)
* Fixed labels not showing for individual entities in data sources when clustering is enabled. [#6087](https://github.com/AnalyticalGraphicsInc/cesium/issues/6087)
* Fixed a crash for 3D Tiles that have zero volume. [#7945](https://github.com/AnalyticalGraphicsInc/cesium/pull/7945)


### 1.61 - 2019-09-03

Expand Down
5 changes: 5 additions & 0 deletions Source/Scene/TileBoundingSphere.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ define([
'../Core/GeometryInstance',
'../Core/Matrix4',
'../Core/SphereOutlineGeometry',
'../Core/Math',
'./PerInstanceColorAppearance',
'./Primitive'
], function(
Expand All @@ -18,6 +19,7 @@ define([
GeometryInstance,
Matrix4,
SphereOutlineGeometry,
CesiumMath,
PerInstanceColorAppearance,
Primitive) {
'use strict';
Expand All @@ -33,6 +35,9 @@ define([
* @private
*/
function TileBoundingSphere(center, radius) {
if (radius === 0) {
radius = CesiumMath.EPSILON7;
}
this._boundingSphere = new BoundingSphere(center, radius);
}

Expand Down
67 changes: 65 additions & 2 deletions Source/Scene/TileOrientedBoundingBox.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ define([
'../Core/Matrix3',
'../Core/Matrix4',
'../Core/OrientedBoundingBox',
'../Core/Math',
'./PerInstanceColorAppearance',
'./Primitive'
], function(
Expand All @@ -22,10 +23,70 @@ define([
Matrix3,
Matrix4,
OrientedBoundingBox,
CesiumMath,
PerInstanceColorAppearance,
Primitive) {
'use strict';

var scratchU = new Cartesian3();
var scratchV = new Cartesian3();
var scratchW = new Cartesian3();
var scratchCartesian = new Cartesian3();

function computeMissingVector(a, b, result) {
result = Cartesian3.cross(a, b, result);
var magnitude = Cartesian3.magnitude(result);
return Cartesian3.multiplyByScalar(result, CesiumMath.EPSILON7 / magnitude, result);
}

function findOrthogonalVector(a, result) {
var temp = Cartesian3.normalize(a, scratchCartesian);
var b = Cartesian3.equalsEpsilon(temp, Cartesian3.UNIT_X, CesiumMath.EPSILON6) ? Cartesian3.UNIT_Y : Cartesian3.UNIT_X;
return computeMissingVector(a, b, result);
}

function checkHalfAxes(halfAxes) {
var u = Matrix3.getColumn(halfAxes, 0, scratchU);
var v = Matrix3.getColumn(halfAxes, 1, scratchV);
var w = Matrix3.getColumn(halfAxes, 2, scratchW);

var uZero = Cartesian3.equals(u, Cartesian3.ZERO);
var vZero = Cartesian3.equals(v, Cartesian3.ZERO);
var wZero = Cartesian3.equals(w, Cartesian3.ZERO);

if (!uZero && !vZero && !wZero) {
return halfAxes;
}
if (uZero && vZero && wZero) {
halfAxes[0] = CesiumMath.EPSILON7;
halfAxes[4] = CesiumMath.EPSILON7;
halfAxes[8] = CesiumMath.EPSILON7;
return halfAxes;
}
if (uZero && !vZero && !wZero) {
u = computeMissingVector(v, w, u);
} else if (!uZero && vZero && !wZero) {
v = computeMissingVector(u, w, v);
} else if (!uZero && !vZero && wZero) {
w = computeMissingVector(v, u, w);
} else if (!uZero) {
v = findOrthogonalVector(u, v);
w = computeMissingVector(v, u, w);
} else if (!vZero) {
u = findOrthogonalVector(v, u);
w = computeMissingVector(v, u, w);
} else if (!wZero) {
u = findOrthogonalVector(w, u);
v = computeMissingVector(w, u, v);
}

Matrix3.setColumn(halfAxes, 0, u, halfAxes);
Matrix3.setColumn(halfAxes, 1, v, halfAxes);
Matrix3.setColumn(halfAxes, 2, w, halfAxes);

return halfAxes;
}

/**
* A tile bounding volume specified as an oriented bounding box.
* @alias TileOrientedBoundingBox
Expand All @@ -39,6 +100,7 @@ define([
* @private
*/
function TileOrientedBoundingBox(center, halfAxes) {
halfAxes = checkHalfAxes(halfAxes);
this._orientedBoundingBox = new OrientedBoundingBox(center, halfAxes);
this._boundingSphere = BoundingSphere.fromOrientedBoundingBox(this._orientedBoundingBox);
}
Expand Down Expand Up @@ -111,6 +173,7 @@ define([
*/
TileOrientedBoundingBox.prototype.update = function(center, halfAxes) {
Cartesian3.clone(center, this._orientedBoundingBox.center);
halfAxes = checkHalfAxes(halfAxes);
Matrix3.clone(halfAxes, this._orientedBoundingBox.halfAxes);
BoundingSphere.fromOrientedBoundingBox(this._orientedBoundingBox, this._boundingSphere);
};
Expand All @@ -128,8 +191,8 @@ define([

var geometry = new BoxOutlineGeometry({
// Make a 2x2x2 cube
minimum: new Cartesian3(-1.0, -1.0, -1.0),
maximum: new Cartesian3(1.0, 1.0, 1.0)
minimum : new Cartesian3(-1.0, -1.0, -1.0),
maximum : new Cartesian3(1.0, 1.0, 1.0)
});
var modelMatrix = Matrix4.fromRotationTranslation(this.boundingVolume.halfAxes, this.boundingVolume.center);
var instance = new GeometryInstance({
Expand Down
27 changes: 27 additions & 0 deletions Specs/Scene/Cesium3DTileSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,33 @@ describe('Scene/Cesium3DTile', function() {
expect(tile.boundingVolume).toEqual(obb);
});

it('does not crash for bounding box with 0 volume', function() {
// Create a copy of the tile with bounding box.
var tileWithBoundingBox0Volume = JSON.parse(JSON.stringify(tileWithBoundingBox));
// Generate all the combinations of missing axes.
var boxes = [];
for (var x = 0; x < 2; ++x) {
for (var y = 0; y < 2; ++y) {
for (var z = 0; z < 2; ++z) {
boxes.push([0.0, 0.0, 0.0, x, 0.0, 0.0, 0.0, y, 0.0, 0.0, 0.0, z]);
}
}
}

for (var i = 0; i < boxes.length; ++i) {
var box = boxes[i];

tileWithBoundingBox0Volume.boundingVolume.box = box;

var tile = new Cesium3DTile(mockTileset, '/some_url', tileWithBoundingBox0Volume, undefined);
expect(tile.boundingVolume).toBeDefined();
var center = new Cartesian3(box[0], box[1], box[2]);
var halfAxes = Matrix3.fromArray(box, 3);
var obb = new TileOrientedBoundingBox(center, halfAxes);
expect(tile.boundingVolume).toEqual(obb);
}
});

it('can have a content oriented bounding box', function() {
var box = tileWithContentBoundingBox.boundingVolume.box;
var tile = new Cesium3DTile(mockTileset, '/some_url', tileWithContentBoundingBox, undefined);
Expand Down