I'm working on a modeling tool that lets you directly manipulate meshes. For instance, you can grab a face and drag it around. The user's perception of the "face" could be of more than one coplanar triangle. For instance, the top "face" of a cube would actually be two triangles that get dragged together as one square.
To accomplish this, I'd like to collect all coplanar, adjacent faces to any particular triangle for use when dragging. I've looked at Simplifier, as well as this post as examples, but I want to retain the underlying triangles, not reduce/remove them.
In the good ol' days, you'd build an edge model ala Mantlya, where you could walk each edge to see adjacent faces and check normals.
I was hoping there might be some code already written somewhere for THREEJS that groups coplanar triangles together. If I write this from scratch, the best algorithm I can think of is O(n^2), something like:
- Build edges hash (both directions) by walking all vertices of all faces. Each entry is an array of 2 face pointers. You only need to do this step once when a mesh is created or modified.
- When user picks a face to manipulate, create empty evaluation stack and put picked face into that stack. Also, create empty coplanar face array.
- Pop face off evaluation stack, and walk edges of that face. Look up all faces adjacent to that edge in the edges hash. If face is coplanar, push that face onto evaluation stack and store in coplanar face array.
- Repeat steps 3-4 until evaluation stack is empty.
When this algorithm finishes, you should have an array of all faces coplanar and adjacent to the face you start with. But it seems relatively inefficient to me.
Any and all suggestions/pointers welcomed!
Your idea works.
I added an angle threshold so you can grab slightly non-coplanar topography.I had to make an onEvent to allow for an indeterminate recursion time. It should be modified to put vertexHash in mesh.userData instead.
//edit. I've updated the class to utilize a clamp parameter that allows you to clamp the maxAngle to the original face when set to true. When set to false it will compare each face to next face.
Usage is simple:
I added the class to someone else's fiddle and it works fine. http://jsfiddle.net/fnuaw44r/
I updated the fiddle to use a clamp option: http://jsfiddle.net/ta0g3mLc/
I imagine its terribly inefficient as you suggest, but it depends on the mesh. I added a "pendingRecursive" variable. So long as it's not equal to zero you could put up a gif and remove it when the value is zero again.
It's a starting point anyways. I am sure someone clever could toss through the faces without a nested for loop.