That’s some truly horrifying Python. It’s also a pretty flaky solution because it relies on all like edges sharing the same index. It might work, but I would never trust it.
As for the missing comparisons, why are you looping through the objects in collections rather than just looping over bpy.data.objects[:]? I don’t know your scene structure, but that seems a likely problem.
A cleaner solution would be.
scene_objects = bpy.data.objects[:]
# Loop over the objects, not indexes or strings
for obj_a in scene_objects:
for obj_b in scene_objects:
if obj_a == obj_b:
continue
...
I also wonder if you could be having memory issues by not calling BMesh.free() at the end of each loop. Unless explicitly freed, BMesh objects can remain in memory until the script finishes executing.
Please revisit my earlier answer for guidance on coding an actual solution. Maybe run through some basic Python tutorials first.
You could reuse the same bmesh objects for every loop by declaring them first and using .clear() method at the end of each loop.
Increasing the delta will make it match objects that are more varied. The delta is how much difference is allowed, so larger number means more difference.
You should loop over bpy.data.objects rather than messing around with the collections.
@init_pixel I looked over the file and the edges are in the same order between objects. There is no reason why they wouldn’t be when it’s the same object that has just been duplicated, scaled, rotated.
(I will test your code on the file later if I get that time)
Okay try this script. It should leave you with only unique objects selected.
import bpy
import bmesh
delta = 0.005 # set margin of error allowed
print("Number of objects: %s" % (len(bpy.data.objects)))
# Select everything - Duplicates will be deselected
bpy.ops.object.select_all(action='SELECT')
bm1 = bmesh.new()
bm2 = bmesh.new()
obj_count = 0
dup_count = 0
not_meshs = 0
# Compare all objects that haven't been deselected
for obj in bpy.data.objects:
# Only interested in meshes and objects that are selected
if obj.type != 'MESH' or not obj.select_get():
if obj.type != 'MESH': not_meshes += 1
continue
obj_count += 1
print("\nComparing object %s to:" % (obj.name))
# Fill bmesh object
bm1.from_mesh(obj.data)
bm1.edges.ensure_lookup_table()
# Compare to all other objects that are still selected
for dup in bpy.data.objects:
# Only compare with other meshes and objects that haven't been eliminated
if obj == dup or dup.type != 'MESH' or not dup.select_get():
continue
# Fill bmesh object with test subject
bm2.from_mesh(dup.data)
bm2.edges.ensure_lookup_table()
# If edge counts are different, its not going to match
if len(bm1.edges) != len(bm2.edges):
bm2.clear()
continue
print(dup.name)
# Compare all edges between objects allowing for delta difference in length
is_match = True
for idx in range(len(bm1.edges)):
len1 = bm1.edges[idx].calc_length()
len2 = bm2.edges[idx].calc_length()
# As soon as an edge is outside margin of error, end comparison
if abs(len1 - len2) > delta:
is_match = False
break
# Check if it was a match, if so deselect it
if is_match:
print("MATCH")
dup_count += 1
dup.select_set(False)
# Clean up bmesh
bm2.clear()
# Clean other bemsh
bm1.clear()
print('\nTotal Duplicate Objects', dup_count)
print('Total Unique Objects', obj_count)
print('Non-Meshes', not_meshs)