icadkit 0.3.5__tar.gz → 0.3.7__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 (137) hide show
  1. {icadkit-0.3.5 → icadkit-0.3.7}/Cargo.lock +4 -4
  2. {icadkit-0.3.5 → icadkit-0.3.7}/Cargo.toml +2 -2
  3. {icadkit-0.3.5 → icadkit-0.3.7}/LICENSES/rust-dependencies.txt +1 -1
  4. {icadkit-0.3.5 → icadkit-0.3.7}/PKG-INFO +28 -27
  5. {icadkit-0.3.5 → icadkit-0.3.7}/README.md +26 -25
  6. {icadkit-0.3.5 → icadkit-0.3.7}/THIRD_PARTY_NOTICES.md +7 -5
  7. {icadkit-0.3.5 → icadkit-0.3.7}/crates/icad-core/LICENSE +9 -7
  8. icadkit-0.3.7/crates/icad-core/build.rs +49 -0
  9. {icadkit-0.3.5 → icadkit-0.3.7}/crates/icad-core/src/document.rs +13 -0
  10. {icadkit-0.3.5 → icadkit-0.3.7}/crates/icad-core/src/lib.rs +3 -3
  11. {icadkit-0.3.5 → icadkit-0.3.7}/crates/icad-core/src/native.rs +93 -2
  12. {icadkit-0.3.5 → icadkit-0.3.7}/crates/icad-core/src/trailer.rs +294 -0
  13. {icadkit-0.3.5 → icadkit-0.3.7}/crates/icad-core/tests/resources.rs +32 -8
  14. {icadkit-0.3.5 → icadkit-0.3.7}/crates/icad-python/LICENSE +9 -7
  15. {icadkit-0.3.5 → icadkit-0.3.7}/crates/icad-python/src/brep.rs +19 -0
  16. {icadkit-0.3.5 → icadkit-0.3.7}/crates/icad-python/src/document.rs +77 -33
  17. {icadkit-0.3.5 → icadkit-0.3.7}/docs/api.md +3 -2
  18. {icadkit-0.3.5 → icadkit-0.3.7}/docs/changelog.md +156 -0
  19. {icadkit-0.3.5 → icadkit-0.3.7}/docs/csg.md +17 -3
  20. {icadkit-0.3.5 → icadkit-0.3.7}/docs/native.md +3 -1
  21. {icadkit-0.3.5 → icadkit-0.3.7}/docs/preview.md +5 -3
  22. {icadkit-0.3.5 → icadkit-0.3.7}/docs/roadmap.md +98 -3
  23. {icadkit-0.3.5 → icadkit-0.3.7}/docs/saved-bodies.md +36 -8
  24. {icadkit-0.3.5 → icadkit-0.3.7}/docs/support.md +16 -8
  25. {icadkit-0.3.5 → icadkit-0.3.7}/docs/trailer.md +53 -3
  26. {icadkit-0.3.5 → icadkit-0.3.7}/pyproject.toml +1 -1
  27. {icadkit-0.3.5 → icadkit-0.3.7}/scripts/check_license.py +54 -11
  28. {icadkit-0.3.5 → icadkit-0.3.7}/scripts/verify_artifacts.py +11 -15
  29. {icadkit-0.3.5 → icadkit-0.3.7}/scripts/verify_install.py +1 -7
  30. {icadkit-0.3.5 → icadkit-0.3.7}/src/icadkit/__init__.py +4 -0
  31. {icadkit-0.3.5 → icadkit-0.3.7}/src/icadkit/_core.pyi +15 -2
  32. {icadkit-0.3.5 → icadkit-0.3.7}/src/icadkit/_csg_occt.py +70 -5
  33. {icadkit-0.3.5 → icadkit-0.3.7}/src/icadkit/_preview_bridge.py +42 -2
  34. {icadkit-0.3.5 → icadkit-0.3.7}/src/icadkit/_saved_occt.py +116 -28
  35. {icadkit-0.3.5 → icadkit-0.3.7}/src/icadkit/csg.py +90 -19
  36. {icadkit-0.3.5 → icadkit-0.3.7}/src/icadkit/preview.py +3 -9
  37. {icadkit-0.3.5 → icadkit-0.3.7}/src/icadkit/trailer.py +81 -7
  38. {icadkit-0.3.5 → icadkit-0.3.7}/src/icadkit/viewer.py +6 -6
  39. {icadkit-0.3.5 → icadkit-0.3.7}/tests/saved_fixtures.py +156 -0
  40. {icadkit-0.3.5 → icadkit-0.3.7}/tests/test_api.py +2 -1
  41. {icadkit-0.3.5 → icadkit-0.3.7}/tests/test_cli.py +1 -1
  42. {icadkit-0.3.5 → icadkit-0.3.7}/tests/test_csg.py +143 -6
  43. {icadkit-0.3.5 → icadkit-0.3.7}/tests/test_distribution.py +4 -2
  44. {icadkit-0.3.5 → icadkit-0.3.7}/tests/test_geometry.py +19 -8
  45. {icadkit-0.3.5 → icadkit-0.3.7}/tests/test_preview.py +2 -10
  46. {icadkit-0.3.5 → icadkit-0.3.7}/tests/test_saved.py +83 -6
  47. {icadkit-0.3.5 → icadkit-0.3.7}/tests/test_trailer.py +147 -0
  48. {icadkit-0.3.5 → icadkit-0.3.7}/tests/trailer_fixtures.py +16 -8
  49. {icadkit-0.3.5 → icadkit-0.3.7}/uv.lock +8 -8
  50. {icadkit-0.3.5 → icadkit-0.3.7}/COMMERCIAL-LICENSE.md +0 -0
  51. {icadkit-0.3.5 → icadkit-0.3.7}/LICENSE +0 -0
  52. {icadkit-0.3.5 → icadkit-0.3.7}/LICENSES/Apache-2.0.txt +0 -0
  53. {icadkit-0.3.5 → icadkit-0.3.7}/LICENSES/PolyForm-Noncommercial-1.0.0.md +0 -0
  54. {icadkit-0.3.5 → icadkit-0.3.7}/LICENSES/parasolid-core-MIT.txt +0 -0
  55. {icadkit-0.3.5 → icadkit-0.3.7}/corpus/README.md +0 -0
  56. {icadkit-0.3.5 → icadkit-0.3.7}/corpus/generate.py +0 -0
  57. {icadkit-0.3.5 → icadkit-0.3.7}/corpus/public.jsonl +0 -0
  58. {icadkit-0.3.5 → icadkit-0.3.7}/crates/icad-core/Cargo.toml +0 -0
  59. {icadkit-0.3.5 → icadkit-0.3.7}/crates/icad-core/src/compression.rs +0 -0
  60. {icadkit-0.3.5 → icadkit-0.3.7}/crates/icad-core/src/error.rs +0 -0
  61. {icadkit-0.3.5 → icadkit-0.3.7}/crates/icad-core/src/header.rs +0 -0
  62. {icadkit-0.3.5 → icadkit-0.3.7}/crates/icad-core/src/limits.rs +0 -0
  63. {icadkit-0.3.5 → icadkit-0.3.7}/crates/icad-core/src/parasolid.rs +0 -0
  64. {icadkit-0.3.5 → icadkit-0.3.7}/crates/icad-core/src/parts.rs +0 -0
  65. {icadkit-0.3.5 → icadkit-0.3.7}/crates/icad-core/src/provenance.rs +0 -0
  66. {icadkit-0.3.5 → icadkit-0.3.7}/crates/icad-core/src/reader.rs +0 -0
  67. {icadkit-0.3.5 → icadkit-0.3.7}/crates/icad-core/src/record.rs +0 -0
  68. {icadkit-0.3.5 → icadkit-0.3.7}/crates/icad-core/src/resource.rs +0 -0
  69. {icadkit-0.3.5 → icadkit-0.3.7}/crates/icad-core/src/schema.rs +0 -0
  70. {icadkit-0.3.5 → icadkit-0.3.7}/crates/icad-core/src/views.rs +0 -0
  71. {icadkit-0.3.5 → icadkit-0.3.7}/crates/icad-core/tests/header.rs +0 -0
  72. {icadkit-0.3.5 → icadkit-0.3.7}/crates/icad-python/Cargo.toml +0 -0
  73. {icadkit-0.3.5 → icadkit-0.3.7}/crates/icad-python/src/geometry.rs +0 -0
  74. {icadkit-0.3.5 → icadkit-0.3.7}/crates/icad-python/src/lib.rs +0 -0
  75. {icadkit-0.3.5 → icadkit-0.3.7}/crates/icad-python/src/schema.rs +0 -0
  76. {icadkit-0.3.5 → icadkit-0.3.7}/docs/drawing.md +0 -0
  77. {icadkit-0.3.5 → icadkit-0.3.7}/docs/license.md +0 -0
  78. {icadkit-0.3.5 → icadkit-0.3.7}/docs/parameters.md +0 -0
  79. {icadkit-0.3.5 → icadkit-0.3.7}/docs/parts.md +0 -0
  80. {icadkit-0.3.5 → icadkit-0.3.7}/docs/references.md +0 -0
  81. {icadkit-0.3.5 → icadkit-0.3.7}/docs/viewer.md +0 -0
  82. {icadkit-0.3.5 → icadkit-0.3.7}/scripts/check_public_tree.py +0 -0
  83. {icadkit-0.3.5 → icadkit-0.3.7}/scripts/test_publication.py +0 -0
  84. {icadkit-0.3.5 → icadkit-0.3.7}/scripts/verify_corpus.py +0 -0
  85. {icadkit-0.3.5 → icadkit-0.3.7}/scripts/verify_native_corpus.py +0 -0
  86. {icadkit-0.3.5 → icadkit-0.3.7}/src/icadkit/__main__.py +0 -0
  87. {icadkit-0.3.5 → icadkit-0.3.7}/src/icadkit/_viewer/index.html +0 -0
  88. {icadkit-0.3.5 → icadkit-0.3.7}/src/icadkit/_viewer/viewer.css +0 -0
  89. {icadkit-0.3.5 → icadkit-0.3.7}/src/icadkit/_viewer/viewer.js +0 -0
  90. {icadkit-0.3.5 → icadkit-0.3.7}/src/icadkit/_viewer_io.py +0 -0
  91. {icadkit-0.3.5 → icadkit-0.3.7}/src/icadkit/api.py +0 -0
  92. {icadkit-0.3.5 → icadkit-0.3.7}/src/icadkit/cli.py +0 -0
  93. {icadkit-0.3.5 → icadkit-0.3.7}/src/icadkit/document.py +0 -0
  94. {icadkit-0.3.5 → icadkit-0.3.7}/src/icadkit/drawing.py +0 -0
  95. {icadkit-0.3.5 → icadkit-0.3.7}/src/icadkit/errors.py +0 -0
  96. {icadkit-0.3.5 → icadkit-0.3.7}/src/icadkit/geometry.py +0 -0
  97. {icadkit-0.3.5 → icadkit-0.3.7}/src/icadkit/models.py +0 -0
  98. {icadkit-0.3.5 → icadkit-0.3.7}/src/icadkit/native.py +0 -0
  99. {icadkit-0.3.5 → icadkit-0.3.7}/src/icadkit/parameters.py +0 -0
  100. {icadkit-0.3.5 → icadkit-0.3.7}/src/icadkit/parts.py +0 -0
  101. {icadkit-0.3.5 → icadkit-0.3.7}/src/icadkit/py.typed +0 -0
  102. {icadkit-0.3.5 → icadkit-0.3.7}/src/icadkit/references.py +0 -0
  103. {icadkit-0.3.5 → icadkit-0.3.7}/src/icadkit/saved.py +0 -0
  104. {icadkit-0.3.5 → icadkit-0.3.7}/src/icadkit/schema.py +0 -0
  105. {icadkit-0.3.5 → icadkit-0.3.7}/src/icadkit/views.py +0 -0
  106. {icadkit-0.3.5 → icadkit-0.3.7}/tests/conftest.py +0 -0
  107. {icadkit-0.3.5 → icadkit-0.3.7}/tests/drawing_fixtures.py +0 -0
  108. {icadkit-0.3.5 → icadkit-0.3.7}/tests/fixture_builders.py +0 -0
  109. {icadkit-0.3.5 → icadkit-0.3.7}/tests/geometry_fixtures.py +0 -0
  110. {icadkit-0.3.5 → icadkit-0.3.7}/tests/parameter_fixtures.py +0 -0
  111. {icadkit-0.3.5 → icadkit-0.3.7}/tests/part_fixtures.py +0 -0
  112. {icadkit-0.3.5 → icadkit-0.3.7}/tests/preview_fixtures.py +0 -0
  113. {icadkit-0.3.5 → icadkit-0.3.7}/tests/test_corpus.py +0 -0
  114. {icadkit-0.3.5 → icadkit-0.3.7}/tests/test_drawing.py +0 -0
  115. {icadkit-0.3.5 → icadkit-0.3.7}/tests/test_extrusion.py +0 -0
  116. {icadkit-0.3.5 → icadkit-0.3.7}/tests/test_followup_parts.py +0 -0
  117. {icadkit-0.3.5 → icadkit-0.3.7}/tests/test_inspect.py +0 -0
  118. {icadkit-0.3.5 → icadkit-0.3.7}/tests/test_legacy_parts.py +0 -0
  119. {icadkit-0.3.5 → icadkit-0.3.7}/tests/test_mirrors.py +0 -0
  120. {icadkit-0.3.5 → icadkit-0.3.7}/tests/test_native.py +0 -0
  121. {icadkit-0.3.5 → icadkit-0.3.7}/tests/test_native_corpus.py +0 -0
  122. {icadkit-0.3.5 → icadkit-0.3.7}/tests/test_native_round.py +0 -0
  123. {icadkit-0.3.5 → icadkit-0.3.7}/tests/test_parameters.py +0 -0
  124. {icadkit-0.3.5 → icadkit-0.3.7}/tests/test_part_profiles.py +0 -0
  125. {icadkit-0.3.5 → icadkit-0.3.7}/tests/test_part_semantics.py +0 -0
  126. {icadkit-0.3.5 → icadkit-0.3.7}/tests/test_parts.py +0 -0
  127. {icadkit-0.3.5 → icadkit-0.3.7}/tests/test_profile_shapes.py +0 -0
  128. {icadkit-0.3.5 → icadkit-0.3.7}/tests/test_references.py +0 -0
  129. {icadkit-0.3.5 → icadkit-0.3.7}/tests/test_resource_cli.py +0 -0
  130. {icadkit-0.3.5 → icadkit-0.3.7}/tests/test_resources.py +0 -0
  131. {icadkit-0.3.5 → icadkit-0.3.7}/tests/test_v7_parts.py +0 -0
  132. {icadkit-0.3.5 → icadkit-0.3.7}/tests/test_v8l4_boundary.py +0 -0
  133. {icadkit-0.3.5 → icadkit-0.3.7}/tests/test_version_geometry.py +0 -0
  134. {icadkit-0.3.5 → icadkit-0.3.7}/tests/test_viewer.py +0 -0
  135. {icadkit-0.3.5 → icadkit-0.3.7}/tests/viewer_assembly_browser.mjs +0 -0
  136. {icadkit-0.3.5 → icadkit-0.3.7}/tests/viewer_browser.mjs +0 -0
  137. {icadkit-0.3.5 → icadkit-0.3.7}/tests/viewer_mirror_browser.mjs +0 -0
@@ -89,7 +89,7 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
89
89
 
90
90
  [[package]]
91
91
  name = "icad-core"
92
- version = "0.3.5"
92
+ version = "0.3.7"
93
93
  dependencies = [
94
94
  "flate2",
95
95
  "parasolid-core",
@@ -99,7 +99,7 @@ dependencies = [
99
99
 
100
100
  [[package]]
101
101
  name = "icad-python"
102
- version = "0.3.5"
102
+ version = "0.3.7"
103
103
  dependencies = [
104
104
  "icad-core",
105
105
  "parasolid-core",
@@ -142,9 +142,9 @@ checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
142
142
 
143
143
  [[package]]
144
144
  name = "parasolid-core"
145
- version = "0.3.5"
145
+ version = "0.3.7"
146
146
  source = "registry+https://github.com/rust-lang/crates.io-index"
147
- checksum = "ea19ba26c4ea0217f3f81dc5a5479239f92d43fc08bd6754d9f9f5ad74cf2c0a"
147
+ checksum = "7ff3cbb9817406ac809cd989e47454deee4af89a30b57b436561b676f98af37e"
148
148
 
149
149
  [[package]]
150
150
  name = "portable-atomic"
@@ -3,13 +3,13 @@ members = ["crates/icad-core", "crates/icad-python"]
3
3
  resolver = "3"
4
4
 
5
5
  [workspace.package]
6
- version = "0.3.5"
6
+ version = "0.3.7"
7
7
  edition = "2024"
8
8
  rust-version = "1.88"
9
9
  license = "PolyForm-Noncommercial-1.0.0"
10
10
 
11
11
  [workspace.dependencies]
12
- parasolid-core = "=0.3.5"
12
+ parasolid-core = "=0.3.7"
13
13
  pyo3 = { version = "=0.29.2", features = ["abi3-py310"] }
14
14
  flate2 = { version = "1", default-features = false, features = ["rust_backend"] }
15
15
  sha2 = "0.10"
@@ -134,7 +134,7 @@ IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
134
134
  DEALINGS IN THE SOFTWARE.
135
135
 
136
136
 
137
- === parasolid-core 0.3.5 (MIT AND Apache-2.0) ===
137
+ === parasolid-core 0.3.7 (MIT AND Apache-2.0) ===
138
138
  MIT License
139
139
 
140
140
  Copyright (c) 2026 parasolid-kit contributors
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: icadkit
3
- Version: 0.3.5
3
+ Version: 0.3.7
4
4
  Classifier: Development Status :: 2 - Pre-Alpha
5
5
  Classifier: Programming Language :: Python :: 3 :: Only
6
6
  Classifier: Programming Language :: Python :: Implementation :: CPython
7
7
  Classifier: Programming Language :: Rust
8
8
  Classifier: Typing :: Typed
9
- Requires-Dist: parasolid-kit[occt]==0.2.0 ; extra == 'preview'
9
+ Requires-Dist: parasolid-kit[occt]==0.3.7 ; extra == 'preview'
10
10
  Provides-Extra: preview
11
11
  License-File: LICENSE
12
12
  License-File: COMMERCIAL-LICENSE.md
@@ -32,27 +32,27 @@ A Rust-based Python reader for **iCAD SX `.icd` files**. Read saved part
32
32
  structure, coordinate frames, names and selected attributes; inspect native
33
33
  box/cylinder parameters; and extract embedded Parasolid geometry.
34
34
 
35
- Version **0.3.5** adds:
36
-
37
- - [View inventories and saved 2D geometry](docs/drawing.md) through
38
- `read_views()` / `read_drawing()` and the `views` / `drawing` CLI commands.
39
- Old originals and registered parts are read directly. Qualified 2D primitives
40
- use view-local coordinates; text content is separate from unsupported layout.
41
- - Catalog-free raw parsing and source B-Rep mapping of
42
- [twenty-six further exact iCAD schema keys](docs/support.md#schemas) through
43
- `parasolid-core 0.3.5`. SPUN_SURF geometry remains partial; saved-body
44
- conversion has separate limits.
45
- - The [trailing container](docs/trailer.md): per-entity blocks with stored
46
- local bounds and the identity of their faces and edges (`read_trailer()`,
47
- `icadkit trailer`).
48
- - [Saved final bodies](docs/saved-bodies.md) bound through saved association
49
- records in V8 and by source ID in V7L2–V7L5, and converted with elliptical
50
- edges, intersection curves and cone apexes.
51
- - More [native primitives](docs/native.md): polygon extrusions, extrusions with
52
- arc profiles, revolved profiles and signed heights, in V7L6/V7L7 and
53
- V8L1/V8L2/V8L3, including internal mirrors.
54
- - [Saved 3D parameter tables](docs/parameters.md) and explicit
55
- [external-reference resolution](docs/references.md).
35
+ Version **0.3.7** adds:
36
+
37
+ - [Saved final bodies](docs/saved-bodies.md) on rolling-ball blend surfaces
38
+ and on toroidal faces that reach their axis, through `parasolid-core 0.3.7`
39
+ and the `preview` extra pinned to `parasolid-kit[occt]==0.3.7`. The local
40
+ sample rises from 28,896 to 29,386 of 29,703 bound bodies, with the
41
+ previously converted bodies unchanged.
42
+ - One declaration per backend version (`Cargo.toml`, `pyproject.toml`); the
43
+ runtime checks of the backend version are gone.
44
+
45
+ Version 0.3.6 added [saved final bodies](docs/saved-bodies.md) on spun
46
+ surfaces (SPUN_SURF), line/arc profile extrusions as [CSG](docs/csg.md)
47
+ operands and decoded surface and edge items of the
48
+ [trailing container](docs/trailer.md).
49
+
50
+ Version 0.3.5 added [view inventories and saved 2D geometry](docs/drawing.md),
51
+ twenty-six further catalog-free [schema keys](docs/support.md#schemas), the
52
+ [trailing container](docs/trailer.md), saved final bodies bound through V8
53
+ association records and V7 source IDs, more [native primitives](docs/native.md),
54
+ [saved 3D parameter tables](docs/parameters.md) and explicit
55
+ [external-reference resolution](docs/references.md).
56
56
 
57
57
  Version 0.3.0 added the [native file viewer](docs/viewer.md), broader
58
58
  [part access](docs/parts.md), optional [V7L7 boolean evaluation](docs/csg.md)
@@ -73,7 +73,7 @@ The base reader supports standard GIL-enabled CPython 3.10–3.14. Wheel targets
73
73
  are Linux x86_64 (glibc 2.28+), Windows x86_64 and macOS ARM64 (11+):
74
74
 
75
75
  ```sh
76
- python -m pip install icadkit==0.3.5
76
+ python -m pip install icadkit
77
77
  ```
78
78
 
79
79
  The native extension bundles `parasolid-core` and has no mandatory Python
@@ -82,7 +82,7 @@ explicit compatible catalog is needed only for schemas absent from the built-in
82
82
  profiles. Release files are available on the
83
83
  [GitHub releases page](https://github.com/monozukuri-ai/icadkit/releases).
84
84
 
85
- For preview/GLB, install `python -m pip install 'icadkit[preview]==0.3.5'`.
85
+ For preview/GLB, install `python -m pip install 'icadkit[preview]'`.
86
86
  The optional OCCT dependency requires glibc 2.31+ on Linux; see
87
87
  [preview requirements](docs/preview.md#dependencies-and-validation).
88
88
  To build from a source checkout or sdist, install Rust 1.88+ and a C linker,
@@ -111,8 +111,9 @@ Qualified V7L7 part frames use millimetres and are evaluated relative to the
111
111
  saved root frame. Qualified standalone primitive owners also expose geometry and saved
112
112
  entity appearance. The separate [CSG API](docs/csg.md) and
113
113
  `uv run --extra preview icadkit view model.icd --csg` evaluate qualified
114
- box/cylinder unions, differences and intersections. Unknown programs retain
115
- diagnostics without substitute geometry.
114
+ unions, differences and intersections of boxes, cylinders, prisms and profile
115
+ extrusions, including saved single-leaf extrusion bodies. Unknown programs
116
+ retain diagnostics without substitute geometry.
116
117
  The [saved final body mode](docs/saved-bodies.md), `view --saved-brep`, also
117
118
  displays qualified V7L7/V8L3 final bodies and imported solids, including bounded
118
119
  spherical, conical and toroidal surfaces. V8L3 resource sharing preserves each
@@ -4,27 +4,27 @@ A Rust-based Python reader for **iCAD SX `.icd` files**. Read saved part
4
4
  structure, coordinate frames, names and selected attributes; inspect native
5
5
  box/cylinder parameters; and extract embedded Parasolid geometry.
6
6
 
7
- Version **0.3.5** adds:
8
-
9
- - [View inventories and saved 2D geometry](docs/drawing.md) through
10
- `read_views()` / `read_drawing()` and the `views` / `drawing` CLI commands.
11
- Old originals and registered parts are read directly. Qualified 2D primitives
12
- use view-local coordinates; text content is separate from unsupported layout.
13
- - Catalog-free raw parsing and source B-Rep mapping of
14
- [twenty-six further exact iCAD schema keys](docs/support.md#schemas) through
15
- `parasolid-core 0.3.5`. SPUN_SURF geometry remains partial; saved-body
16
- conversion has separate limits.
17
- - The [trailing container](docs/trailer.md): per-entity blocks with stored
18
- local bounds and the identity of their faces and edges (`read_trailer()`,
19
- `icadkit trailer`).
20
- - [Saved final bodies](docs/saved-bodies.md) bound through saved association
21
- records in V8 and by source ID in V7L2–V7L5, and converted with elliptical
22
- edges, intersection curves and cone apexes.
23
- - More [native primitives](docs/native.md): polygon extrusions, extrusions with
24
- arc profiles, revolved profiles and signed heights, in V7L6/V7L7 and
25
- V8L1/V8L2/V8L3, including internal mirrors.
26
- - [Saved 3D parameter tables](docs/parameters.md) and explicit
27
- [external-reference resolution](docs/references.md).
7
+ Version **0.3.7** adds:
8
+
9
+ - [Saved final bodies](docs/saved-bodies.md) on rolling-ball blend surfaces
10
+ and on toroidal faces that reach their axis, through `parasolid-core 0.3.7`
11
+ and the `preview` extra pinned to `parasolid-kit[occt]==0.3.7`. The local
12
+ sample rises from 28,896 to 29,386 of 29,703 bound bodies, with the
13
+ previously converted bodies unchanged.
14
+ - One declaration per backend version (`Cargo.toml`, `pyproject.toml`); the
15
+ runtime checks of the backend version are gone.
16
+
17
+ Version 0.3.6 added [saved final bodies](docs/saved-bodies.md) on spun
18
+ surfaces (SPUN_SURF), line/arc profile extrusions as [CSG](docs/csg.md)
19
+ operands and decoded surface and edge items of the
20
+ [trailing container](docs/trailer.md).
21
+
22
+ Version 0.3.5 added [view inventories and saved 2D geometry](docs/drawing.md),
23
+ twenty-six further catalog-free [schema keys](docs/support.md#schemas), the
24
+ [trailing container](docs/trailer.md), saved final bodies bound through V8
25
+ association records and V7 source IDs, more [native primitives](docs/native.md),
26
+ [saved 3D parameter tables](docs/parameters.md) and explicit
27
+ [external-reference resolution](docs/references.md).
28
28
 
29
29
  Version 0.3.0 added the [native file viewer](docs/viewer.md), broader
30
30
  [part access](docs/parts.md), optional [V7L7 boolean evaluation](docs/csg.md)
@@ -45,7 +45,7 @@ The base reader supports standard GIL-enabled CPython 3.10–3.14. Wheel targets
45
45
  are Linux x86_64 (glibc 2.28+), Windows x86_64 and macOS ARM64 (11+):
46
46
 
47
47
  ```sh
48
- python -m pip install icadkit==0.3.5
48
+ python -m pip install icadkit
49
49
  ```
50
50
 
51
51
  The native extension bundles `parasolid-core` and has no mandatory Python
@@ -54,7 +54,7 @@ explicit compatible catalog is needed only for schemas absent from the built-in
54
54
  profiles. Release files are available on the
55
55
  [GitHub releases page](https://github.com/monozukuri-ai/icadkit/releases).
56
56
 
57
- For preview/GLB, install `python -m pip install 'icadkit[preview]==0.3.5'`.
57
+ For preview/GLB, install `python -m pip install 'icadkit[preview]'`.
58
58
  The optional OCCT dependency requires glibc 2.31+ on Linux; see
59
59
  [preview requirements](docs/preview.md#dependencies-and-validation).
60
60
  To build from a source checkout or sdist, install Rust 1.88+ and a C linker,
@@ -83,8 +83,9 @@ Qualified V7L7 part frames use millimetres and are evaluated relative to the
83
83
  saved root frame. Qualified standalone primitive owners also expose geometry and saved
84
84
  entity appearance. The separate [CSG API](docs/csg.md) and
85
85
  `uv run --extra preview icadkit view model.icd --csg` evaluate qualified
86
- box/cylinder unions, differences and intersections. Unknown programs retain
87
- diagnostics without substitute geometry.
86
+ unions, differences and intersections of boxes, cylinders, prisms and profile
87
+ extrusions, including saved single-leaf extrusion bodies. Unknown programs
88
+ retain diagnostics without substitute geometry.
88
89
  The [saved final body mode](docs/saved-bodies.md), `view --saved-brep`, also
89
90
  displays qualified V7L7/V8L3 final bodies and imported solids, including bounded
90
91
  spherical, conical and toroidal surfaces. V8L3 resource sharing preserves each
@@ -4,8 +4,9 @@ icadkit project material is offered under PolyForm Noncommercial 1.0.0, with sep
4
4
  commercial licensing available from UnRobotics Inc.
5
5
  See `LICENSE` and `COMMERCIAL-LICENSE.md`.
6
6
 
7
- Binary distributions also contain `parasolid-core 0.3.5` (MIT AND Apache-2.0)
8
- and PyO3 (MIT OR Apache-2.0, MIT selected). The source metadata declares
7
+ Binary distributions also contain `parasolid-core` (MIT AND Apache-2.0; the
8
+ exact version is listed in `LICENSES/rust-dependencies.txt`) and PyO3 (MIT OR
9
+ Apache-2.0, MIT selected). The source metadata declares
9
10
  `PolyForm-Noncommercial-1.0.0`; the combined Python distribution declares
10
11
  `PolyForm-Noncommercial-1.0.0 AND MIT AND Apache-2.0`. These expressions describe
11
12
  different portions of the package, not a choice to use all icadkit material
@@ -25,9 +26,10 @@ under MIT or Apache-2.0. Third-party components are not relicensed.
25
26
  for project-authored material. Their V30 scalar layouts derive from the
26
27
  MIT/Apache-2.0 `parasolid-core` profile; see `tests/geometry_fixtures.py`
27
28
  for attribution.
28
- - The optional `preview` extra installs `parasolid-kit[occt] 0.2.0` and its
29
- separately distributed OCCT runtime dependencies. These are not bundled in
30
- the icadkit wheel. Their own distributions retain their license terms.
29
+ - The optional `preview` extra installs the `parasolid-kit[occt]` release
30
+ pinned in `pyproject.toml` and its separately distributed OCCT runtime
31
+ dependencies. These are not bundled in the icadkit wheel. Their own
32
+ distributions retain their license terms.
31
33
  Generated viewer directories copy that package's browser assets and retain
32
34
  the included MIT/Zlib notices and the n8ao ISC metadata / CC0-1.0 license-text
33
35
  discrepancy. Keep those notices when redistributing generated viewers.
@@ -1,4 +1,4 @@
1
- Generated by scripts/check_license.py --write-crate-notices.
1
+ Generated by scripts/check_license.py --write.
2
2
  Canonical source notices follow; paths refer to the source root.
3
3
 
4
4
  ===== LICENSE =====
@@ -108,8 +108,9 @@ icadkit project material is offered under PolyForm Noncommercial 1.0.0, with sep
108
108
  commercial licensing available from UnRobotics Inc.
109
109
  See `LICENSE` and `COMMERCIAL-LICENSE.md`.
110
110
 
111
- Binary distributions also contain `parasolid-core 0.3.5` (MIT AND Apache-2.0)
112
- and PyO3 (MIT OR Apache-2.0, MIT selected). The source metadata declares
111
+ Binary distributions also contain `parasolid-core` (MIT AND Apache-2.0; the
112
+ exact version is listed in `LICENSES/rust-dependencies.txt`) and PyO3 (MIT OR
113
+ Apache-2.0, MIT selected). The source metadata declares
113
114
  `PolyForm-Noncommercial-1.0.0`; the combined Python distribution declares
114
115
  `PolyForm-Noncommercial-1.0.0 AND MIT AND Apache-2.0`. These expressions describe
115
116
  different portions of the package, not a choice to use all icadkit material
@@ -129,9 +130,10 @@ under MIT or Apache-2.0. Third-party components are not relicensed.
129
130
  for project-authored material. Their V30 scalar layouts derive from the
130
131
  MIT/Apache-2.0 `parasolid-core` profile; see `tests/geometry_fixtures.py`
131
132
  for attribution.
132
- - The optional `preview` extra installs `parasolid-kit[occt] 0.2.0` and its
133
- separately distributed OCCT runtime dependencies. These are not bundled in
134
- the icadkit wheel. Their own distributions retain their license terms.
133
+ - The optional `preview` extra installs the `parasolid-kit[occt]` release
134
+ pinned in `pyproject.toml` and its separately distributed OCCT runtime
135
+ dependencies. These are not bundled in the icadkit wheel. Their own
136
+ distributions retain their license terms.
135
137
  Generated viewer directories copy that package's browser assets and retain
136
138
  the included MIT/Zlib notices and the n8ao ISC metadata / CC0-1.0 license-text
137
139
  discrepancy. Keep those notices when redistributing generated viewers.
@@ -582,7 +584,7 @@ IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
582
584
  DEALINGS IN THE SOFTWARE.
583
585
 
584
586
 
585
- === parasolid-core 0.3.5 (MIT AND Apache-2.0) ===
587
+ === parasolid-core 0.3.7 (MIT AND Apache-2.0) ===
586
588
  MIT License
587
589
 
588
590
  Copyright (c) 2026 parasolid-kit contributors
@@ -0,0 +1,49 @@
1
+ //! Records the resolved `parasolid-core` version from the workspace lock file.
2
+ //!
3
+ //! The crate reports which backend release it was compiled with
4
+ //! (`PARASOLID_CORE_VERSION`). Reading it from `Cargo.lock` keeps the manifest
5
+ //! pin the only place in the source that names that version.
6
+
7
+ use std::env;
8
+ use std::fs;
9
+ use std::path::{Path, PathBuf};
10
+
11
+ fn main() -> Result<(), String> {
12
+ let manifest_dir = env::var_os("CARGO_MANIFEST_DIR").ok_or("CARGO_MANIFEST_DIR is not set")?;
13
+ let lock = PathBuf::from(manifest_dir)
14
+ .ancestors()
15
+ .map(|dir| dir.join("Cargo.lock"))
16
+ .find(|path| path.is_file())
17
+ .ok_or("no Cargo.lock above the crate directory")?;
18
+ let version = resolved_version(&lock, "parasolid-core")?;
19
+ println!("cargo:rerun-if-changed={}", lock.display());
20
+ println!("cargo:rustc-env=ICAD_PARASOLID_CORE_VERSION={version}");
21
+ Ok(())
22
+ }
23
+
24
+ /// The version of `package` in the lock file, which must resolve it exactly once.
25
+ fn resolved_version(lock: &Path, package: &str) -> Result<String, String> {
26
+ let text = fs::read_to_string(lock)
27
+ .map_err(|error| format!("cannot read {}: {error}", lock.display()))?;
28
+ let mut versions = Vec::new();
29
+ let mut name = None;
30
+ for line in text.lines().map(str::trim) {
31
+ if line == "[[package]]" {
32
+ name = None;
33
+ } else if let Some(value) = line.strip_prefix("name = ") {
34
+ name = Some(value.trim_matches('"'));
35
+ } else if let Some(value) = line.strip_prefix("version = ")
36
+ && name == Some(package)
37
+ {
38
+ versions.push(value.trim_matches('"').to_owned());
39
+ }
40
+ }
41
+ match versions.as_slice() {
42
+ [version] => Ok(version.clone()),
43
+ [] => Err(format!("{package} is not resolved in {}", lock.display())),
44
+ _ => Err(format!(
45
+ "{package} resolves to several versions in {}",
46
+ lock.display()
47
+ )),
48
+ }
49
+ }
@@ -592,4 +592,17 @@ impl Document {
592
592
  self.limits.resource(range.end - range.start, range.start)?;
593
593
  Ok(&self.data[range.start as usize..range.end as usize])
594
594
  }
595
+
596
+ /// Decode one saved boolean component record in place, without an owner
597
+ /// context. The caller has already framed the record and checks its saved
598
+ /// program, result backlink and root frame.
599
+ pub fn read_component(
600
+ &self,
601
+ range: ByteRange,
602
+ ) -> Result<crate::native::NativeEntityRecord, InspectError> {
603
+ Ok(crate::native::read_component_entity(
604
+ self.source_bytes(range)?,
605
+ range,
606
+ ))
607
+ }
595
608
  }
@@ -38,7 +38,7 @@ pub use resource::{Encoding, ResourceAssociation, ResourceRef};
38
38
  pub use schema::SchemaCatalog;
39
39
  pub use trailer::{
40
40
  TrailerBlock, TrailerBlockData, TrailerEdge, TrailerFace, TrailerIndex, TrailerLimits,
41
- TrailerTable, TrailerView,
41
+ TrailerParameterLine, TrailerSurface, TrailerTable, TrailerView,
42
42
  };
43
43
  pub use views::{ViewEntry, ViewIndex, ViewLimits, ViewRecord};
44
44
 
@@ -47,8 +47,8 @@ use parasolid_core::{BuiltinProfileRegistry, ParseError};
47
47
  /// Version of this Rust crate, in Cargo SemVer notation.
48
48
  pub const VERSION: &str = env!("CARGO_PKG_VERSION");
49
49
 
50
- /// Exact registry dependency; checked against the manifest and lock in CI.
51
- pub const PARASOLID_CORE_VERSION: &str = "0.3.5";
50
+ /// Resolved registry version of the backend, read from `Cargo.lock` at build time.
51
+ pub const PARASOLID_CORE_VERSION: &str = env!("ICAD_PARASOLID_CORE_VERSION");
52
52
 
53
53
  /// Metadata of the compiled Parasolid backend, not ICD format coverage.
54
54
  #[derive(Debug, Clone, PartialEq, Eq)]
@@ -139,6 +139,18 @@ pub(crate) fn read_parametric_entity(bytes: &[u8], byte_range: ByteRange) -> Nat
139
139
  }
140
140
 
141
141
  pub(crate) fn read_entity(bytes: &[u8], byte_range: ByteRange) -> NativeEntityRecord {
142
+ decode_entity(bytes, byte_range, false)
143
+ }
144
+
145
+ /// A component record of a saved boolean body: the standalone layout with the
146
+ /// component bit set, an optional explicit-result bit, and a result backlink
147
+ /// where a standalone record stores zero. The caller checks that backlink and
148
+ /// the saved program; nothing here establishes a finished solid.
149
+ pub(crate) fn read_component_entity(bytes: &[u8], byte_range: ByteRange) -> NativeEntityRecord {
150
+ decode_entity(bytes, byte_range, true)
151
+ }
152
+
153
+ fn decode_entity(bytes: &[u8], byte_range: ByteRange, component: bool) -> NativeEntityRecord {
142
154
  let mut result = undecoded_entity(bytes, byte_range);
143
155
  // Layer, saved visibility and palette index are qualified only for these
144
156
  // exact native layouts. A Parasolid body has a different attribute layout.
@@ -168,11 +180,18 @@ pub(crate) fn read_entity(bytes: &[u8], byte_range: ByteRange) -> NativeEntityRe
168
180
  bytes.len() == length
169
181
  && word(bytes, 4) > 0
170
182
  && word(bytes, 8) == 0
171
- && matches!(word(bytes, 12) & 0x00ffefff, 0x000100c1 | 0x00010081)
183
+ && if component {
184
+ // Operands carry the component bit 0x20 and, under an explicit
185
+ // result marker, bit 0x100. The mirror bit stays separate.
186
+ word(bytes, 12) & 0x20 != 0
187
+ && matches!(word(bytes, 12) & 0x00ffeedf, 0x000100c1 | 0x00010081)
188
+ } else {
189
+ matches!(word(bytes, 12) & 0x00ffefff, 0x000100c1 | 0x00010081)
190
+ }
172
191
  && word(bytes, 16) & 0xf0000000 == 0x80000000
173
192
  && word(bytes, 20) == 0
174
193
  && word(bytes, 24) == marker
175
- && word(bytes, 32) == 0
194
+ && (component || word(bytes, 32) == 0)
176
195
  // The upper word is retained as opaque producer metadata.
177
196
  && word(bytes, 40) & 0xffff == if kind == "polygon_extrusion" { 0x1b0 } else { 0x180 }
178
197
  && word(bytes, 44) == 0
@@ -623,3 +642,75 @@ fn simple_polygon(values: &[f64]) -> bool {
623
642
  }
624
643
  true
625
644
  }
645
+
646
+ #[cfg(test)]
647
+ mod tests {
648
+ use super::*;
649
+
650
+ /// A closed rectangle profile of five straight elements with a flag trailer.
651
+ fn record(flags: u32, backlink: u32) -> Vec<u8> {
652
+ let mut bytes = vec![0_u8; 216];
653
+ for (at, value) in [
654
+ (0, 216_u32),
655
+ (4, 1),
656
+ (12, 76 << 24 | flags),
657
+ (16, 0x8000_0003),
658
+ (24, 0x5944_00c0),
659
+ (32, backlink),
660
+ (40, 0x180),
661
+ ] {
662
+ bytes[at..at + 4].copy_from_slice(&value.to_le_bytes());
663
+ }
664
+ bytes[29] = 0x11;
665
+ let values: [f64; 20] = [
666
+ 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 13.0, 0.0, 0.0, 10.0, 0.0, 10.0, 5.0, 0.0,
667
+ 5.0, 0.0, 0.0,
668
+ ];
669
+ for (i, value) in values.iter().enumerate() {
670
+ bytes[48 + 8 * i..56 + 8 * i].copy_from_slice(&value.to_le_bytes());
671
+ }
672
+ bytes
673
+ }
674
+
675
+ const RANGE: ByteRange = ByteRange {
676
+ start: 1000,
677
+ end: 1216,
678
+ };
679
+
680
+ fn decoded(entity: &NativeEntityRecord) -> Option<(&'static str, usize)> {
681
+ entity
682
+ .primitive
683
+ .as_ref()
684
+ .map(|p| (p.kind, p.parameters.len()))
685
+ }
686
+
687
+ #[test]
688
+ fn component_flags_select_the_reader() {
689
+ let implicit = record(0x100e1, 0);
690
+ assert!(read_entity(&implicit, RANGE).primitive.is_none());
691
+ assert_eq!(
692
+ read_entity(&implicit, RANGE).diagnostics[0].code,
693
+ "native.layout"
694
+ );
695
+ let component = read_component_entity(&implicit, RANGE);
696
+ assert_eq!(decoded(&component), Some(("profile_extrusion", 29)));
697
+ assert_eq!(component.source_id, Some(0x8000_0003));
698
+ assert_eq!(component.is_mirror, Some(false));
699
+ // An explicit component keeps its result backlink; a standalone record
700
+ // with the same word, or without the component bit, is not an operand.
701
+ let explicit = record(0x101e1, 0x8000_0009);
702
+ assert_eq!(
703
+ decoded(&read_component_entity(&explicit, RANGE)),
704
+ Some(("profile_extrusion", 29))
705
+ );
706
+ assert!(read_entity(&explicit, RANGE).primitive.is_none());
707
+ assert!(read_entity(&record(0x100c1, 1), RANGE).primitive.is_none());
708
+ let standalone = read_component_entity(&record(0x100c1, 0), RANGE);
709
+ assert!(standalone.primitive.is_none());
710
+ assert_eq!(standalone.diagnostics[0].code, "native.layout");
711
+ assert_eq!(
712
+ decoded(&read_entity(&record(0x100c1, 0), RANGE)),
713
+ Some(("profile_extrusion", 29))
714
+ );
715
+ }
716
+ }