Skip to content

Commit b47cc42

Browse files
committed
Generalize computeBoundingSphere / Box methods
1 parent feb1565 commit b47cc42

File tree

2 files changed

+86
-9
lines changed

2 files changed

+86
-9
lines changed

js/src/_base/Preview.js

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ var Renderable = require('./Renderable');
99
var RenderableView = Renderable.RenderableView;
1010
var RenderableModel = Renderable.RenderableModel;
1111
var OrbitControls = require("../examples/controls/OrbitControls.js").OrbitControls;
12+
var utils = require('./utils.js');
1213

1314

1415
var BLACK = new THREE.Color('black');
@@ -78,14 +79,6 @@ function lookAtSphere(camera, center, radius) {
7879
}
7980

8081
// TODO: Make this available as a general utility somewhere?
81-
function computeSceneBoundingSphere(scene) {
82-
// FIXME: The Box3.setFromObject implementation is not great,
83-
// replace with something that reuses bounding box computations
84-
// of the underlying objects
85-
const box = new THREE.Box3();
86-
box.setFromObject(scene);
87-
return box.getBoundingSphere();
88-
}
8982

9083

9184
var PreviewView = RenderableView.extend({
@@ -208,7 +201,7 @@ var PreviewView = RenderableView.extend({
208201

209202
resetCamera: function() {
210203
// Compute bounding sphere for entire scene
211-
const sphere = computeSceneBoundingSphere(this.scene);
204+
const sphere = utils.computeBoundingSphere(this.scene);
212205

213206
// Update camera to include bounding sphere
214207
lookAtSphere(this.camera, sphere.center, sphere.radius);

js/src/_base/utils.js

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,89 @@
11

22
var widgets = require("@jupyter-widgets/base");
3+
var THREE = require('three');
34

45

6+
/**
7+
* Compute the box bounding all objects in a scene graph.
8+
*
9+
* Returns a unity box if no relevant objects were found.
10+
*/
11+
var computeBoundingBox = function() {
12+
var objectBoundingBox = new THREE.Box3();
13+
14+
return function computeBoundingBox(scene) {
15+
var boundingBox = new THREE.Box3();
16+
scene.traverseVisible(function (object) {
17+
if (object.geometry) {
18+
object.geometry.computeBoundingBox();
19+
objectBoundingBox.copy(object.geometry.boundingBox);
20+
objectBoundingBox.applyMatrix4(object.matrixWorld);
21+
boundingBox.union(objectBoundingBox);
22+
}
23+
});
24+
if (boundingBox.isEmpty()) {
25+
boundingBox.min.set(-1, -1, -1);
26+
boundingBox.max.set(1, 1, 1);
27+
}
28+
return boundingBox;
29+
}
30+
}();
31+
32+
33+
/**
34+
* Compute the sphere bounding all objects in a scene graph.
35+
*
36+
* Note: This is based on the bounding spheres of the individual objects
37+
* in the scene, and not the set of all points in the scene, and will
38+
* therefore not be optimal.
39+
*
40+
* Returns a unity sphere if no relevant objects were found.
41+
*/
42+
var computeBoundingSphere = function() {
43+
var objectBoundingSphere = new THREE.Sphere();
44+
var vAB = new THREE.Vector3();
45+
var d, rmin, rmax, rA, rB;
46+
return function computeBoundingSphere(scene) {
47+
// Current bounding sphere:
48+
var boundingSphere = null;
49+
scene.traverseVisible(function (object) {
50+
if (object.geometry) {
51+
object.geometry.computeBoundingSphere();
52+
if (boundingSphere === null) {
53+
// First sphere found, store it
54+
boundingSphere = object.geometry.boundingSphere.clone();
55+
boundingSphere.applyMatrix4(object.matrixWorld);
56+
return; // continue traverse
57+
}
58+
objectBoundingSphere.copy(object.geometry.boundingSphere);
59+
objectBoundingSphere.applyMatrix4(object.matrixWorld);
60+
61+
rA = boundingSphere.radius;
62+
rB = objectBoundingSphere.radius;
63+
rmin = Math.min(rA, rB);
64+
rmax = Math.max(rA, rB);
65+
66+
vAB.subVectors(objectBoundingSphere.center, boundingSphere.center);
67+
d = vAB.length();
68+
if (d + rmin < rmax) {
69+
// Smallest sphere contained within largest
70+
if (rB > rA) {
71+
boundingSphere.copy(objectBoundingSphere);
72+
}
73+
return; // continue traverse
74+
}
75+
76+
// Calculate new bounding-sphere:
77+
boundingSphere.radius = 0.5 * (rA + rB + d);
78+
boundingSphere.center.addScaledVector(vAB, 0.5 + rB);
79+
}
80+
});
81+
if (boundingSphere === null) {
82+
return new THREE.Sphere(new THREE.Vector3(), 1);
83+
}
84+
return boundingSphere;
85+
}
86+
}();
587

688
/**
789
* Work around for notebook issue #2730.
@@ -81,4 +163,6 @@ var createModel = function(constructor, widget_manager, obj) {
81163

82164
module.exports = {
83165
createModel: createModel,
166+
computeBoundingSphere: computeBoundingSphere,
167+
computeBoundingBox: computeBoundingBox,
84168
}

0 commit comments

Comments
 (0)