Delineating the Boundaries of an stl Object in three.js

Greetings to all,

I have been encountering numerous discussions on this subject, yet none of the proposed solutions seem to work for me. I am currently working with an object that is loaded using the STLLoader in three.js, and I need to obtain its bounding box.

    // Function to add STL objects along with 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 the element, use:
        // mesh.scale.set(0.01, 0.01, 0.01);
        // Assign a name to the object for easy identification
        mesh.name = name;
        mesh.position.x = 0;
        mesh.position.y = 0;
        mesh.position.z = 0;

        scene.add(mesh);
    });
}

This is how I load the object:

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

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

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

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

However, the initial solution returns an error stating "Cannot read property 'updateMatrixWorld' of undefined", while the second solution does not display any errors but does not perform as expected either. When trying to access the "geometry" property, it claims that it does not exist.

If anyone has a functional solution, I would greatly appreciate your assistance.

Wishing you a pleasant day!

UPDATE:

        // Function to add STL objects along with 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 the element, use:
        // mesh.scale.set(0.01, 0.01, 0.01);
        // Assign a name to the object for easy identification
        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;
    });
}

Followed by:

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

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

UPDATE 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 the element, use:
        // mesh.scale.set(0.01, 0.01, 0.01);
        // Assign a name to the object for easy identification
        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 );

This approach fails to yield the desired outcome.

UPDATE 3: I attempted to devise a function that encompasses all necessary operations and returns an object containing all pertinent information:

    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 the element, use:
        // mesh.scale.set(0.01, 0.01, 0.01);
        // Assign a name to the object for easy identification
        mesh.name = name;
        mesh.position.x = 0;
        mesh.position.y = 0;
        mesh.position.z = 0;

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

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

    // Utilize an interval to wait until the corresponding bounding box and geometry are 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, there seems to be an issue with passing the object through, resulting in a final output of "undefined" when attempting to save it:

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

What might I be overlooking?

Answer №1

Ensure that all computations are done after the model has finished loading, as model loading is asynchronous. Insert a callback function to handle actions after the model has loaded, including the call to the bbox. Currently, the scene.getObjectByName() is being called with an empty object, leading to verification issues ("if I try accessing the "geometry" property it says that it doesn't exist")

Latest Update:

Add the following code snippet inside the loader.load() function:

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

The setFromObject() function only generates the bounding box and not the geometry for the bbox.

Updated Information II

If you wish to access the bbox beyond the loader.load() function, consider using a global variable:

var bboxComputed = false;

Set this variable to true immediately after calculating the bbox within your loader.load() function:

scene.add( bbox );
bboxComputed = true;

In your main section, replace the existing code snippet:

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

with something like the following:

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

A slight delay of 0.1 second is set before checking if the bbox has been computed, ensuring the interval does not run indefinitely once it's calculated.

Answer №2

Starting from three.js R125, the recommended approach for loading STL files is through the loadAsync method, which is now integrated into three.js:

https://threejs.org/docs/#api/en/loaders/Loader.loadAsync

This method returns a promise. You can then utilize 'then' to access the geometry of the STL file and create the mesh. Alternatively, you can also opt for a traditional callback similar to previous solutions, or utilize an async/await structure. However, I believe that the example provided below using the built-in three.js method offers the simplest solution. The code snippet explains how to store the geometry in a global variable once the promise is fulfilled and the STL file is successfully loaded:

// Declare global variables for bounding boxes
let bbox;

const loader = new STLLoader();
const promise = loader.loadAsync('model1.stl');
promise.then(function ( geometry ) {
  const material = new THREE.MeshPhongMaterial();
  const mesh = new THREE.Mesh( geometry, material );
  mesh.geometry.computeBoundingBox();
  bbox = mesh.geometry.boundingBox;
  scene.add( mesh );
  buildScene();
  console.log('STL file loaded!');
}).catch(failureCallback);

function failureCallback(){
  console.log('Failed to load STL file!');
}

function buildScene() {
  console.log('STL file loaded, proceed with building the scene');
  // Access the bounding box of the STL mesh
  console.log(bbox);
  // Continue building your scene...
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the best way to say hello using jQuery?

I need some assistance with a task that involves entering my name into an input field, clicking a button, and having an h1 tag display below the input saying Hello (my name)! Unfortunately, I am struggling to figure out how to achieve this. Below is the H ...

What is the best way to input an HTML element into AngularJS code?

I am looking to integrate the html element into my angularjs code. Within my HTML, I have elements such as data-form-selector='#linechart_general_form' and data-url="{% url 'horizon:admin:metering:samples'%}" that I need to access withi ...

I noticed that my regular expression is functioning correctly on regex101, but for some reason, it's

My search works perfectly on regex101 using this link: https://regex101.com/r/z8JCpv/1 However, in my Node script, the third matched group array[2] is returning not only the matching text but also everything following it. An example line from the source ...

Having difficulty transferring images from the frontend to Cloudinary or any backend system

My goal is to upload an image from the frontend to Cloudinary for use as a profile picture in my app. Below is the code I am using: import { StyledInput, StyledLabel} from '../FormInputs/styles' import { useState } from 'react' import { ...

Understanding Node.js document object

Hey, I'm currently trying to execute a JavaScript function on the server side using node.js, but I've encountered an issue. The function relies on accessing hidden values within the returned HTML using the document DOM, however, the document obje ...

How to incorporate click and drag feature for rotating a 3D object using vue.js

Whenever I click a button, the rotation function is activated and allows me to rotate an object by hovering over it with my mouse. Now, I want to modify this behavior so that the object rotates only when I click on it and move the mouse (while holding dow ...

"Learn the process of extracting information from a database and exporting it to a CSV file with Angular 2

Currently, I am facing an issue where I need to retrieve data from a database and export it to a CSV file. While I am able to fetch all the data successfully, I am encountering difficulty when trying to fetch data that is in object format as it shows up as ...

I am not enhancing the array's value; rather, I am substituting it

Hey everyone, I'm currently working on extracting an array of Sizes and Colors from an object. The goal is to trigger a handler, clickHandler(), when the input is clicked. However, each time the handler is invoked, the code ends up replacing the value ...

The error message "TypeError Cannot read properties of undefined (reading 'backdrop') - bootstrap v5.2.1 modal" is indicating that there is an

While working with the bootstrap modal, an error has been encountered ( TypeError Cannot read properties of undefined (reading 'backdrop') ), which has been logged in our bug tracker. However, attempts to replicate this error have been unsuccessf ...

Define a new type in Typescript that is equal to another type, but with the added flexibility of having optional

I have 2 categories: category Main = { x: boolean; y: number; z: string } category MainOptions = { x?: boolean; y?: number; z?: string; } In this scenario, MainOptions is designed to include some, none, or all of the attributes that belong to ...

Transferring information from a Form to various web pages using a single JavaScript source file

After successfully creating a basic login page with hardcoded credentials, I faced a challenge. While I could transition to the next page once the user logs in, I struggled to display the username entered on the first page onto the second page. I attempte ...

Encountering Rendering Issues with EJS Post HTML Conversion

After working on a much larger project for over a month, I'm now six hours into troubleshooting and everything is starting to blend together. Prior to switching to EJS, everything was working perfectly. I'm not looking for someone to solve the ...

Alignment issue with Ul dropdown menus and shadow

After stumbling upon a fascinating menu design at this link, I decided to tweak it for center alignment by following the advice on this forum thread. Unfortunately, my efforts have hit a roadblock - the drop down menus aren't aligning as intended and ...

Is it possible to use multiple routes in the same page with Vue-router?

In the process of developing a Vue-based web application that utilizes vue-router in history mode, everything was functioning smoothly for navigating between various pages. However, a new request has been made to open certain pages within a virtual dialogu ...

Place additional text above the export button within Highcharts

Presently, I'm utilizing the Highcharts API here and here to customize the export button for Highcharts. I am attempting to position an ellipsis inside the export button in order to adhere to certain style guidelines. However, due to the limitations o ...

Discovering the differences between input values in HTML when using scripts

I have a code snippet here for an HTML project. The code includes an input field for username and password. I am looking to compare the user's input with a specific value using JavaScript. My question is, what code should be included in the button cli ...

Create a variable and set it equal to the value of a form

I'm having trouble setting a value to a hidden form field that needs to come from a query string parameter. The function that extracts the query string parameter is working properly, but the function that assigns this variable to the hidden form field ...

Using JavaScript, you can filter an array of objects based on a specific search input

I am in the process of implementing a filtering feature for a list using React, but surprisingly, I haven't been able to find any useful resources online to guide me through this common task. Currently, I have an array of users that I need to filter ...

The function to createUserWithEmailAndPassword in firebase.auth() is showing an error as Undefined, indicating it

I am currently studying the user management section of the Firebase documentation var firebase = require('firebase'); // Setting up Firebase firebase.initializeApp({ serviceAccount: "./<mysecreturledittedout>.json", databaseURL: " ...

What is the best approach to dealing with a non-TypeScript project that is requesting the installation of @types for

With the project set up using create-react-app and custom-react-scripts to utilize decorators for MobX, I am aiming to incorporate the react-c3js library for data visualization. Surprisingly, everything is functioning correctly, but there's a warning ...