Skip to content

Commit

Permalink
add simple default engine choosing
Browse files Browse the repository at this point in the history
  • Loading branch information
mikedh committed Oct 31, 2024
1 parent dfad924 commit 9f069a8
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 108 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ requires = ["setuptools >= 61.0", "wheel"]
[project]
name = "trimesh"
requires-python = ">=3.8"
version = "4.5.1"
version = "4.5.2"
authors = [{name = "Michael Dawson-Haggerty", email = "[email protected]"}]
license = {file = "LICENSE.md"}
description = "Import, export, process, analyze and view triangular meshes."
Expand Down
2 changes: 0 additions & 2 deletions tests/test_boolean.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

import numpy as np


# test only available engines by default
engines = g.trimesh.boolean.available_engines
# test all engines if all_dep is set
Expand Down Expand Up @@ -89,7 +88,6 @@ def test_boolean_manifold():
# run this test only when manifold3d is available when
# all_dep is enabled
if manifold.exists or g.all_dependencies:

times = {}
for operation in ["union", "intersection"]:
if operation == "union":
Expand Down
2 changes: 2 additions & 0 deletions trimesh/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
grouping,
inertia,
intersections,
iteration,
nsphere,
permutate,
poses,
Expand Down Expand Up @@ -102,6 +103,7 @@
"graph",
"grouping",
"inertia",
"iteration",
"intersections",
"load",
"load_mesh",
Expand Down
115 changes: 89 additions & 26 deletions trimesh/boolean.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,19 @@
Do boolean operations on meshes using either Blender or Manifold.
"""

# for dynamic module imports
from importlib import import_module
import numpy as np

from . import interfaces
from .exceptions import ExceptionWrapper
from .iteration import reduce_cascade
from .typed import Optional, Sequence

try:
from manifold3d import Manifold, Mesh
except BaseException as E:
Mesh = ExceptionWrapper(E)
Manifold = ExceptionWrapper(E)


def difference(
meshes: Sequence, engine: Optional[str] = None, check_volume: bool = True, **kwargs
Expand Down Expand Up @@ -100,27 +108,82 @@ def intersection(
return _engines[engine](meshes, operation="intersection", **kwargs)


# supported backend boolean engines
# ordered by preference
all_engines = [
"manifold",
"blender",
]

# test which engines are actually usable
_engines = {}
available_engines = []
for name in all_engines:
engine = import_module("trimesh.interfaces." + name)
if engine.exists:
_engines[name] = engine.boolean
available_engines.append(name)
if None not in _engines:
# pick the first available engine as the default
_engines[None] = engine.boolean


def set_default_engine(engine):
if engine not in available_engines:
raise ValueError(f"Engine {engine} is not available on this system")
_engines[None] = _engines[engine]
def boolean_manifold(
meshes: Sequence,
operation: str,
check_volume: bool = True,
**kwargs,
):
"""
Run an operation on a set of meshes using the Manifold engine.
Parameters
----------
meshes : list of trimesh.Trimesh
Meshes to be processed
operation
Which boolean operation to do.
check_volume
Raise an error if not all meshes are watertight
positive volumes. Advanced users may want to ignore
this check as it is expensive.
kwargs
Passed through to the `engine`.
"""
if check_volume and not all(m.is_volume for m in meshes):
raise ValueError("Not all meshes are volumes!")

# Convert to manifold meshes
manifolds = [
Manifold(
mesh=Mesh(
vert_properties=np.array(mesh.vertices, dtype=np.float32),
tri_verts=np.array(mesh.faces, dtype=np.uint32),
)
)
for mesh in meshes
]

# Perform operations
if operation == "difference":
if len(meshes) < 2:
raise ValueError("Difference only defined over two meshes.")
elif len(meshes) == 2:
# apply the single difference
result_manifold = manifolds[0] - manifolds[1]
elif len(meshes) > 2:
# union all the meshes to be subtracted from the final result
unioned = reduce_cascade(lambda a, b: a + b, manifolds[1:])
# apply the difference
result_manifold = manifolds[0] - unioned
elif operation == "union":
result_manifold = reduce_cascade(lambda a, b: a + b, manifolds)
elif operation == "intersection":
result_manifold = reduce_cascade(lambda a, b: a ^ b, manifolds)
else:
raise ValueError(f"Invalid boolean operation: '{operation}'")

# Convert back to trimesh meshes
from . import Trimesh

result_mesh = result_manifold.to_mesh()
return Trimesh(vertices=result_mesh.vert_properties, faces=result_mesh.tri_verts)


# which backend boolean engines
_engines = {
"manifold": boolean_manifold,
"blender": interfaces.blender.boolean,
}

if not isinstance(boolean_manifold, ExceptionWrapper):
# if available, manifold3d is the preferred option
_engines[None] = boolean_manifold
elif interfaces.blender.boolean.exists:
# otherwise we can call blender with subprocess
_engines[None] = interfaces.blender.boolean
else:
# failing that add a helpful error message
_engines[None] = ExceptionWrapper(
ImportError("No boolean backend! `pip install manifold3d` or install blender")
)
2 changes: 1 addition & 1 deletion trimesh/interfaces/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from . import blender, gmsh

# add to __all__ as per pep8
__all__ = ["gmsh"]
__all__ = ["gmsh", "blender"]
77 changes: 0 additions & 77 deletions trimesh/interfaces/manifold.py

This file was deleted.

2 changes: 1 addition & 1 deletion trimesh/path/polygons.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
from .. import bounds, geometry, graph, grouping
from ..constants import log
from ..constants import tol_path as tol
from ..iteration import reduce_cascade
from ..transformations import transform_points
from ..typed import Iterable, NDArray, Number, Optional, Union, float64, int64
from ..util import reduce_cascade
from .simplify import fit_circle_check
from .traversal import resample_path

Expand Down

0 comments on commit 9f069a8

Please sign in to comment.