diff --git a/pyproject.toml b/pyproject.toml index e9ec351e2..6a906c4e5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ requires = ["setuptools >= 61.0", "wheel"] [project] name = "trimesh" requires-python = ">=3.8" -version = "4.5.0" +version = "4.5.1" authors = [{name = "Michael Dawson-Haggerty", email = "mikedh@kerfed.com"}] license = {file = "LICENSE.md"} description = "Import, export, process, analyze and view triangular meshes." diff --git a/tests/test_boolean.py b/tests/test_boolean.py index e83b3df96..9e842fa54 100644 --- a/tests/test_boolean.py +++ b/tests/test_boolean.py @@ -219,14 +219,21 @@ def test_multiple_difference(): spheres = [g.trimesh.creation.icosphere()] spheres.extend(g.trimesh.creation.icosphere().apply_translation(c) for c in center) - # compute using meshes method - diff_base = spheres[0].difference(spheres[1:]) - # compute using function call (should be identical) - diff_meth = g.trimesh.boolean.difference(spheres) + for engine, exists in engines: + if not exists: + g.log.warning("skipping boolean engine %s", engine) + continue + + g.log.info("Testing multiple difference with engine %s", engine) + + # compute using meshes method + diff_base = spheres[0].difference(spheres[1:], engine=engine) + # compute using function call (should be identical) + diff_meth = g.trimesh.boolean.difference(spheres, engine=engine) - # both methods should produce the same result - assert np.isclose(diff_base.volume, diff_meth.volume) - assert diff_base.volume < spheres[0].volume + # both methods should produce the same result + assert np.isclose(diff_base.volume, diff_meth.volume) + assert diff_base.volume < spheres[0].volume - # should have done the diff - assert np.allclose(diff_base.extents, [1.5, 1.5, 2.0], atol=1e-8) + # should have done the diff + assert np.allclose(diff_base.extents, [1.5, 1.5, 2.0], atol=1e-8) diff --git a/trimesh/exchange/threemf.py b/trimesh/exchange/threemf.py index 554398e39..9713cf2db 100644 --- a/trimesh/exchange/threemf.py +++ b/trimesh/exchange/threemf.py @@ -11,23 +11,49 @@ def _read_mesh(mesh): + """ + Read a ` None: def dump(self, concatenate: bool = False) -> List[Geometry]: """ - Get a list of every geometry moved to it's instance position, + Get a list of every geometry moved to its instance position, i.e. freezing or "baking" transforms. Parameters diff --git a/trimesh/util.py b/trimesh/util.py index d2bd8f381..ab452e695 100644 --- a/trimesh/util.py +++ b/trimesh/util.py @@ -2015,17 +2015,20 @@ def triangle_strips_to_faces(strips): """ # save the length of each list in the list of lists - lengths = np.array([len(i) for i in strips]) + lengths = np.array([len(i) for i in strips], dtype=np.int64) # looping through a list of lists is extremely slow # combine all the sequences into a blob we can manipulate - blob = np.concatenate(strips) - - # preallocate and slice the blob into rough triangles - tri = np.zeros((len(blob) - 2, 3), dtype=np.int64) - for i in range(3): - tri[: len(blob) - 3, i] = blob[i : -3 + i] - # the last triangle is left off from the slicing, add it back - tri[-1] = blob[-3:] + blob = np.concatenate(strips, dtype=np.int64) + + # slice the blob into rough triangles + tri = np.array([blob[:-2], blob[1:-1], blob[2:]], dtype=np.int64).T + + # if we only have one strip we can do a *lot* less work + # as we keep every triangle and flip every other one + if len(strips) == 1: + # flip in-place every other triangle + tri[1::2] = np.fliplr(tri[1::2]) + return tri # remove the triangles which were implicit but not actually there # because we combined everything into one big array for speed