Add children to a group break traverse method

Hi there!
I would like to traverse the whole scene looking for a certain child (which is actually a grand-child) and then add it to another group in order to change its pivot point (it’s a door).
Here’s my code:

pivot(nome, lato) {
    scene.traverse(child => {
        if (child instanceof THREE.Mesh){
            if (child.name.includes(nome)) {
                let box = new THREE.Box3().setFromObject( child );
                let pivotAnta = new THREE.Group();
                scene.add(pivotAnta);
                if (lato === "sx") {
                    pivotAnta.position.set(box.min.x, 0, box.min.z);
                } else if (lato === "dx") {
                    pivotAnta.position.set(box.max.x, 0, box.min.z);
                } else if (lato === "up") {
                    pivotAnta.position.set(0, box.max.y, boxSX.min.z);
                } else if (lato === "down") {
                    pivotAnta.position.set(0, box.min.y, boxSX.min.z);
                } else {
                    console.log("errore: non hai specificato il lato di apertura")
                }
                let pivotHelper = new THREE.AxesHelper( 500 );
                pivotAnta.attach(pivotHelper);
                pivotAnta.rotation.y = 0;
                pivotAnta.rotation.z = 0;
                pivotAnta.rotation.x = -Math.PI / 2;
                pivotAnta.scale.x = 0.01;
                pivotAnta.scale.y = 0.01;
                pivotAnta.scale.z = 0.01;
                pivotAnta.add(child);
                // console.log("hai collegato "+child.name+" a "+pivotAnta.name);
            } else {
                // console.log(child.name);
            }
        }
    });
},

Now, it works since it comes to the first child that makes the ifs true and then break the traverse saying “TypeError: Cannot read property ‘traverse’ of undefined”.

Can you help me understand why?

Thank you in advance.

Hi!

The offending line is pivotAnta.add(child);. That is what breaks the tree traversal.

You should do for example (before the call to traverse):

var newPivots = [];

Then substitute the offending line with

newPivots.push( { pivot: pivotAnta; child: child } );

Finally, when the traversal has finished, do

for ( var i = 0, n = newPivots.length; i < n; i ++ ) ) {
    newPivots[ i ].pivot.add( newPivots[ i ].child );
}
1 Like

Thank you @yombo!!
It just works!

1 Like

You are welcome :slight_smile:

But… You know why it works, right?

2 Likes

I clearly understand why to use array, give a name to the objects and cycle through it to parent the right children to the right pivots.
What isn’t clear to me is why add child to a parent broke the traverse function. I thought it was conceptually right, but apparently it’s not.
Is there a good reason why or it’s just something to know?

Looking at the Object3D.traverse:

traverse: function ( callback ) {
		callback( this );
		var children = this.children;
		for ( var i = 0, l = children.length; i < l; i ++ ) {
			children[ i ].traverse( callback );
		}
	}

Let’s say a child is processed and added to a new pivot. The key is that it is also removed from its parent. When traverse continues to execute in the parent, the for loop is broken because the children array was altered.

Hence, as a general rule, you can’t modify an object tree structure while you are traversing it.

Happy coding!

3 Likes

What can I say? I learned something thanks to you. It’s amazing to find people that use their time to help others, like you do.
Thanks again, I very much appreciated.
Have a nice day

1 Like

:tada::tada::tada:
I try to teach everytime I have a chance :slight_smile:

1 Like