Skip to content

Commit 94b8cea

Browse files
authored
Merge pull request #2179 from mikedh/release/upstreamctm
Release: Upstream CTM + STEP
2 parents 27fbc55 + 5b3e165 commit 94b8cea

14 files changed

Lines changed: 10693 additions & 198 deletions

File tree

docs/content/install.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ Trimesh has a lot of soft-required upstream packages, and we try to make sure th
7171
|`pyinstrument`| A sampling based profiler for performance tweaking. | | `test`|
7272
|`vhacdx`| A binding for VHACD which provides convex decompositions | | `recommend`|
7373
|`manifold3d`| A binding for the Manifold mesh boolean engine | | `recommend`|
74+
|`openctm`| A binding for OpenCTM loaders enabling `.ctm` loading | | `recommend`|
75+
|`cascadio`| A binding for OpenCASCADE enabling `.STEP` loading | | `recommend`|
7476

7577
## Adding A Dependency
7678

models/box_sides.STEP

Lines changed: 10542 additions & 0 deletions
Large diffs are not rendered by default.

pyproject.toml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ requires = ["setuptools >= 61.0", "wheel"]
55
[project]
66
name = "trimesh"
77
requires-python = ">=3.7"
8-
version = "4.1.8"
8+
version = "4.2.0"
99
authors = [{name = "Michael Dawson-Haggerty", email = "mikedh@kerfed.com"}]
1010
license = {file = "LICENSE.md"}
1111
description = "Import, export, process, analyze and view triangular meshes."
@@ -88,7 +88,9 @@ recommend = [
8888
"pyglet<2",
8989
"psutil",
9090
"scikit-image",
91-
"python-fcl",
91+
"python-fcl", # do collision checks
92+
"openctm", # load `CTM` compressed models
93+
"cascadio", # load `STEP` files
9294
"manifold3d>=2.3.0"
9395
]
9496

tests/test_step.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
try:
2+
import generic as g
3+
except BaseException:
4+
from . import generic as g
5+
6+
7+
class STEPTests(g.unittest.TestCase):
8+
def test_basic(self):
9+
try:
10+
import cascadio # noqa
11+
except BaseException:
12+
g.log.error("failed to get cascadio!", exc_info=True)
13+
return
14+
15+
s = g.get_mesh("box_sides.STEP")
16+
assert len(s.geometry) == 10
17+
18+
19+
if __name__ == "__main__":
20+
g.trimesh.util.attach_to_log()
21+
g.unittest.main()

trimesh/base.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -225,8 +225,8 @@ def process(
225225
of their 2D oriented bounding box
226226
shorter than tol.merge
227227
4) remove duplicated triangles
228-
5) ensure triangles are consistently wound
229-
and normals face outwards
228+
5) Attempt to ensure triangles are consistently wound
229+
and normals face outwards.
230230
231231
Parameters
232232
------------
@@ -249,8 +249,8 @@ def process(
249249
if validate:
250250
# get a mask with only unique and non-degenerate faces
251251
mask = self.unique_faces() & self.nondegenerate_faces()
252-
self.fix_normals()
253252
self.update_faces(mask)
253+
self.fix_normals()
254254

255255
# since none of our process operations moved vertices or faces
256256
# we can keep face and vertex normals in the cache without recomputing

trimesh/exchange/cascade.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import os
2+
import tempfile
3+
4+
from ..typed import BinaryIO, Dict, Optional
5+
6+
# used as an intermediate format
7+
from .gltf import load_glb
8+
9+
10+
def load_step(
11+
file_obj: BinaryIO,
12+
file_type,
13+
tol_linear: Optional[float] = None,
14+
tol_angular: Optional[float] = None,
15+
tol_relative: Optional[bool] = False,
16+
merge_primitives: bool = True,
17+
**kwargs,
18+
) -> Dict:
19+
"""
20+
Use `cascadio` a packaged version of OpenCASCADE
21+
to load a STEP file using GLB as an intermediate.
22+
23+
Parameters
24+
-----------
25+
file_obj
26+
STEP file to load.
27+
**kwargs
28+
Passed to `cascadio.step_to_glb`
29+
30+
Returns
31+
----------
32+
kwargs
33+
Keyword arguments for a Scene.
34+
"""
35+
# TODO : update upstream `cascadio` to accept bytes objects
36+
# so that we don't need to write a temporary file to disc!
37+
with tempfile.TemporaryDirectory() as F:
38+
# temporarily copy the STEP
39+
stepfile = os.path.join(F, "data.step")
40+
with open(stepfile, "wb") as f:
41+
f.write(file_obj.read())
42+
43+
# where to save the converted GLB
44+
glbfile = os.path.join(F, "converted.glb")
45+
46+
# the arguments for cascadio are not optional so
47+
# filter out any `None` value arguments here
48+
cascadio_kwargs = {
49+
"merge_primitives": bool(merge_primitives),
50+
"tol_linear": tol_linear,
51+
"tol_angular": tol_angular,
52+
"tol_relative": tol_relative,
53+
}
54+
# run the conversion
55+
cascadio.step_to_glb(
56+
stepfile,
57+
glbfile,
58+
**{k: v for k, v in cascadio_kwargs.items() if v is not None},
59+
)
60+
61+
with open(glbfile, "rb") as f:
62+
# return the parsed intermediate file
63+
return load_glb(file_obj=f, merge_primitives=merge_primitives, **kwargs)
64+
65+
66+
try:
67+
# wheels for most platforms: `pip install cascadio`
68+
import cascadio
69+
70+
_cascade_loaders = {"stp": load_step, "step": load_step}
71+
except BaseException:
72+
_cascade_loaders = {}

trimesh/exchange/load.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from ..util import log, now
1414
from . import misc
1515
from .binvox import _binvox_loaders
16+
from .cascade import _cascade_loaders
1617
from .dae import _collada_loaders
1718
from .gltf import _gltf_loaders
1819
from .misc import _misc_loaders
@@ -655,6 +656,7 @@ def _parse_file_args(
655656
mesh_loaders.update(_threedxml_loaders)
656657
mesh_loaders.update(_three_loaders)
657658
mesh_loaders.update(_xyz_loaders)
659+
mesh_loaders.update(_cascade_loaders)
658660

659661
# collect loaders which return voxel types
660662
voxel_loaders = {}

trimesh/exchange/misc.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,3 +133,10 @@ def load_meshio(file_obj, file_type=None, **kwargs):
133133
_misc_loaders.update(_meshio_loaders)
134134
except BaseException:
135135
_meshio_loaders = {}
136+
137+
try:
138+
import openctm
139+
140+
_misc_loaders["ctm"] = openctm.load_ctm
141+
except BaseException:
142+
pass

trimesh/exchange/openctm.py

Lines changed: 0 additions & 182 deletions
This file was deleted.

trimesh/exchange/urdf.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,6 @@ def export_urdf(mesh, directory, scale=1.0, color=None, **kwargs):
2727

2828
import lxml.etree as et
2929

30-
from ..resources import get
31-
3230
# TODO: fix circular import
3331
from .export import export_mesh
3432

@@ -153,8 +151,10 @@ def export_urdf(mesh, directory, scale=1.0, color=None, **kwargs):
153151
tree = et.ElementTree(root)
154152

155153
if tol.strict:
154+
from ..resources import get_stream
155+
156156
# todo : we don't pass the URDF schema validation
157-
schema = et.XMLSchema(file=get("schema/urdf.xsd", as_stream=True))
157+
schema = et.XMLSchema(file=get_stream("schema/urdf.xsd"))
158158
if not schema.validate(tree):
159159
# actual error isn't raised by validate
160160
log.debug(schema.error_log)

0 commit comments

Comments
 (0)