Bounding cell of stl object in three.js file

Good afternoon everyone

I came across several posts on this topic, but no solution will work. I have an object that I am loading using STLLoader in three.js for which I would like to get a bounding box.

    // Add stl objects and a name
function addSTLObject(url, name) {
    var loader = new THREE.STLLoader();
    loader.load(url, function (geometry) {

        var material = new THREE.MeshPhongMaterial({ color: 0xff5533 });
        var mesh = new THREE.Mesh(geometry, material);
        // To scale element, use:
        // mesh.scale.set(0.01, 0.01, 0.01);
        // Add a name to the object to find it if it needs to be removed
        mesh.name = name;
        mesh.position.x = 0;
        mesh.position.y = 0;
        mesh.position.z = 0;

        scene.add(mesh);
    });
}

      

and i load this object like this:

addSTLObject('model/cases/iphone5.stl', 'phone-model');
var phoneModelAdded = scene.getObjectByName('phone-model', true);

      

I have now tried the solutions suggested here: https://github.com/mrdoob/three.js/issues/3471 and here Any way to get the bounding box from a 3.js Object3D?

var bbox = new THREE.Box3().setFromObject(phoneModelAdded);

var geometry = phoneModel.children[0].children[0].geometry;
geometry.computeBoundingBox();

      

While the first solution gives me the error "Unable to read property 'updateMatrixWorld' from undefined", the second gives me no error, but does nothing, and if I try to access the property "geometry" it doesn't exist.

Does anyone have a working solution? Any help is appreciated.

Have a nice day!

EDIT

        // Add stl objects and a name
function addSTLObject(url, name) {
    var bbox;
    var loader = new THREE.STLLoader();
    loader.load(url, function (geometry) {

        var material = new THREE.MeshPhongMaterial({ color: 0xff5533 });
        var mesh = new THREE.Mesh(geometry, material);
        // To scale element, use:
        // mesh.scale.set(0.01, 0.01, 0.01);
        // Add a name to the object to find it if it needs to be removed
        mesh.name = name;
        mesh.position.x = 0;
        mesh.position.y = 0;
        mesh.position.z = 0;

        bbox = new THREE.Box3().setFromObject(mesh);

        scene.add(mesh);

        return bbox;
    });
}

      

and back

var bbox = addSTLObject('model/cases/iphone5.stl', 'phone-model');
    scene.add(bbox);

      

Error: "THREE.Object3D.add: object is not an instance of THREE.Object3D"

EDIT 2:

var bbox, bboxComputed = false;

    function addSTLObject(url, name) {
    var bbox;
    var loader = new THREE.STLLoader();
    loader.load(url, function (geometry) {

        var material = new THREE.MeshPhongMaterial({ color: 0xff5533 });
        var mesh = new THREE.Mesh(geometry, material);
        // To scale element, use:
        // mesh.scale.set(0.01, 0.01, 0.01);
        // Add a name to the object to find it if it needs to be removed
        mesh.name = name;
        mesh.position.x = 0;
        mesh.position.y = 0;
        mesh.position.z = 0;

        bbox = new THREE.BoundingBoxHelper(mesh);
        bbox.update();
        bboxComputed = true;

        scene.add(mesh);
    });

}

addSTLObject('model/cases/iphone5.stl', 'phone-model');
    var myInterval = setInterval( function(){
        if( bboxComputed ) {
            alert( bbox.box.min, bbox.box.max, bbox.box.size() );
            scene.add(bbox);
            clearInterval( myInterval );
            bboxComputed = false;
        }
    }, 100 );

      

It won't work.

EDIT 3: I was trying to set up a function that will have everything I need and return an object with all the information calculated:

    function calculateSTLProperties(url, name) {
    var STLObject, STLbbox, STLComputed = false, STLGeometry;

    var loader = new THREE.STLLoader();
    loader.load(url, function (geometry) {

        var material = new THREE.MeshPhongMaterial({ color: 0xff5533 });
        var mesh = new THREE.Mesh(geometry, material);
        // To scale element, use:
        // mesh.scale.set(0.01, 0.01, 0.01);
        // Add a name to the object to find it if it needs to be removed
        mesh.name = name;
        mesh.position.x = 0;
        mesh.position.y = 0;
        mesh.position.z = 0;

        // Compute a bounding box for the element
        STLbbox = new THREE.BoundingBoxHelper(mesh);
        STLbbox.update();

        // Get the geometry of the case
        STLGeometry = geometry;
        STLComputed = true;
    });

    // Set an interval to wait for the corresponding bounding box and geometry to be computed
    var myInterval = setInterval( function(){
        if( STLComputed ) {
        STLObject = {
            "geometry" : STLGeometry,
            "bbox" : STLbbox,
            "x" : STLbbox.box.size().x,
            "y" : STLbbox.box.size().y,
            "z" : STLbbox.box.size().z
        };

        clearInterval( myInterval );
        bboxComputed = false;

        }
    }, 100 );

    return STLObject;
}

      

Unfortunately, somehow the object fails and I end up getting "undefined" when trying to store it:

var STLObjectLoaded = calculateSTLProperties('model/cases/iphone5.stl', 'phone-model');
    console.log(STLObjectLoaded);

      

What am I missing?

+3


source to share


1 answer


Loading the model is asynchronous, so all calculations must be done after loading the model. Add a callback that gets called when the model is loaded and adds a call there to bbox. The way you do it, the call scene.getObjectByName()

is made with an empty object, which you are checking as well ("if I try to access the" geometry "property it says it doesn't exist")

Update:

Using:

var bbox = new THREE.BoundingBoxHelper( mesh ); bbox.update();
scene.add( bbox );

      

from within the function loader.load()

.

The call setFromObject()

only creates the bounding box, not the geometry for the bbox.

Update II

If you want to bbox

be available outside of your function loader.load()

, you will need to use a global variable



var bboxComputed = false;

      

which you set to true right after calculating bbox inside your function loader.load()

:

scene.add( bbox );
bboxComputed = true;

      

Then basically instead of using:

console.log( bbox.box.min, bbox.box.max, bbox.box.size() );

      

you would use something like:

var myInterval = setInterval( function(){
    if( bboxComputed ) {
        console.log( bbox.box.min, bbox.box.max, bbox.box.size() );
        clearInterval( myInterval );
    }
}, 100 );

      

I set the delay to 0.1 seconds, and when it is bbox

finally calculated, I clear the interval so that it doesn't run forever.

+1


source







All Articles