Skip to content

Mesh.remove_duplicate_vertices() possible hash collision #1453

@2twenity

Description

@2twenity

Describe the bug
Given: The mesh is received from Speckle as a list of vertices and faces, but some of the vertices are duplicated.
The mesh was constructed and the following checks were performed:

mesh.is_manifold() -> True
mesh.is_connected() -> False # because some of the vertices are duplicated
mesh.is_valid() -> True
mesh.is_trimesh() -> True

After the usage of a method, the results are following

mesh.remove_duplicate_vertices()

mesh.is_manifold() -> True
mesh.is_connected() -> True # The connectivity was fixed
mesh.is_valid() -> False 
mesh.is_trimesh() -> False # Probably because of the TOL.geometric_key some collision happens

Instead, if a comparison of equality of vertices is done in way when we compare sets of coordinates directly, doesn't cause this collision

def validate_mesh(input_mesh: Mesh) -> Mesh:
    input_coordinates = [tuple(input_mesh.vertex_coordinates(vertex)) for vertex in input_mesh.vertices()]
    no_duplicates_coordinates = list(set([tuple(input_mesh.vertex_coordinates(vertex)) for vertex in input_mesh.vertices()]))
 
    
    all_updated_faces = []
    
    for face in sorted(list(input_mesh.faces())):
        vertices_lst = input_mesh.face_vertices(face) # vertices list like [12, 13, 14]
    
       
        vertex0 = input_coordinates[vertices_lst[0]]
        vertex1 = input_coordinates[vertices_lst[1]]
        vertex2 = input_coordinates[vertices_lst[2]]

        new_index0 = no_duplicates_coordinates.index(vertex0)
        new_index1 = no_duplicates_coordinates.index(vertex1)
        new_index2 = no_duplicates_coordinates.index(vertex2)

        updated_faces = [new_index0, new_index1, new_index2]
        # print(updated_faces)

        all_updated_faces.append(updated_faces)

  
    new_mesh = Mesh.from_vertices_and_faces(vertices = no_duplicates_coordinates,
                                           faces = all_updated_faces)

    return new_mesh

The result

new_mesh = validate_mesh(mesh)

new_mesh.is_manifold() -> True
new_mesh.is_connected() -> True 
new_mesh.is_valid() -> True
new_mesh.is_trimesh() -> True

Since there are no specific tests for a mesh.remove_duplicate_vertices() function, I'd assume that it's reasonable to modify it a bit. If needed, I'd be happy to contribute.

To Reproduce
Steps to reproduce the behavior:

  1. Context [Jupyter Notebook, latest compas installed]
  2. Sample data

Mesh itself

[(1.624855, 4.584075, 3.408143), (1.624855, 4.470224, 3.4), (1.624855, 4.470224, 3.4)]
[(1.624855, 4.470224, 3.4), (1.624855, 4.470224, 3.8), (1.624855, 4.52715, 3.804071)]
[(1.624855, 4.866152, 4.143074), (1.624855, 4.870224, 4.2), (1.624855, 5.270224, 4.2)]
[(1.624855, 5.270224, 4.2), (1.624855, 5.262081, 4.086148), (1.624855, 5.237818, 3.974614)]
[(1.624855, 5.237818, 3.974614), (1.624855, 5.197929, 3.867668), (1.624855, 5.143226, 3.767487)]
[(1.624855, 5.143226, 3.767487), (1.624855, 5.074823, 3.676111), (1.624855, 4.994112, 3.5954)]
[(1.624855, 4.994112, 3.5954), (1.624855, 4.902736, 3.526997), (1.624855, 4.802556, 3.472294)]
[(1.624855, 4.802556, 3.472294), (1.624855, 4.69561, 3.432406), (1.624855, 4.584075, 3.408143)]
[(1.624855, 4.584075, 3.408143), (1.624855, 4.470224, 3.4), (1.624855, 4.52715, 3.804071)]
[(1.624855, 4.854021, 4.087307), (1.624855, 4.866152, 4.143074), (1.624855, 5.270224, 4.2)]
[(1.624855, 5.270224, 4.2), (1.624855, 5.237818, 3.974614), (1.624855, 5.143226, 3.767487)]
[(1.624855, 5.143226, 3.767487), (1.624855, 4.994112, 3.5954), (1.624855, 4.802556, 3.472294)]
[(1.624855, 4.802556, 3.472294), (1.624855, 4.584075, 3.408143), (1.624855, 4.52715, 3.804071)]
[(1.624855, 4.834076, 4.033834), (1.624855, 4.854021, 4.087307), (1.624855, 5.270224, 4.2)]
[(1.624855, 5.270224, 4.2), (1.624855, 5.143226, 3.767487), (1.624855, 4.802556, 3.472294)]
[(1.624855, 4.802556, 3.472294), (1.624855, 4.52715, 3.804071), (1.624855, 4.582917, 3.816203)]
[(1.624855, 4.806725, 3.983744), (1.624855, 4.834076, 4.033834), (1.624855, 5.270224, 4.2)]
[(1.624855, 4.802556, 3.472294), (1.624855, 4.582917, 3.816203), (1.624855, 4.63639, 3.836147)]
[(1.624855, 4.772523, 3.938056), (1.624855, 4.806725, 3.983744), (1.624855, 5.270224, 4.2)]
[(1.624855, 4.802556, 3.472294), (1.624855, 4.63639, 3.836147), (1.624855, 4.68648, 3.863499)]
[(1.624855, 4.732168, 3.8977), (1.624855, 4.772523, 3.938056), (1.624855, 5.270224, 4.2)]
[(1.624855, 5.270224, 4.2), (1.624855, 4.802556, 3.472294), (1.624855, 4.68648, 3.863499)]
[(1.624855, 4.68648, 3.863499), (1.624855, 4.732168, 3.8977), (1.624855, 5.270224, 4.2)]
[(2.024855, 4.584075, 3.408143), (2.024855, 4.470224, 3.4), (2.024855, 4.470224, 3.4)]
[(2.024855, 4.470224, 3.4), (2.024855, 4.52715, 3.804071), (2.024855, 4.470224, 3.8)]
[(2.024855, 4.866152, 4.143074), (2.024855, 5.270224, 4.2), (2.024855, 4.870224, 4.2)]
[(2.024855, 5.270224, 4.2), (2.024855, 5.237818, 3.974614), (2.024855, 5.262081, 4.086148)]
[(2.024855, 5.237818, 3.974614), (2.024855, 5.143226, 3.767487), (2.024855, 5.197929, 3.867668)]
[(2.024855, 5.143226, 3.767487), (2.024855, 4.994112, 3.5954), (2.024855, 5.074823, 3.676111)]
[(2.024855, 4.994112, 3.5954), (2.024855, 4.802556, 3.472294), (2.024855, 4.902736, 3.526997)]
[(2.024855, 4.802556, 3.472294), (2.024855, 4.584075, 3.408143), (2.024855, 4.69561, 3.432406)]
[(2.024855, 4.584075, 3.408143), (2.024855, 4.52715, 3.804071), (2.024855, 4.470224, 3.4)]
[(2.024855, 4.854021, 4.087307), (2.024855, 5.270224, 4.2), (2.024855, 4.866152, 4.143074)]
[(2.024855, 5.270224, 4.2), (2.024855, 5.143226, 3.767487), (2.024855, 5.237818, 3.974614)]
[(2.024855, 5.143226, 3.767487), (2.024855, 4.802556, 3.472294), (2.024855, 4.994112, 3.5954)]
[(2.024855, 4.802556, 3.472294), (2.024855, 4.52715, 3.804071), (2.024855, 4.584075, 3.408143)]
[(2.024855, 4.834076, 4.033834), (2.024855, 5.270224, 4.2), (2.024855, 4.854021, 4.087307)]
[(2.024855, 5.270224, 4.2), (2.024855, 4.802556, 3.472294), (2.024855, 5.143226, 3.767487)]
[(2.024855, 4.802556, 3.472294), (2.024855, 4.582917, 3.816203), (2.024855, 4.52715, 3.804071)]
[(2.024855, 4.806725, 3.983744), (2.024855, 5.270224, 4.2), (2.024855, 4.834076, 4.033834)]
[(2.024855, 4.802556, 3.472294), (2.024855, 4.63639, 3.836147), (2.024855, 4.582917, 3.816203)]
[(2.024855, 4.772523, 3.938056), (2.024855, 5.270224, 4.2), (2.024855, 4.806725, 3.983744)]
[(2.024855, 4.802556, 3.472294), (2.024855, 4.68648, 3.863499), (2.024855, 4.63639, 3.836147)]
[(2.024855, 4.732168, 3.8977), (2.024855, 5.270224, 4.2), (2.024855, 4.772523, 3.938056)]
[(2.024855, 5.270224, 4.2), (2.024855, 4.68648, 3.863499), (2.024855, 4.802556, 3.472294)]
[(2.024855, 4.68648, 3.863499), (2.024855, 5.270224, 4.2), (2.024855, 4.732168, 3.8977)]
[(2.024855, 4.470224, 3.4), (1.624855, 4.470224, 3.8), (1.624855, 4.470224, 3.4)]
[(2.024855, 4.470224, 3.4), (2.024855, 4.470224, 3.8), (1.624855, 4.470224, 3.8)]
[(2.024855, 4.470224, 3.8), (1.624855, 4.52715, 3.804071), (1.624855, 4.470224, 3.8)]
[(2.024855, 4.470224, 3.8), (2.024855, 4.52715, 3.804071), (1.624855, 4.52715, 3.804071)]
[(2.024855, 4.52715, 3.804071), (1.624855, 4.582917, 3.816203), (1.624855, 4.52715, 3.804071)]
[(2.024855, 4.52715, 3.804071), (2.024855, 4.582917, 3.816203), (1.624855, 4.582917, 3.816203)]
[(2.024855, 4.582917, 3.816203), (1.624855, 4.63639, 3.836147), (1.624855, 4.582917, 3.816203)]
[(2.024855, 4.582917, 3.816203), (2.024855, 4.63639, 3.836147), (1.624855, 4.63639, 3.836147)]
[(2.024855, 4.63639, 3.836147), (1.624855, 4.68648, 3.863499), (1.624855, 4.63639, 3.836147)]
[(2.024855, 4.63639, 3.836147), (2.024855, 4.68648, 3.863499), (1.624855, 4.68648, 3.863499)]
[(2.024855, 4.68648, 3.863499), (1.624855, 4.732168, 3.8977), (1.624855, 4.68648, 3.863499)]
[(2.024855, 4.68648, 3.863499), (2.024855, 4.732168, 3.8977), (1.624855, 4.732168, 3.8977)]
[(2.024855, 4.732168, 3.8977), (1.624855, 4.772523, 3.938056), (1.624855, 4.732168, 3.8977)]
[(2.024855, 4.732168, 3.8977), (2.024855, 4.772523, 3.938056), (1.624855, 4.772523, 3.938056)]
[(2.024855, 4.772523, 3.938056), (1.624855, 4.806725, 3.983744), (1.624855, 4.772523, 3.938056)]
[(2.024855, 4.772523, 3.938056), (2.024855, 4.806725, 3.983744), (1.624855, 4.806725, 3.983744)]
[(2.024855, 4.806725, 3.983744), (1.624855, 4.834076, 4.033834), (1.624855, 4.806725, 3.983744)]
[(2.024855, 4.806725, 3.983744), (2.024855, 4.834076, 4.033834), (1.624855, 4.834076, 4.033834)]
[(2.024855, 4.834076, 4.033834), (1.624855, 4.854021, 4.087307), (1.624855, 4.834076, 4.033834)]
[(2.024855, 4.834076, 4.033834), (2.024855, 4.854021, 4.087307), (1.624855, 4.854021, 4.087307)]
[(2.024855, 4.854021, 4.087307), (1.624855, 4.866152, 4.143074), (1.624855, 4.854021, 4.087307)]
[(2.024855, 4.854021, 4.087307), (2.024855, 4.866152, 4.143074), (1.624855, 4.866152, 4.143074)]
[(2.024855, 4.866152, 4.143074), (1.624855, 4.870224, 4.2), (1.624855, 4.866152, 4.143074)]
[(2.024855, 4.866152, 4.143074), (2.024855, 4.870224, 4.2), (1.624855, 4.870224, 4.2)]
[(2.024855, 4.870224, 4.2), (1.624855, 5.270224, 4.2), (1.624855, 4.870224, 4.2)]
[(2.024855, 4.870224, 4.2), (2.024855, 5.270224, 4.2), (1.624855, 5.270224, 4.2)]
[(2.024855, 5.270224, 4.2), (1.624855, 5.262081, 4.086148), (1.624855, 5.270224, 4.2)]
[(2.024855, 5.270224, 4.2), (2.024855, 5.262081, 4.086148), (1.624855, 5.262081, 4.086148)]
[(2.024855, 5.262081, 4.086148), (1.624855, 5.237818, 3.974614), (1.624855, 5.262081, 4.086148)]
[(2.024855, 5.262081, 4.086148), (2.024855, 5.237818, 3.974614), (1.624855, 5.237818, 3.974614)]
[(2.024855, 5.237818, 3.974614), (1.624855, 5.197929, 3.867668), (1.624855, 5.237818, 3.974614)]
[(2.024855, 5.237818, 3.974614), (2.024855, 5.197929, 3.867668), (1.624855, 5.197929, 3.867668)]
[(2.024855, 5.197929, 3.867668), (1.624855, 5.143226, 3.767487), (1.624855, 5.197929, 3.867668)]
[(2.024855, 5.197929, 3.867668), (2.024855, 5.143226, 3.767487), (1.624855, 5.143226, 3.767487)]
[(2.024855, 5.143226, 3.767487), (1.624855, 5.074823, 3.676111), (1.624855, 5.143226, 3.767487)]
[(2.024855, 5.143226, 3.767487), (2.024855, 5.074823, 3.676111), (1.624855, 5.074823, 3.676111)]
[(2.024855, 5.074823, 3.676111), (1.624855, 4.994112, 3.5954), (1.624855, 5.074823, 3.676111)]
[(2.024855, 5.074823, 3.676111), (2.024855, 4.994112, 3.5954), (1.624855, 4.994112, 3.5954)]
[(2.024855, 4.994112, 3.5954), (1.624855, 4.902736, 3.526997), (1.624855, 4.994112, 3.5954)]
[(2.024855, 4.994112, 3.5954), (2.024855, 4.902736, 3.526997), (1.624855, 4.902736, 3.526997)]
[(2.024855, 4.902736, 3.526997), (1.624855, 4.802556, 3.472294), (1.624855, 4.902736, 3.526997)]
[(2.024855, 4.902736, 3.526997), (2.024855, 4.802556, 3.472294), (1.624855, 4.802556, 3.472294)]
[(2.024855, 4.802556, 3.472294), (1.624855, 4.69561, 3.432406), (1.624855, 4.802556, 3.472294)]
[(2.024855, 4.802556, 3.472294), (2.024855, 4.69561, 3.432406), (1.624855, 4.69561, 3.432406)]
[(2.024855, 4.69561, 3.432406), (1.624855, 4.584075, 3.408143), (1.624855, 4.69561, 3.432406)]
[(2.024855, 4.69561, 3.432406), (2.024855, 4.584075, 3.408143), (1.624855, 4.584075, 3.408143)]
[(2.024855, 4.584075, 3.408143), (1.624855, 4.470224, 3.4), (1.624855, 4.584075, 3.408143)]
[(2.024855, 4.584075, 3.408143), (2.024855, 4.470224, 3.4), (1.624855, 4.470224, 3.4)]
Image
  1. See error
    Viewer fails to visualize because trimesh structure is broken
    Screenshots
Image

Desktop (please complete the following information):

  • iOS M4
  • Python version 3.12
  • Python package manager Conda

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions