Unexpected result creating Mesh3D?


I am getting an unexpected result with some Mesh3D elements and I wonder if anyone has a guess about why this might be happening?

If I use the Mesh3D.from_face_vertices() method and set the purge flag to True, I am still getting most (but not all) of the original vertices? From the doc-string of that method, I would have expected the purge flag to remove these duplicate vertices?

With a simple 6-sided brep I get 21 vertices from this method instead of 8, as I would have expected:

Do you think its some sort of tolerance issue with the index() call in _interpret_input_from_face_vertices method ?

I tried a modified version of the _interpret_input_from_face_vertices which uses the point’s is_equivalent instead of the standard __eq__ and this seems to yield the expected result (8 vertices):

from ladybug_rhino.fromgeometry import from_mesh3d
from ladybug_geometry.geometry3d.mesh import Mesh3D
TOL = 0.0000001

def custom_index(vertix_list, vertix):
    for i, other_vert in enumerate(vertix_list):
        if vertix.is_equivalent(other_vert, TOL):
            return i
    raise ValueError()

def interpret_input_from_face_vertices(faces):
    vertices = []
    face_collector = []
    for f in faces:
        ind = []
        for v in f:
            try:  # this can get very slow for large number of vertices.
                ind.append(custom_index(vertices, v))
            except ValueError:  # add new point
                ind.append(len(vertices) - 1)
    return vertices, face_collector

def from_face_vertices(faces):
    vertices, face_collector = interpret_input_from_face_vertices(faces)
    return Mesh3D(tuple(vertices), tuple(face_collector))

face_vertices = [v for msh in _meshes for v in msh.face_vertices]
joined_mesh = from_face_vertices(face_vertices)
mesh_ = from_mesh3d(joined_mesh)

But I don’t know if there is a reason that reducing to just the 8 vertices is ‘wrong’ though? Is there a reason that the current version yields 21 instead of 8 in this case?


vert_test.gh (14.1 KB)

1 Like

Hi @edpmay ,

You are right that it’s related to tolerance. The current purge capability only works if the vertex coordinates are perfectly equal to one another within Python float tolerance. You can set up cases like this that work in pure cPython but, in Rhino IronPython, it’s really tough to get geometries to equal one another within Python float tolerance. So it’s not going to work well for the example you have here.

Honestly, I never improved the purge option because I really don’t use it in the rest of Ladybug Tools SDK. In all cases where I thought it would be useful, I realized that it was better for me to just use the faster option with purge=False and accept that the result will have duplicate vertices.

If you need a method that purges the vertices within a specified tolerance that is not Python float tolerance, I’m happy to add it to ladybug_geometry. I would probably do it as a separate classmethod (something like Mesh3D.from_purged_face_vertices(tolerance)). This way, I can add a required argument for tolerance without affecting the rest of the Ladybug Tools SDK. I can add this method in a day or two unless you send a PR for it before me.

I’m curious to know what you’re using the purge ability for here. As I said above, I never had much use for it but I’m glad to see you’ve found a case to use it.

Hey @chris

Thanks for the info. I’m glad to know I’m I wasn’t doing something wrong there.

This came up as I was trying to diagnose a few issues with some geometry and I wasn’t sure if it was an issue with the specific geometry I had, or just the normal behavior of the method. (The main problems ended up being with the underlying geometry creation method - importing from CAD-Mapper - which had left it a bit gnarly, but nothing to do with LBT’s operations.)

The specific scenario where this came up was trying to clean up and reduce the size of some large shading-object meshes we were transferring as part of an API request. We have an HBJSON ‘viewer’ web-app that uses THREE.js for the frontend and FastAPI to serve the model elements. In this scenario, I am creating the element meshes during the serialization on the backend - so sometimes they can get quite large for things like complex shading objects and the like. I was trying a few different methods to reduce transfer size and was hoping this might help some. Once I implemented the version above it did actually help a fair bit with the high-vertex-meshes. In one scenario it was able to take a request response from 2.1MB to ~400KB, so that’s certainly helpful in some situations. (The better solution was to properly clean up the geometry in the first so that it didn’t result in such unnecessarily complex meshes.)

FWIW, I would definitely make use of a method like this, and have implemented my own version using the is_equivalent test as shown above, but would certainly prefer to use a built in method if it were available. I wouldn’t say there is any rush though, at least on our end.

I’ll plan to submit a PR this week and send along for your review.


1 Like

I’m just noting for the community that you submitted a PR, @edpmay , and it has been merged here: