Find duplicate objects or vertices without removing them

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)
1 Like