Bolt Factory Addon: RemoveDoubles() improvements #2

Open
opened 2024-07-16 16:53:01 +02:00 by Loren Osborn · 1 comment
Contributor

Originally blender/blender-addons#105066 from @sw-tya

System Information
Operating system: Linux Mint 21.2 Victoria base: Ubuntu 22.04 jammy
Graphics card: OpenGL: renderer: Mesa Intel HD Graphics 4000 (IVB GT2) v: 4.2 Mesa 23.3.0

Blender Version
Broken: 3.0.1
Worked: Probably never? It has been 6 years since the last main branch edit to this function, assuming I looked in the right place.

Addon Information
Name: BoltFactory (0, 4, 0)
Author: Aaron Keith

Short description of error
While looking to clean up the non-manifold parts of the Bolt Factory library I have found a couple of things which should be addressed within the RemoveDoubles() function inside createMesh.py :

Duplicate faces are not removed.
The built-in round function does not find similar values depending on the precision.
Function description; it would have been helpful to state, Verts that are not matched to a Face of length 3 or 4 are silently expunged.
Please note that I'm not a software engineer :)
Exact steps for others to reproduce the error
Towards the end of createMesh.py, just before "verts = Scale_Mesh_Verts(verts, GLOBAL_SCALE)" add the following lines:

props.report({'INFO'}, "length of verts before RemoveDoubles: " + str( len(verts) ) )
props.report({'INFO'}, "length of faces before RemoveDoubles: " + str( len(faces) ) )
verts, faces = RemoveDoubles(verts, faces, 4)
props.report({'INFO'}, "length of faces after RemoveDoubles 4DP: " + str( len(faces) ) )
props.report({'INFO'}, "length of verts after RemoveDoubles 4DP: " + str( len(verts) ) )
verts, faces = RemoveDoubles(verts, faces, 5) # Needs to be 5 to fix non-manifold boundary on a M6 nut
props.report({'INFO'}, "length of faces after RemoveDoubles 5DP: " + str( len(faces) ) )
props.report({'INFO'}, "length of verts after RemoveDoubles 5DP: " + str( len(verts) ) )
verts, faces = RemoveDoubles(verts, faces, 6) # 6 to check we got them all
props.report({'INFO'}, "length of faces after RemoveDoubles 6DP: " + str( len(faces) ) )
props.report({'INFO'}, "length of verts after RemoveDoubles 6DP: " + str( len(verts) ) )
if 0: #Set true to capture the output data to the debug window.
props.report({'INFO'}, "Final_Nut_Verts = " + str( (verts) ) )
props.report({'INFO'}, "Final_Nut_Faces = " + str( (faces) ) )
In a new project, enable the Bolt Factory addon if not already setup.
Add -> Mesh -> BoltFactory
OperatorPresent -> m6
Model -> Nut
Type -> Hex
Observe the Info Log window, as see that Verts length of "RemovedDoubles 5DP" is less than RemovedDoubles 4DP.
For me this gives the following:
length of verts after RemoveDoubles 4DP: 1342
length of verts after RemoveDoubles 5DP: 1339

Originally https://projects.blender.org/blender/blender-addons/issues/105066 from @sw-tya System Information Operating system: Linux Mint 21.2 Victoria base: Ubuntu 22.04 jammy Graphics card: OpenGL: renderer: Mesa Intel HD Graphics 4000 (IVB GT2) v: 4.2 Mesa 23.3.0 Blender Version Broken: 3.0.1 Worked: Probably never? It has been 6 years since the last main branch edit to this function, assuming I looked in the right place. Addon Information Name: BoltFactory (0, 4, 0) Author: Aaron Keith Short description of error While looking to clean up the non-manifold parts of the Bolt Factory library I have found a couple of things which should be addressed within the RemoveDoubles() function inside createMesh.py : Duplicate faces are not removed. The built-in round function does not find similar values depending on the precision. Function description; it would have been helpful to state, Verts that are not matched to a Face of length 3 or 4 are silently expunged. Please note that I'm not a software engineer :) Exact steps for others to reproduce the error Towards the end of createMesh.py, just before "verts = Scale_Mesh_Verts(verts, GLOBAL_SCALE)" add the following lines: props.report({'INFO'}, "length of verts before RemoveDoubles: " + str( len(verts) ) ) props.report({'INFO'}, "length of faces before RemoveDoubles: " + str( len(faces) ) ) verts, faces = RemoveDoubles(verts, faces, 4) props.report({'INFO'}, "length of faces after RemoveDoubles 4DP: " + str( len(faces) ) ) props.report({'INFO'}, "length of verts after RemoveDoubles 4DP: " + str( len(verts) ) ) verts, faces = RemoveDoubles(verts, faces, 5) # Needs to be 5 to fix non-manifold boundary on a M6 nut props.report({'INFO'}, "length of faces after RemoveDoubles 5DP: " + str( len(faces) ) ) props.report({'INFO'}, "length of verts after RemoveDoubles 5DP: " + str( len(verts) ) ) verts, faces = RemoveDoubles(verts, faces, 6) # 6 to check we got them all props.report({'INFO'}, "length of faces after RemoveDoubles 6DP: " + str( len(faces) ) ) props.report({'INFO'}, "length of verts after RemoveDoubles 6DP: " + str( len(verts) ) ) if 0: #Set true to capture the output data to the debug window. props.report({'INFO'}, "Final_Nut_Verts = " + str( (verts) ) ) props.report({'INFO'}, "Final_Nut_Faces = " + str( (faces) ) ) In a new project, enable the Bolt Factory addon if not already setup. Add -> Mesh -> BoltFactory OperatorPresent -> m6 Model -> Nut Type -> Hex Observe the Info Log window, as see that Verts length of "RemovedDoubles 5DP" is less than RemovedDoubles 4DP. For me this gives the following: length of verts after RemoveDoubles 4DP: 1342 length of verts after RemoveDoubles 5DP: 1339

There are several parts to this ticket I'd like to have a crack at addressing. Game plan:

  1. Removing duplicate faces. Leaving a mesh with duplicate faces is not ideal as it creates non-manifold objects.
    Checking for a duplicate face is testing a list of verts against an existing dictionary. Minor complication is that order does matter, as order sets the top side. I think it should be a matter of doing a cyclic shift then testing 3 or 4 times.

  2. Add 1 level of recursion to resolve the mathematical rounding.
    The alternative method would be a vector radius to test if any point resides within a sphere of another point. I expect this would be more computationally expensive than two passes of rounding vectors and comparing.

  3. The rounding causes faces to end up with fewer than 3 sides. Which is fine. However it might be nice to check for a slither, that is two faces pointing in opposite directions. The validate mesh catches this preventing a crash, but knowing where it occurred would help debug and find the point where the generation requires fixing.

  4. Finally the easy bit, add some documentation. While playing around I discovered it was impossible to make a face with 5 or more sides. Not a problem if it documented, as it can be worked around.

Why: The start and end thread generation in a nut can create an invalid mesh - this was previously attempted to be fixed by adding a random offset, which does not always work.

There are several parts to this ticket I'd like to have a crack at addressing. Game plan: 1) Removing duplicate faces. Leaving a mesh with duplicate faces is not ideal as it creates non-manifold objects. Checking for a duplicate face is testing a list of verts against an existing dictionary. Minor complication is that order does matter, as order sets the top side. I think it should be a matter of doing a cyclic shift then testing 3 or 4 times. 2) Add 1 level of recursion to resolve the mathematical rounding. The alternative method would be a vector radius to test if any point resides within a sphere of another point. I expect this would be more computationally expensive than two passes of rounding vectors and comparing. 3) The rounding causes faces to end up with fewer than 3 sides. Which is fine. However it might be nice to check for a slither, that is two faces pointing in opposite directions. The validate mesh catches this preventing a crash, but knowing where it occurred would help debug and find the point where the generation requires fixing. 4) Finally the easy bit, add some documentation. While playing around I discovered it was impossible to make a face with 5 or more sides. Not a problem if it documented, as it can be worked around. Why: The start and end thread generation in a nut can create an invalid mesh - this was previously attempted to be fixed by adding a random offset, which does not always work.
Sign in to join this conversation.
No Label
No Milestone
No project
No Assignees
2 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: extensions/add_mesh_BoltFactory#2
No description provided.