Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: create mesh in fewer iterations #868

Merged
merged 1 commit into from
Jan 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 34 additions & 28 deletions src/build123d/mesher.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,36 +312,42 @@ def _create_3mf_mesh(
# Round off the vertices to avoid vertices within tolerance being
# considered as different vertices
digits = -int(round(math.log(TOLERANCE, 10), 1))
ocp_mesh_vertices = [
(round(x, digits), round(y, digits), round(z, digits))
for x, y, z in ocp_mesh_vertices

# Create vertex to index mapping directly
vertex_to_idx = {}
next_idx = 0
vert_table = {}

# First pass - create mapping
for i, (x, y, z) in enumerate(ocp_mesh_vertices):
key = (round(x, digits), round(y, digits), round(z, digits))
if key not in vertex_to_idx:
vertex_to_idx[key] = next_idx
next_idx += 1
vert_table[i] = vertex_to_idx[key]

# Create vertices array in one shot
vertices_3mf = [
Lib3MF.Position((ctypes.c_float * 3)(*v))
for v in vertex_to_idx.keys()
]
"""Create the data to create a 3mf mesh"""
# Create a lookup table of face vertex to shape vertex
unique_vertices = list(set(ocp_mesh_vertices))
vert_table = {
i: unique_vertices.index(pnt) for i, pnt in enumerate(ocp_mesh_vertices)
}

# Create vertex list of 3MF positions
vertices_3mf = []
for pnt in unique_vertices:
c_array = (ctypes.c_float * 3)(*pnt)
vertices_3mf.append(Lib3MF.Position(c_array))
# mesh_3mf.AddVertex Should AddVertex be used to save memory?

# Create triangle point list

# Pre-allocate triangles array and process in bulk
c_uint3 = ctypes.c_uint * 3
triangles_3mf = []
for vertex_indices in triangles:
mapped_indices = [
vert_table[i] for i in [vertex_indices[i] for i in range(3)]
]
# Remove degenerate triangles
if len(set(mapped_indices)) != 3:
continue
c_array = (ctypes.c_uint * 3)(*mapped_indices) # type: ignore[assignment]
triangles_3mf.append(Lib3MF.Triangle(c_array))


# Process triangles in bulk
for tri in triangles:
# Map indices directly without list comprehension
a, b, c = tri[0], tri[1], tri[2]
mapped_a = vert_table[a]
mapped_b = vert_table[b]
mapped_c = vert_table[c]

# Quick degenerate check without set creation
if mapped_a != mapped_b and mapped_b != mapped_c and mapped_c != mapped_a:
triangles_3mf.append(Lib3MF.Triangle(c_uint3(mapped_a, mapped_b, mapped_c)))

return (vertices_3mf, triangles_3mf)

def _add_color(self, b3d_shape: Shape, mesh_3mf: Lib3MF.MeshObject):
Expand Down
14 changes: 14 additions & 0 deletions tests/test_mesher.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from packaging.specifiers import SpecifierSet
from pathlib import Path
from os import fsdecode, fsencode
import time

import pytest

Expand All @@ -16,6 +17,19 @@
from build123d.geometry import Axis, Color, Location, Vector, VectorLike
from build123d.mesher import Mesher

class InternalApiBenchmark(unittest.TestCase):
def test_create_3mf_mesh(self):
start = time.perf_counter()
for i in [100, 1000, 10000, 100000]:
vertices = [(float(i), 0.0, 0.0) for i in range(i)]
triangles = [[i, i+1, i+2] for i in range(0, i-3, 3)]
start = time.perf_counter()
Mesher()._create_3mf_mesh(vertices, triangles)
runtime = time.perf_counter() - start
print(f"| {i} | {runtime:.3f} |")
final_runtime = time.perf_counter() - start
max_runtime = 1.0
self.assertLessEqual(final_runtime, max_runtime, f"All meshes took {final_runtime:.3f}s > {max_runtime}s")

class DirectApiTestCase(unittest.TestCase):
def assertTupleAlmostEquals(
Expand Down
Loading