pyvista-cad 0.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (188) hide show
  1. pyvista_cad-0.0.1/.gitattributes +19 -0
  2. pyvista_cad-0.0.1/.github/FUNDING.yml +1 -0
  3. pyvista_cad-0.0.1/.github/dependabot.yml +11 -0
  4. pyvista_cad-0.0.1/.github/workflows/ci.yml +171 -0
  5. pyvista_cad-0.0.1/.github/workflows/docs.yml +87 -0
  6. pyvista_cad-0.0.1/.gitignore +60 -0
  7. pyvista_cad-0.0.1/.pre-commit-config.yaml +79 -0
  8. pyvista_cad-0.0.1/LICENSE +21 -0
  9. pyvista_cad-0.0.1/PKG-INFO +219 -0
  10. pyvista_cad-0.0.1/README.md +142 -0
  11. pyvista_cad-0.0.1/assets/render_hero.py +78 -0
  12. pyvista_cad-0.0.1/assets/render_readme.py +196 -0
  13. pyvista_cad-0.0.1/cspell.json +330 -0
  14. pyvista_cad-0.0.1/doc/Makefile +21 -0
  15. pyvista_cad-0.0.1/doc/_static/hero.png +0 -0
  16. pyvista_cad-0.0.1/doc/_static/pyvista_logo.svg +6161 -0
  17. pyvista_cad-0.0.1/doc/_static/readme_cad_plotting.png +0 -0
  18. pyvista_cad-0.0.1/doc/_static/readme_quickstart.png +0 -0
  19. pyvista_cad-0.0.1/doc/_static/readme_workflow.png +0 -0
  20. pyvista_cad-0.0.1/doc/_static/theme_overrides.css +1 -0
  21. pyvista_cad-0.0.1/doc/api/index.rst +225 -0
  22. pyvista_cad-0.0.1/doc/conf.py +165 -0
  23. pyvista_cad-0.0.1/doc/index.md +86 -0
  24. pyvista_cad-0.0.1/doc/make.bat +29 -0
  25. pyvista_cad-0.0.1/doc/user_guide/cad_visualization.md +144 -0
  26. pyvista_cad-0.0.1/doc/user_guide/interop_with_build123d.md +82 -0
  27. pyvista_cad-0.0.1/examples/01_readers/README.rst +8 -0
  28. pyvista_cad-0.0.1/examples/01_readers/read_3mf.py +34 -0
  29. pyvista_cad-0.0.1/examples/01_readers/read_brep.py +47 -0
  30. pyvista_cad-0.0.1/examples/01_readers/read_dxf.py +48 -0
  31. pyvista_cad-0.0.1/examples/01_readers/read_fcstd.py +40 -0
  32. pyvista_cad-0.0.1/examples/01_readers/read_ifc.py +53 -0
  33. pyvista_cad-0.0.1/examples/01_readers/read_iges.py +64 -0
  34. pyvista_cad-0.0.1/examples/01_readers/read_scad.py +44 -0
  35. pyvista_cad-0.0.1/examples/01_readers/read_step.py +35 -0
  36. pyvista_cad-0.0.1/examples/02_writers/README.rst +7 -0
  37. pyvista_cad-0.0.1/examples/02_writers/write_3mf.py +54 -0
  38. pyvista_cad-0.0.1/examples/02_writers/write_brep.py +47 -0
  39. pyvista_cad-0.0.1/examples/02_writers/write_dxf.py +53 -0
  40. pyvista_cad-0.0.1/examples/02_writers/write_step_faceted.py +58 -0
  41. pyvista_cad-0.0.1/examples/03_bridges/README.rst +9 -0
  42. pyvista_cad-0.0.1/examples/03_bridges/from_build123d_box.py +63 -0
  43. pyvista_cad-0.0.1/examples/03_bridges/from_build123d_compound.py +66 -0
  44. pyvista_cad-0.0.1/examples/03_bridges/from_cadquery_workplane.py +65 -0
  45. pyvista_cad-0.0.1/examples/03_bridges/to_build123d.py +57 -0
  46. pyvista_cad-0.0.1/examples/03_bridges/to_topods.py +67 -0
  47. pyvista_cad-0.0.1/examples/03_bridges/via_gmsh.py +51 -0
  48. pyvista_cad-0.0.1/examples/04_metadata/README.rst +8 -0
  49. pyvista_cad-0.0.1/examples/04_metadata/assembly_tree_walk.py +74 -0
  50. pyvista_cad-0.0.1/examples/04_metadata/color_aware_3mf.py +57 -0
  51. pyvista_cad-0.0.1/examples/04_metadata/inspect_step_assembly.py +72 -0
  52. pyvista_cad-0.0.1/examples/04_metadata/split_by_layer_dxf.py +54 -0
  53. pyvista_cad-0.0.1/examples/04_metadata/units_and_conversion.py +68 -0
  54. pyvista_cad-0.0.1/examples/05_workflows/README.rst +7 -0
  55. pyvista_cad-0.0.1/examples/05_workflows/as_designed_vs_scan.py +88 -0
  56. pyvista_cad-0.0.1/examples/05_workflows/cad_to_fea_tet_mesh.py +68 -0
  57. pyvista_cad-0.0.1/examples/05_workflows/cad_to_signed_distance.py +73 -0
  58. pyvista_cad-0.0.1/examples/05_workflows/parametric_to_3d_print.py +65 -0
  59. pyvista_cad-0.0.1/examples/06_advanced/README.rst +7 -0
  60. pyvista_cad-0.0.1/examples/06_advanced/cad_friendly_plot.py +70 -0
  61. pyvista_cad-0.0.1/examples/06_advanced/custom_tessellation.py +58 -0
  62. pyvista_cad-0.0.1/examples/06_advanced/ifc_to_unstructured_grid.py +69 -0
  63. pyvista_cad-0.0.1/examples/06_advanced/multiblock_walk.py +65 -0
  64. pyvista_cad-0.0.1/examples/README.rst +9 -0
  65. pyvista_cad-0.0.1/justfile +62 -0
  66. pyvista_cad-0.0.1/pyproject.toml +329 -0
  67. pyvista_cad-0.0.1/setup.cfg +4 -0
  68. pyvista_cad-0.0.1/src/pyvista_cad/__init__.py +248 -0
  69. pyvista_cad-0.0.1/src/pyvista_cad/__init__.pyi +44 -0
  70. pyvista_cad-0.0.1/src/pyvista_cad/_accessor.py +2369 -0
  71. pyvista_cad-0.0.1/src/pyvista_cad/_backends/__init__.py +5 -0
  72. pyvista_cad-0.0.1/src/pyvista_cad/_backends/_build123d.py +418 -0
  73. pyvista_cad-0.0.1/src/pyvista_cad/_backends/_cascadio.py +101 -0
  74. pyvista_cad-0.0.1/src/pyvista_cad/_backends/_ezdxf.py +383 -0
  75. pyvista_cad-0.0.1/src/pyvista_cad/_backends/_freecad.py +347 -0
  76. pyvista_cad-0.0.1/src/pyvista_cad/_backends/_gltf.py +227 -0
  77. pyvista_cad-0.0.1/src/pyvista_cad/_backends/_ifcopenshell.py +400 -0
  78. pyvista_cad-0.0.1/src/pyvista_cad/_backends/_lib3mf.py +420 -0
  79. pyvista_cad-0.0.1/src/pyvista_cad/_backends/_openscad.py +85 -0
  80. pyvista_cad-0.0.1/src/pyvista_cad/_backends/_pyiges.py +174 -0
  81. pyvista_cad-0.0.1/src/pyvista_cad/_bridges/__init__.py +6 -0
  82. pyvista_cad-0.0.1/src/pyvista_cad/_bridges/build123d.py +200 -0
  83. pyvista_cad-0.0.1/src/pyvista_cad/_bridges/cadquery.py +123 -0
  84. pyvista_cad-0.0.1/src/pyvista_cad/_bridges/gmsh.py +175 -0
  85. pyvista_cad-0.0.1/src/pyvista_cad/_bridges/topods.py +113 -0
  86. pyvista_cad-0.0.1/src/pyvista_cad/_cad_view.py +1186 -0
  87. pyvista_cad-0.0.1/src/pyvista_cad/_conversion.py +327 -0
  88. pyvista_cad-0.0.1/src/pyvista_cad/_errors.py +138 -0
  89. pyvista_cad-0.0.1/src/pyvista_cad/_metadata.py +378 -0
  90. pyvista_cad-0.0.1/src/pyvista_cad/_readers/__init__.py +6 -0
  91. pyvista_cad-0.0.1/src/pyvista_cad/_readers/brep.py +136 -0
  92. pyvista_cad-0.0.1/src/pyvista_cad/_readers/dxf.py +172 -0
  93. pyvista_cad-0.0.1/src/pyvista_cad/_readers/fcstd.py +51 -0
  94. pyvista_cad-0.0.1/src/pyvista_cad/_readers/gltf.py +52 -0
  95. pyvista_cad-0.0.1/src/pyvista_cad/_readers/ifc.py +59 -0
  96. pyvista_cad-0.0.1/src/pyvista_cad/_readers/iges.py +66 -0
  97. pyvista_cad-0.0.1/src/pyvista_cad/_readers/scad.py +51 -0
  98. pyvista_cad-0.0.1/src/pyvista_cad/_readers/step.py +443 -0
  99. pyvista_cad-0.0.1/src/pyvista_cad/_readers/three_mf.py +81 -0
  100. pyvista_cad-0.0.1/src/pyvista_cad/_version.py +24 -0
  101. pyvista_cad-0.0.1/src/pyvista_cad/examples/__init__.py +94 -0
  102. pyvista_cad-0.0.1/src/pyvista_cad/examples/_generate.py +376 -0
  103. pyvista_cad-0.0.1/src/pyvista_cad/examples/data/SOURCES.md +24 -0
  104. pyvista_cad-0.0.1/src/pyvista_cad/examples/data/assembly.3mf +0 -0
  105. pyvista_cad-0.0.1/src/pyvista_cad/examples/data/bracket.step +705 -0
  106. pyvista_cad-0.0.1/src/pyvista_cad/examples/data/cube.step +415 -0
  107. pyvista_cad-0.0.1/src/pyvista_cad/examples/data/drawing.dxf +13378 -0
  108. pyvista_cad-0.0.1/src/pyvista_cad/examples/data/plate.dxf +3208 -0
  109. pyvista_cad-0.0.1/src/pyvista_cad/examples/data/small_building.ifc +103 -0
  110. pyvista_cad-0.0.1/src/pyvista_cad/examples/downloads.py +286 -0
  111. pyvista_cad-0.0.1/src/pyvista_cad/py.typed +0 -0
  112. pyvista_cad-0.0.1/src/pyvista_cad.egg-info/PKG-INFO +219 -0
  113. pyvista_cad-0.0.1/src/pyvista_cad.egg-info/SOURCES.txt +186 -0
  114. pyvista_cad-0.0.1/src/pyvista_cad.egg-info/dependency_links.txt +1 -0
  115. pyvista_cad-0.0.1/src/pyvista_cad.egg-info/entry_points.txt +16 -0
  116. pyvista_cad-0.0.1/src/pyvista_cad.egg-info/requires.txt +56 -0
  117. pyvista_cad-0.0.1/src/pyvista_cad.egg-info/top_level.txt +1 -0
  118. pyvista_cad-0.0.1/tests/__init__.py +0 -0
  119. pyvista_cad-0.0.1/tests/conftest.py +86 -0
  120. pyvista_cad-0.0.1/tests/data/README.md +138 -0
  121. pyvista_cad-0.0.1/tests/data/_generate_fixtures.py +821 -0
  122. pyvista_cad-0.0.1/tests/data/assembly_two_parts.step +585 -0
  123. pyvista_cad-0.0.1/tests/data/building.ifc +45 -0
  124. pyvista_cad-0.0.1/tests/data/dxf_r12.dxf +1224 -0
  125. pyvista_cad-0.0.1/tests/data/dxf_r2018.dxf +3298 -0
  126. pyvista_cad-0.0.1/tests/data/external.brep +303 -0
  127. pyvista_cad-0.0.1/tests/data/impeller.iges +92 -0
  128. pyvista_cad-0.0.1/tests/data/multimaterial.3mf +0 -0
  129. pyvista_cad-0.0.1/tests/image_cache/asymmetric_part_image.png +0 -0
  130. pyvista_cad-0.0.1/tests/image_cache/cad_view_faces_and_topological_edges.png +0 -0
  131. pyvista_cad-0.0.1/tests/image_cache/cad_view_image_regression.png +0 -0
  132. pyvista_cad-0.0.1/tests/image_cache/filleted_box_image_regression.png +0 -0
  133. pyvista_cad-0.0.1/tests/image_cache/read_dxf_image.png +0 -0
  134. pyvista_cad-0.0.1/tests/image_cache/read_step_image.png +0 -0
  135. pyvista_cad-0.0.1/tests/perf/__init__.py +0 -0
  136. pyvista_cad-0.0.1/tests/perf/conftest.py +76 -0
  137. pyvista_cad-0.0.1/tests/perf/test_3mf_read.py +61 -0
  138. pyvista_cad-0.0.1/tests/perf/test_dxf_read.py +36 -0
  139. pyvista_cad-0.0.1/tests/perf/test_import_cold.py +72 -0
  140. pyvista_cad-0.0.1/tests/perf/test_multiblock_walk.py +43 -0
  141. pyvista_cad-0.0.1/tests/perf/test_split_by_layer.py +39 -0
  142. pyvista_cad-0.0.1/tests/perf/test_step_read.py +81 -0
  143. pyvista_cad-0.0.1/tests/test_accessor.py +142 -0
  144. pyvista_cad-0.0.1/tests/test_accessor_coverage.py +1286 -0
  145. pyvista_cad-0.0.1/tests/test_bridges/__init__.py +0 -0
  146. pyvista_cad-0.0.1/tests/test_bridges/test_bridge_paths.py +302 -0
  147. pyvista_cad-0.0.1/tests/test_bridges/test_build123d.py +42 -0
  148. pyvista_cad-0.0.1/tests/test_bridges/test_cadquery.py +24 -0
  149. pyvista_cad-0.0.1/tests/test_bridges/test_gmsh.py +24 -0
  150. pyvista_cad-0.0.1/tests/test_bridges/test_import_errors.py +74 -0
  151. pyvista_cad-0.0.1/tests/test_bridges/test_topods.py +53 -0
  152. pyvista_cad-0.0.1/tests/test_cad_view.py +136 -0
  153. pyvista_cad-0.0.1/tests/test_cad_view_branches.py +796 -0
  154. pyvista_cad-0.0.1/tests/test_conversion.py +403 -0
  155. pyvista_cad-0.0.1/tests/test_coverage_contract.py +202 -0
  156. pyvista_cad-0.0.1/tests/test_errors.py +96 -0
  157. pyvista_cad-0.0.1/tests/test_examples.py +380 -0
  158. pyvista_cad-0.0.1/tests/test_image_regression.py +151 -0
  159. pyvista_cad-0.0.1/tests/test_lazy_imports.py +278 -0
  160. pyvista_cad-0.0.1/tests/test_metadata.py +280 -0
  161. pyvista_cad-0.0.1/tests/test_multiblock_methods.py +122 -0
  162. pyvista_cad-0.0.1/tests/test_packaging_contract.py +98 -0
  163. pyvista_cad-0.0.1/tests/test_plugin_registration.py +207 -0
  164. pyvista_cad-0.0.1/tests/test_properties.py +205 -0
  165. pyvista_cad-0.0.1/tests/test_readers/__init__.py +0 -0
  166. pyvista_cad-0.0.1/tests/test_readers/test_brep.py +95 -0
  167. pyvista_cad-0.0.1/tests/test_readers/test_cascadio.py +64 -0
  168. pyvista_cad-0.0.1/tests/test_readers/test_dxf.py +112 -0
  169. pyvista_cad-0.0.1/tests/test_readers/test_fcstd.py +84 -0
  170. pyvista_cad-0.0.1/tests/test_readers/test_gltf.py +160 -0
  171. pyvista_cad-0.0.1/tests/test_readers/test_ifc.py +259 -0
  172. pyvista_cad-0.0.1/tests/test_readers/test_iges.py +58 -0
  173. pyvista_cad-0.0.1/tests/test_readers/test_scad.py +70 -0
  174. pyvista_cad-0.0.1/tests/test_readers/test_step.py +163 -0
  175. pyvista_cad-0.0.1/tests/test_readers/test_three_mf.py +146 -0
  176. pyvista_cad-0.0.1/tests/test_roundtrip/__init__.py +0 -0
  177. pyvista_cad-0.0.1/tests/test_roundtrip/test_brep_roundtrip.py +47 -0
  178. pyvista_cad-0.0.1/tests/test_roundtrip/test_dxf_roundtrip.py +72 -0
  179. pyvista_cad-0.0.1/tests/test_roundtrip/test_gltf_roundtrip.py +140 -0
  180. pyvista_cad-0.0.1/tests/test_roundtrip/test_ifc_roundtrip.py +165 -0
  181. pyvista_cad-0.0.1/tests/test_roundtrip/test_iges_roundtrip.py +35 -0
  182. pyvista_cad-0.0.1/tests/test_roundtrip/test_step_roundtrip.py +129 -0
  183. pyvista_cad-0.0.1/tests/test_roundtrip/test_three_mf_roundtrip.py +161 -0
  184. pyvista_cad-0.0.1/tests/test_writers/__init__.py +0 -0
  185. pyvista_cad-0.0.1/tests/test_writers/test_brep.py +80 -0
  186. pyvista_cad-0.0.1/tests/test_writers/test_dxf.py +45 -0
  187. pyvista_cad-0.0.1/tests/test_writers/test_step.py +353 -0
  188. pyvista_cad-0.0.1/tests/test_writers/test_three_mf.py +63 -0
@@ -0,0 +1,19 @@
1
+ # CAD / mesh fixtures are opaque payloads. Treat them as binary so git
2
+ # never does EOL conversion, diff, or merge text munging on them.
3
+ *.step binary
4
+ *.stp binary
5
+ *.dxf binary
6
+ *.brep binary
7
+ *.iges binary
8
+ *.igs binary
9
+ *.3mf binary
10
+ *.ifc binary
11
+ *.scad binary
12
+ *.glb binary
13
+ *.gltf binary
14
+ *.stl binary
15
+ *.obj binary
16
+ *.ply binary
17
+ *.vtk binary
18
+ *.vtu binary
19
+ *.vtp binary
@@ -0,0 +1 @@
1
+ github: [banesullivan]
@@ -0,0 +1,11 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "pip"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "weekly"
7
+ open-pull-requests-limit: 5
8
+ - package-ecosystem: "github-actions"
9
+ directory: "/"
10
+ schedule:
11
+ interval: "weekly"
@@ -0,0 +1,171 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ tags: ["v*"]
7
+ pull_request:
8
+ branches: [main]
9
+
10
+ concurrency:
11
+ group: ${{ github.workflow }}-${{ github.ref }}
12
+ cancel-in-progress: true
13
+
14
+ jobs:
15
+ lint:
16
+ runs-on: ubuntu-latest
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+ with:
20
+ fetch-depth: 0
21
+ - uses: astral-sh/setup-uv@v6
22
+ - run: uv sync --extra dev
23
+ - run: uv run ruff check .
24
+ - run: uv run ruff format --check .
25
+ - run: uv run mypy src/pyvista_cad
26
+
27
+ test:
28
+ runs-on: ${{ matrix.os }}
29
+ strategy:
30
+ fail-fast: false
31
+ matrix:
32
+ os: [ubuntu-latest, macos-14, windows-latest]
33
+ # 3.14 is intentionally absent: every test extra transitively
34
+ # pulls `cadquery` (dev -> docs -> full -> cadquery), and
35
+ # `cadquery-ocp` ships no cp314 wheel for any platform/version,
36
+ # so the env is uninstallable on 3.14. Re-add once cadquery-ocp
37
+ # publishes cp314 wheels. requires-python stays `>=3.10`.
38
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
39
+ # `dev,full` carries `step-light` (cascadio) so the cascadio STEP
40
+ # backend E2E runs in CI; `openscad` is installed via apt on Linux
41
+ # so the SCAD reader E2E runs there too. One combination gaining
42
+ # these is enough — the matrix shape is unchanged.
43
+ extras: ["dev", "dev,step", "dev,full,step-light"]
44
+ exclude:
45
+ - os: windows-latest
46
+ extras: "dev,full,step-light"
47
+ steps:
48
+ - uses: actions/checkout@v4
49
+ with:
50
+ fetch-depth: 0
51
+ - uses: astral-sh/setup-uv@v6
52
+ with:
53
+ python-version: ${{ matrix.python-version }}
54
+ - name: Set up headless display
55
+ uses: pyvista/setup-headless-display-action@v4
56
+ - name: Install system packages for OCCT / gmsh backends
57
+ if: runner.os == 'Linux'
58
+ run: |
59
+ sudo apt-get update
60
+ sudo apt-get install -y \
61
+ libgl1-mesa-dev libglu1 libxft2 libxcursor-dev libxinerama1 \
62
+ libocct-data-exchange-dev libocct-foundation-dev xvfb openscad
63
+ - name: Install dependencies
64
+ run: uv sync --extra ${{ matrix.extras }}
65
+ - name: Run tests
66
+ run: uv run pytest tests/ --cov --cov-report=xml -v
67
+ - name: Upload coverage
68
+ if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.13' && matrix.extras == 'dev,full,step-light'
69
+ uses: codecov/codecov-action@v5
70
+ with:
71
+ files: coverage.xml
72
+ fail_ci_if_error: false
73
+ - name: Upload image-cache failures
74
+ if: failure()
75
+ uses: actions/upload-artifact@v4
76
+ with:
77
+ name: image-cache-failures-${{ matrix.os }}-py${{ matrix.python-version }}-${{ matrix.extras }}
78
+ path: tests/image_cache_failures/
79
+ if-no-files-found: ignore
80
+
81
+ lazy-imports:
82
+ # Mission goal #4: `import pyvista_cad` must not import build123d,
83
+ # cascadio, OCP, lib3mf, ifcopenshell, gmsh, FreeCAD, pyiges, geomdl.
84
+ # This job installs ONLY the core package (DXF-only via ezdxf) so a
85
+ # leaked import would actually be detectable (modules aren't on the
86
+ # path, ImportError would surface). The matrix-`test` job above runs
87
+ # with `[full]` and so cannot enforce this invariant.
88
+ name: Lazy-imports guardrail (minimal extras)
89
+ runs-on: ubuntu-latest
90
+ steps:
91
+ - uses: actions/checkout@v4
92
+ with:
93
+ fetch-depth: 0
94
+ - uses: astral-sh/setup-uv@v6
95
+ with:
96
+ python-version: "3.13"
97
+ - name: Install minimal (core + pytest only, no optional backends)
98
+ # pytest-pyvista is a test plugin (not a CAD backend); it owns
99
+ # the `image_cache_dir` pytest ini option, so omitting it makes
100
+ # pytest fail at config time with strict-warnings enabled.
101
+ run: |
102
+ uv venv
103
+ uv pip install -e . pytest pytest-pyvista
104
+ - name: Run lazy-imports guardrail
105
+ run: uv run pytest tests/test_lazy_imports.py -v
106
+
107
+ benchmark:
108
+ # Ubuntu-only because cross-platform timing is noisy. The first
109
+ # green run on `main` establishes the baseline; the 5% regression
110
+ # gate lands in a follow-up once `bench.json` has been compared
111
+ # across at least two runs.
112
+ name: Benchmark (perf regression gate)
113
+ runs-on: ubuntu-latest
114
+ # Informational until the cross-run 5% regression gate lands: absolute
115
+ # wall-clock budgets are too noisy on shared runners to block CI.
116
+ continue-on-error: true
117
+ steps:
118
+ - uses: actions/checkout@v4
119
+ with:
120
+ fetch-depth: 0
121
+ - uses: astral-sh/setup-uv@v6
122
+ with:
123
+ python-version: "3.13"
124
+ - uses: pyvista/setup-headless-display-action@v4
125
+ - name: Install [dev,full] for end-to-end perf cases
126
+ run: uv sync --extra dev --extra full
127
+ - name: Run benchmarks
128
+ # Absolute wall-clock budgets flake on shared runners; soft mode
129
+ # records breaches without failing the job. bench.json is still
130
+ # emitted for the planned cross-run regression gate.
131
+ env:
132
+ PYVISTA_CAD_PERF_SOFT: "1"
133
+ run: |
134
+ uv run pytest tests/perf/ \
135
+ --benchmark-only \
136
+ --benchmark-json=bench.json \
137
+ -v
138
+ - name: Upload benchmark JSON
139
+ uses: actions/upload-artifact@v4
140
+ with:
141
+ name: bench-json
142
+ path: bench.json
143
+ if-no-files-found: error
144
+
145
+ build:
146
+ runs-on: ubuntu-latest
147
+ needs: [lint, test]
148
+ steps:
149
+ - uses: actions/checkout@v4
150
+ with:
151
+ fetch-depth: 0
152
+ - uses: astral-sh/setup-uv@v6
153
+ - run: uv build
154
+ - uses: actions/upload-artifact@v4
155
+ with:
156
+ name: dist
157
+ path: dist/
158
+
159
+ publish:
160
+ runs-on: ubuntu-latest
161
+ needs: [build]
162
+ if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
163
+ environment: release
164
+ permissions:
165
+ id-token: write
166
+ steps:
167
+ - uses: actions/download-artifact@v4
168
+ with:
169
+ name: dist
170
+ path: dist/
171
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,87 @@
1
+ name: Docs
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ tags: ["v*"]
7
+ pull_request:
8
+ branches: [main]
9
+ workflow_dispatch:
10
+
11
+ concurrency:
12
+ group: ${{ github.workflow }}-${{ github.ref }}
13
+ cancel-in-progress: true
14
+
15
+ permissions:
16
+ contents: read
17
+ pages: write
18
+ id-token: write
19
+
20
+ jobs:
21
+ build:
22
+ name: Build Sphinx docs + gallery
23
+ runs-on: ubuntu-24.04
24
+ steps:
25
+ - uses: actions/checkout@v4
26
+ with:
27
+ fetch-depth: 0
28
+
29
+ - uses: astral-sh/setup-uv@v6
30
+ with:
31
+ python-version: "3.13"
32
+
33
+ - name: Set up headless display
34
+ uses: pyvista/setup-headless-display-action@v4
35
+
36
+ - name: Install system packages for OCCT-backed examples
37
+ run: |
38
+ sudo apt-get update
39
+ sudo apt-get install -y \
40
+ libgl1-mesa-dev libglu1 libxft2 libxcursor-dev libxinerama1 \
41
+ libocct-data-exchange-dev libocct-foundation-dev xvfb pandoc openscad
42
+
43
+ - name: Install with [docs]
44
+ run: uv sync --extra docs
45
+
46
+ - name: Build documentation
47
+ run: uv run make -C doc html
48
+
49
+ - name: Prevent Jekyll processing on GH Pages
50
+ run: touch doc/_build/html/.nojekyll
51
+
52
+ - name: Upload Pages artifact
53
+ uses: actions/upload-pages-artifact@v3
54
+ with:
55
+ path: doc/_build/html/
56
+
57
+ deploy:
58
+ name: Deploy to GitHub Pages
59
+ needs: build
60
+ if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v'))
61
+ runs-on: ubuntu-24.04
62
+ environment:
63
+ name: github-pages
64
+ url: ${{ steps.deployment.outputs.page_url }}
65
+ steps:
66
+ - name: Deploy to GitHub Pages
67
+ id: deployment
68
+ uses: actions/deploy-pages@v4
69
+
70
+ doctest:
71
+ name: Doctest
72
+ runs-on: ubuntu-24.04
73
+ needs: build
74
+ steps:
75
+ - uses: actions/checkout@v4
76
+ - uses: astral-sh/setup-uv@v6
77
+ with:
78
+ python-version: "3.13"
79
+ - uses: pyvista/setup-headless-display-action@v4
80
+ - name: Install system packages for OCCT-backed examples
81
+ run: |
82
+ sudo apt-get update
83
+ sudo apt-get install -y \
84
+ libgl1-mesa-dev libglu1 libxft2 libxcursor-dev libxinerama1 \
85
+ libocct-data-exchange-dev libocct-foundation-dev xvfb pandoc openscad
86
+ - run: uv sync --extra docs
87
+ - run: uv run make -C doc doctest
@@ -0,0 +1,60 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ dist/
6
+ build/
7
+ *.egg
8
+
9
+ # Virtual environments
10
+ .venv/
11
+
12
+ # uv lockfile (library: resolve fresh, do not pin)
13
+ uv.lock
14
+
15
+ # Testing / coverage / benchmarks
16
+ .coverage
17
+ .pytest_cache/
18
+ .benchmarks/
19
+ .hypothesis/
20
+ htmlcov/
21
+ coverage.xml
22
+
23
+ # Type checking / linting
24
+ .mypy_cache/
25
+ .ruff_cache/
26
+
27
+ # Profiling
28
+ *.prof
29
+
30
+ # OS
31
+ .DS_Store
32
+
33
+ # IDE
34
+ .idea/
35
+ .vscode/
36
+ *.swp
37
+ *.swo
38
+
39
+ # Agent / local tooling
40
+ .claude/
41
+
42
+ # Local-only notes, design docs, audits, benchmarks (not published)
43
+ notes/
44
+
45
+ # setuptools_scm-generated version file
46
+ src/pyvista_cad/_version.py
47
+
48
+ # Local env
49
+ .env
50
+
51
+ # pytest-pyvista regression failures
52
+ tests/image_cache_failures/
53
+
54
+ # Sphinx + Sphinx Gallery build artifacts
55
+ doc/_build/
56
+ doc/examples/
57
+ doc/sg_execution_times.rst
58
+ doc/api/_autosummary/
59
+ doc/api/_backrefs/
60
+ errors.txt
@@ -0,0 +1,79 @@
1
+ ci:
2
+ autoupdate_schedule: monthly
3
+
4
+ # CAD/mesh fixtures are opaque binary-ish payloads. Whitespace,
5
+ # end-of-file, line-ending, and spell hooks must never rewrite them.
6
+ exclude: |
7
+ (?x)^(
8
+ .*\.(step|stp|dxf|brep|iges|igs|3mf|ifc|scad|glb|gltf|stl|obj|ply|vtk|vtu|vtp)
9
+ )$
10
+
11
+ repos:
12
+ - repo: https://github.com/numpy/numpydoc
13
+ rev: v1.10.0
14
+ hooks:
15
+ - id: numpydoc-validation
16
+ files: ^src/pyvista_cad/
17
+
18
+ - repo: https://github.com/pre-commit/pre-commit-hooks
19
+ rev: v6.0.0
20
+ hooks:
21
+ - id: check-added-large-files
22
+ args: [--maxkb, "5000"]
23
+ - id: check-json
24
+ - id: check-merge-conflict
25
+ - id: check-shebang-scripts-are-executable
26
+ - id: check-toml
27
+ - id: check-yaml
28
+ - id: debug-statements
29
+ - id: detect-private-key
30
+ - id: trailing-whitespace
31
+ - id: check-docstring-first
32
+ - id: end-of-file-fixer
33
+ - id: mixed-line-ending
34
+
35
+ - repo: https://github.com/astral-sh/ruff-pre-commit
36
+ rev: v0.15.1
37
+ hooks:
38
+ - id: ruff-format
39
+ - id: ruff-check
40
+ args: ["--fix", "--show-fixes"]
41
+
42
+ - repo: https://github.com/rbubley/mirrors-prettier
43
+ rev: v3.8.1
44
+ hooks:
45
+ - id: prettier
46
+ types_or: [yaml, markdown, json]
47
+
48
+ - repo: https://github.com/gitleaks/gitleaks
49
+ rev: v8.30.0
50
+ hooks:
51
+ - id: gitleaks
52
+
53
+ - repo: https://github.com/python-jsonschema/check-jsonschema
54
+ rev: 0.36.1
55
+ hooks:
56
+ - id: check-github-workflows
57
+
58
+ - repo: https://github.com/ComPWA/taplo-pre-commit
59
+ rev: v0.9.3
60
+ hooks:
61
+ - id: taplo-format
62
+
63
+ - repo: https://github.com/streetsidesoftware/cspell-cli
64
+ rev: v9.2.0
65
+ hooks:
66
+ - id: cspell
67
+ # cspell-cli v9 needs Node >=20.18; pin so the hook does not
68
+ # fall back to whatever Node is on PATH (system Node may be 18).
69
+ language_version: "22.22.1"
70
+ args: ["--no-progress", "--no-summary"]
71
+
72
+ - repo: local
73
+ hooks:
74
+ - id: format-justfile
75
+ name: Format justfile
76
+ entry: just --fmt --unstable
77
+ language: system
78
+ files: "(^|/)justfile$|\\.just$"
79
+ pass_filenames: false
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 The PyVista Developers
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,219 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyvista-cad
3
+ Version: 0.0.1
4
+ Summary: PyVista accessor and reader-registry plugin for CAD formats (STEP, IGES, BREP, DXF, 3MF, IFC, FCStd) and bridges to build123d, cadquery, OCP, and gmsh.
5
+ Author-email: The PyVista Developers <info@pyvista.org>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/pyvista/pyvista-cad
8
+ Project-URL: Documentation, https://pyvista.github.io/pyvista-cad/
9
+ Project-URL: Issues, https://github.com/pyvista/pyvista-cad/issues
10
+ Project-URL: Repository, https://github.com/pyvista/pyvista-cad
11
+ Keywords: 3d,pyvista,cad,step,iges,brep,dxf,3mf,ifc,build123d,cadquery,opencascade
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: Operating System :: MacOS
16
+ Classifier: Operating System :: POSIX :: Linux
17
+ Classifier: Operating System :: Microsoft :: Windows
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Programming Language :: Python :: 3.14
24
+ Classifier: Topic :: Scientific/Engineering :: Visualization
25
+ Classifier: Topic :: Multimedia :: Graphics :: 3D Modeling
26
+ Classifier: Topic :: Scientific/Engineering :: Information Analysis
27
+ Classifier: Typing :: Typed
28
+ Requires-Python: >=3.10
29
+ Description-Content-Type: text/markdown
30
+ License-File: LICENSE
31
+ Requires-Dist: ezdxf>=1.3
32
+ Requires-Dist: numpy>=1.24
33
+ Requires-Dist: pooch>=1.8
34
+ Requires-Dist: pyvista>=0.48.4
35
+ Provides-Extra: step
36
+ Requires-Dist: build123d>=0.7; extra == "step"
37
+ Provides-Extra: step-light
38
+ Requires-Dist: cascadio>=0.0.17; extra == "step-light"
39
+ Provides-Extra: 3mf
40
+ Requires-Dist: lib3mf>=2.3; extra == "3mf"
41
+ Provides-Extra: ifc
42
+ Requires-Dist: ifcopenshell>=0.7.0; extra == "ifc"
43
+ Provides-Extra: iges
44
+ Requires-Dist: pyiges[full]>=0.3; extra == "iges"
45
+ Provides-Extra: gmsh
46
+ Requires-Dist: gmsh>=4.13; extra == "gmsh"
47
+ Provides-Extra: cadquery
48
+ Requires-Dist: cadquery>=2.4; extra == "cadquery"
49
+ Provides-Extra: trimesh
50
+ Requires-Dist: pyvista-trimesh>=0.1; extra == "trimesh"
51
+ Provides-Extra: full
52
+ Requires-Dist: pyvista-cad[3mf,cadquery,gmsh,ifc,iges,step,trimesh]; extra == "full"
53
+ Provides-Extra: docs
54
+ Requires-Dist: pyvista-cad[full]; extra == "docs"
55
+ Requires-Dist: cadquery>=2.4; extra == "docs"
56
+ Requires-Dist: pandas>=2.0; extra == "docs"
57
+ Requires-Dist: sphinx>=8.0; extra == "docs"
58
+ Requires-Dist: sphinx-gallery>=0.18; extra == "docs"
59
+ Requires-Dist: sphinx-design>=0.6; extra == "docs"
60
+ Requires-Dist: sphinx-copybutton>=0.5; extra == "docs"
61
+ Requires-Dist: sphinx-book-theme>=1.1; extra == "docs"
62
+ Requires-Dist: myst-parser>=4.0; extra == "docs"
63
+ Requires-Dist: sphinx-notfound-page>=1.1; extra == "docs"
64
+ Requires-Dist: numpydoc>=1.10; extra == "docs"
65
+ Requires-Dist: pypandoc>=1.13; extra == "docs"
66
+ Requires-Dist: pyvista[jupyter]; extra == "docs"
67
+ Provides-Extra: dev
68
+ Requires-Dist: pyvista-cad[docs]; extra == "dev"
69
+ Requires-Dist: mypy==2.1.0; extra == "dev"
70
+ Requires-Dist: ruff==0.15.13; extra == "dev"
71
+ Requires-Dist: pytest>=8.0; extra == "dev"
72
+ Requires-Dist: pytest-benchmark>=4.0; extra == "dev"
73
+ Requires-Dist: pytest-cov>=5.0; extra == "dev"
74
+ Requires-Dist: pytest-pyvista>=0.2; extra == "dev"
75
+ Requires-Dist: hypothesis>=6.100; extra == "dev"
76
+ Dynamic: license-file
77
+
78
+ <p align="center">
79
+ <img src="https://github.com/pyvista/pyvista/raw/main/doc/source/_static/pyvista_logo.svg" alt="PyVista" width="400" />
80
+ </p>
81
+
82
+ # pyvista-cad
83
+
84
+ [![CI](https://github.com/pyvista/pyvista-cad/actions/workflows/ci.yml/badge.svg)](https://github.com/pyvista/pyvista-cad/actions/workflows/ci.yml)
85
+ [![PyPI](https://img.shields.io/pypi/v/pyvista-cad.svg)](https://pypi.org/project/pyvista-cad/)
86
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
87
+
88
+ **CAD format reading, writing, and CAD-style plotting for [PyVista](https://github.com/pyvista/pyvista).**
89
+
90
+ <p align="center">
91
+ <img src="https://raw.githubusercontent.com/pyvista/pyvista-cad/main/doc/_static/hero.png" alt="The same flange shown two ways: a generic mesh viewer drawing the raw triangulation on the left, and pyvista-cad drawing smoothly shaded faces with the model's topological edges on the right." width="90%">
92
+ </p>
93
+
94
+ `pyvista-cad` adds CAD-format support to PyVista: STEP, IGES, BREP, DXF, 3MF, IFC, FreeCAD `.fcstd`, OpenSCAD `.scad`, and glTF. It registers a `.cad` accessor on every `pv.DataSet` / `pv.MultiBlock` and wires reader entries into `pv.read(...)`. It also adds CAD-style rendering: smoothly shaded faces with the model's topological B-rep edges instead of triangle-mesh noise, via `.cad.plot()` and a `plotter.cad` component. No monkey-patching, no forks, no direct VTK calls.
95
+
96
+ ## Install matrix
97
+
98
+ | Extra | Adds | Formats unlocked |
99
+ | -------------- | ----------------------- | ----------------------------------- |
100
+ | (base) | ezdxf | DXF read + write, glTF read + write |
101
+ | `[step]` | build123d, cadquery-ocp | STEP, BREP, FCStd, build123d bridge |
102
+ | `[step-light]` | cascadio | STEP (read-only, faster, no colors) |
103
+ | `[3mf]` | lib3mf | 3MF read + write |
104
+ | `[ifc]` | ifcopenshell | IFC read (with property sets) |
105
+ | `[iges]` | pyiges[full] | IGES read |
106
+ | `[gmsh]` | gmsh | gmsh bridge for FEA meshing |
107
+ | `[openscad]` | (uses `openscad` CLI) | SCAD read |
108
+ | `[full]` | all of the above | every supported format |
109
+
110
+ **Python support:** 3.10 – 3.13. Python 3.14 is not yet supported: the
111
+ `[step]`/`[full]` extras depend on `cadquery-ocp`, which publishes no
112
+ cp314 wheels for any platform. 3.14 will be added once those wheels ship.
113
+
114
+ trimesh interop is provided by pyvista core (`pyvista.from_trimesh`, `pyvista.to_trimesh`) and the `pyvista-trimesh` package's `.trimesh` accessor (install `pyvista-cad[trimesh]`); pyvista-cad does not duplicate it.
115
+
116
+ ```bash
117
+ pip install pyvista-cad # DXF and glTF only
118
+ pip install pyvista-cad[step] # add STEP, BREP, FCStd
119
+ pip install pyvista-cad[full] # everything
120
+ ```
121
+
122
+ ## Quick start
123
+
124
+ ```python
125
+ import pyvista as pv
126
+ import pyvista_cad # registers the .cad accessor and reader entries
127
+
128
+ mesh = pv.read('part.step') # MultiBlock of parts with cad.color, cad.label
129
+ mesh.plot(show_edges=True)
130
+
131
+ floorplan = pv.read('floor.dxf') # PolyData with Layer cell data
132
+ layers = floorplan.cad.split_by_layer() # MultiBlock keyed on layer
133
+ ```
134
+
135
+ <p align="center">
136
+ <img src="https://raw.githubusercontent.com/pyvista/pyvista-cad/main/doc/_static/readme_quickstart.png" alt="Two independent example fixtures. Left: a STEP part read with pv.read, drawn CAD-style with shaded faces and topological edges. Right: a DXF drawing split into colored per-layer blocks (body, centerlines, dimensions, holes)." width="90%">
137
+ </p>
138
+
139
+ ## CAD-friendly plotting
140
+
141
+ A generic mesh viewer draws the _triangulation_. With `show_edges=True` you see every facet edge, an artifact of the tessellation tolerance. A CAD application instead shows smoothly shaded faces with the model's _topological_ edges (the B-rep feature curves) on top. `pyvista-cad` reproduces that: analytic surface normals so a coarse mesh still shades round, topological edges recovered from the cached B-rep, triangle edges hidden.
142
+
143
+ ```python
144
+ import pyvista as pv
145
+ import pyvista_cad
146
+ from pyvista_cad.examples import downloads
147
+
148
+ mb = pyvista_cad.read_step(downloads.step_part_path()) # NIST AM Bench specimen
149
+
150
+ mb.cad.plot() # shaded faces + topological edges
151
+
152
+ # Or compose it into a scene, color faces by a scalar, keep the edges:
153
+ part = mb[0] # a cached block keeps its B-rep
154
+ part['height'] = part.points[:, 2]
155
+ pl = pv.Plotter()
156
+ pl.cad.add(part, scalars='height', cmap='viridis')
157
+ pl.show()
158
+ ```
159
+
160
+ <p align="center">
161
+ <img src="https://raw.githubusercontent.com/pyvista/pyvista-cad/main/doc/_static/readme_cad_plotting.png" alt="The NIST AM Bench specimen. Left: cad.plot draws shaded faces with topological B-rep edges. Right: the same cached block colored by a height scalar with the viridis colormap, the topological edges still drawn." width="90%">
162
+ </p>
163
+
164
+ `.cad.plot()` and the `plotter.cad` component accept a `MultiBlock`, `PolyData`, raw `TopoDS`, or a build123d / cadquery object; a plain mesh with no B-rep origin degrades to crease feature edges.
165
+
166
+ ## Real-world workflow
167
+
168
+ Load a STEP assembly, locate a part, drive it through gmsh to a
169
+ tetrahedral FEA mesh, then clip to expose the interior. Needs the
170
+ `[gmsh]` extra.
171
+
172
+ ```python
173
+ import gmsh
174
+ import pyvista as pv
175
+ import pyvista_cad
176
+ from pyvista_cad.examples import downloads
177
+
178
+ assembly = pv.read(downloads.step_assembly_path()) # 3-part NIST build assembly
179
+ print(assembly.cad.assembly_tree()) # nested dict of block names
180
+ matches = assembly.cad.find('*PartCAD') # glob -> list of (path, block)
181
+ path, part = matches[0]
182
+
183
+ gmsh.initialize()
184
+ try:
185
+ gmsh.model.occ.importShapes(downloads.step_part_path())
186
+ gmsh.model.occ.synchronize()
187
+ gmsh.option.setNumber('Mesh.MeshSizeMax', 2.0)
188
+ gmsh.model.mesh.generate(3)
189
+ grid = pyvista_cad.from_gmsh()
190
+ finally:
191
+ gmsh.finalize()
192
+
193
+ grid = grid.extract_cells(grid.celltypes == 10) # keep VTK_TETRA
194
+ clip = grid.clip(normal='x', crinkle=True)
195
+ clip.save('part_tets.vtu') # full tet mesh round-trips
196
+ ```
197
+
198
+ <p align="center">
199
+ <img src="https://raw.githubusercontent.com/pyvista/pyvista-cad/main/doc/_static/readme_workflow.png" alt="A 3-part NIST build assembly. Three steps: the full assembly as read (CAD-style), the located PartCAD component highlighted against the muted rest, then that part meshed tetrahedrally with gmsh and crinkle-clipped to expose the colored tet interior." width="100%">
200
+ </p>
201
+
202
+ The Quick start uses bundled offline fixtures (`bracket_step_path()`, a parametric L-bracket committed as STEP; `drawing_dxf_path()`, a layered 2D drawing). The other examples pull real, openly licensed parts from `pyvista_cad.examples.downloads` (cached on first fetch) — the NIST AM Bench LPBF specimen and its 3-part build assembly.
203
+
204
+ ## Common tasks
205
+
206
+ | Task | How |
207
+ | ----------------------------------------- | ----------------------------------------------------------------------------------------- |
208
+ | Read a STEP assembly with per-part colors | `pv.read('a.step')` returns a `MultiBlock`; each block has `cad.color` and `cad.label` |
209
+ | Split a DXF by layer | `pv.read('a.dxf').cad.split_by_layer()` |
210
+ | Round-trip a 3MF print | `pyvista_cad.write_three_mf(mb, 'b.3mf')` (object color + units kept) |
211
+ | Load an IFC building and filter walls | `mb = pv.read('b.ifc'); walls = mb.cad.find(ifc_type='IfcWall')` |
212
+ | Read IFC property sets | `json.loads(block.field_data['cad.psets'][0])` returns the source `Pset_*` / `Qto_*` dict |
213
+ | Convert build123d to PyVista | `pyvista_cad.from_build123d(part)` (preserves color, label, transform) |
214
+ | Mesh a STEP for FEA in gmsh | `pyvista_cad.to_gmsh(...)` then gmsh; see `examples/05_workflows/cad_to_fea_tet_mesh.py` |
215
+ | Generate a signed distance field from CAD | see `examples/05_workflows/cad_to_signed_distance.py` |
216
+
217
+ ## Fidelity and limitations
218
+
219
+ Round-trip fidelity varies by format. Tessellated formats (STEP, IGES, BREP, FCStd) discretize analytic surfaces on read; the originating B-rep is cached so `tessellate()` can refine it. DXF and 3MF round-trip geometry and metadata within documented tolerances. IGES and SCAD are read-only.