Bolt Factory Addon: RemoveDoubles() improvements #105066

Open
opened 2023-12-14 17:33:14 +01:00 by sw-tya · 2 comments

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 :

  1. Duplicate faces are not removed.
  2. The built-in round function does not find similar values depending on the precision.
  3. 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

**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 : 1) Duplicate faces are not removed. 2) The built-in round function does not find similar values depending on the precision. 3) 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
sw-tya added the
Status
Needs Triage
Priority
Normal
Type
Report
labels 2023-12-14 17:33:15 +01:00
Author
  1. Here is the code that I used to remove duplicate faces.
    Insert just before the return of RemoveDoubles()
myFinallist = []
for i in new_faces:
    if i not in myFinallist:
        myFinallist.append(i)
new_faces = myFinallist

That removed the exact duplicates, but cyclic shift of the tuple is also the same and may still exist!
I don't know how to do a check for [0,1,2] = [1,2,0] = [2,0,1] as for a face these are all equal.
I've made other changes in my copy of the file to not generate those in the first place => Needs another ticket to explain.

  1. Rounding explained using python command line.
    A subtle bug in RemoveDoubles() where the rounded list is created. Using the following two numbers and round to different precision, see the result:
round(2.08249974, 3) = 2.082
round(2.08249974, 4) = 2.0825
round(2.08250021, 3) = 2.083
round(2.08250021, 4) = 2.0825

When data is rounded to fewer decimal places one might assume it collects more of the same rather than missing some!
For the purpose of the physical world those two values are the same, and both need collection.
My solution has been to call, RemoveDoubles twice, but it would be good to have this work inside the function.
With luck this is a 'simple' loop to add code for Decimal_places+1 ...

  1. Comment text above the function:
    Please consider adding something like - "Verts without an associated face of size 3 or 4 get silently expunged."
    Is there a way to check for faces that don't meet that criteria rather than silently removing them?

The source file I've been looking at:
https://projects.blender.org/blender/blender-addons/src/branch/main/add_mesh_BoltFactory/createMesh.py

Thanks

1) Here is the code that I used to remove duplicate faces. Insert just before the return of RemoveDoubles() ``` myFinallist = [] for i in new_faces: if i not in myFinallist: myFinallist.append(i) new_faces = myFinallist ``` That removed the exact duplicates, but cyclic shift of the tuple is also the same and may still exist! I don't know how to do a check for [0,1,2] = [1,2,0] = [2,0,1] as for a face these are all equal. I've made other changes in my copy of the file to not generate those in the first place => Needs another ticket to explain. 2) Rounding explained using python command line. A subtle bug in RemoveDoubles() where the rounded list is created. Using the following two numbers and round to different precision, see the result: ``` round(2.08249974, 3) = 2.082 round(2.08249974, 4) = 2.0825 round(2.08250021, 3) = 2.083 round(2.08250021, 4) = 2.0825 ``` When data is rounded to fewer decimal places one might assume it collects more of the same rather than missing some! For the purpose of the physical world those two values are the same, and both need collection. My solution has been to call, RemoveDoubles twice, but it would be good to have this work inside the function. With luck this is a 'simple' loop to add code for Decimal_places+1 ... 3) Comment text above the function: Please consider adding something like - "Verts without an associated face of size 3 or 4 get silently expunged." Is there a way to check for faces that don't meet that criteria rather than silently removing them? The source file I've been looking at: https://projects.blender.org/blender/blender-addons/src/branch/main/add_mesh_BoltFactory/createMesh.py Thanks
Author

I've done some more testing and the solution I have to address the rounding is to add 4 lines of code at the beginning of RemoveDoubles()

verts, faces = RemoveDoubles_core(verts, faces, Decimal_Places+1)
verts, faces = RemoveDoubles_core(verts, faces, Decimal_Places)
return verts, faces
def RemoveDoubles_core(verts, faces, Decimal_Places=4):

I've done some more testing and the solution I have to address the rounding is to add 4 lines of code at the beginning of RemoveDoubles() ` verts, faces = RemoveDoubles_core(verts, faces, Decimal_Places+1)` ` verts, faces = RemoveDoubles_core(verts, faces, Decimal_Places)` ` return verts, faces` `def RemoveDoubles_core(verts, faces, Decimal_Places=4):`
Sign in to join this conversation.
No Milestone
No project
No Assignees
1 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: blender/blender-addons#105066
No description provided.