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:
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
vertices.append(v)
ind.append(len(vertices) - 1)
face_collector.append(tuple(ind))
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?
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.
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.