icadkit 0.3.0__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 (148) hide show
  1. {icadkit-0.3.0 → icadkit-0.3.7}/Cargo.lock +4 -4
  2. {icadkit-0.3.0 → icadkit-0.3.7}/Cargo.toml +2 -2
  3. {icadkit-0.3.0 → icadkit-0.3.7}/LICENSES/rust-dependencies.txt +1 -1
  4. {icadkit-0.3.0 → icadkit-0.3.7}/PKG-INFO +40 -20
  5. {icadkit-0.3.0 → icadkit-0.3.7}/README.md +39 -19
  6. {icadkit-0.3.0 → icadkit-0.3.7}/THIRD_PARTY_NOTICES.md +7 -5
  7. icadkit-0.3.7/corpus/README.md +57 -0
  8. {icadkit-0.3.0 → icadkit-0.3.7}/crates/icad-core/LICENSE +9 -7
  9. icadkit-0.3.7/crates/icad-core/build.rs +49 -0
  10. {icadkit-0.3.0 → icadkit-0.3.7}/crates/icad-core/src/document.rs +45 -1
  11. {icadkit-0.3.0 → icadkit-0.3.7}/crates/icad-core/src/lib.rs +16 -5
  12. icadkit-0.3.7/crates/icad-core/src/native.rs +716 -0
  13. {icadkit-0.3.0 → icadkit-0.3.7}/crates/icad-core/src/parasolid.rs +2 -3
  14. {icadkit-0.3.0 → icadkit-0.3.7}/crates/icad-core/src/parts.rs +507 -24
  15. {icadkit-0.3.0 → icadkit-0.3.7}/crates/icad-core/src/reader.rs +14 -0
  16. {icadkit-0.3.0 → icadkit-0.3.7}/crates/icad-core/src/resource.rs +10 -0
  17. icadkit-0.3.7/crates/icad-core/src/trailer.rs +997 -0
  18. icadkit-0.3.7/crates/icad-core/src/views.rs +410 -0
  19. {icadkit-0.3.0 → icadkit-0.3.7}/crates/icad-core/tests/resources.rs +114 -1
  20. {icadkit-0.3.0 → icadkit-0.3.7}/crates/icad-python/LICENSE +9 -7
  21. {icadkit-0.3.0 → icadkit-0.3.7}/crates/icad-python/src/brep.rs +19 -0
  22. icadkit-0.3.7/crates/icad-python/src/document.rs +576 -0
  23. {icadkit-0.3.0 → icadkit-0.3.7}/docs/api.md +38 -1
  24. icadkit-0.3.7/docs/changelog.md +389 -0
  25. {icadkit-0.3.0 → icadkit-0.3.7}/docs/csg.md +24 -3
  26. icadkit-0.3.7/docs/drawing.md +131 -0
  27. {icadkit-0.3.0 → icadkit-0.3.7}/docs/native.md +94 -8
  28. icadkit-0.3.7/docs/parameters.md +74 -0
  29. {icadkit-0.3.0 → icadkit-0.3.7}/docs/parts.md +106 -34
  30. {icadkit-0.3.0 → icadkit-0.3.7}/docs/preview.md +6 -4
  31. icadkit-0.3.7/docs/references.md +173 -0
  32. icadkit-0.3.7/docs/roadmap.md +420 -0
  33. icadkit-0.3.7/docs/saved-bodies.md +241 -0
  34. icadkit-0.3.7/docs/support.md +216 -0
  35. icadkit-0.3.7/docs/trailer.md +205 -0
  36. {icadkit-0.3.0 → icadkit-0.3.7}/docs/viewer.md +34 -7
  37. {icadkit-0.3.0 → icadkit-0.3.7}/pyproject.toml +2 -1
  38. {icadkit-0.3.0 → icadkit-0.3.7}/scripts/check_license.py +54 -11
  39. {icadkit-0.3.0 → icadkit-0.3.7}/scripts/verify_artifacts.py +20 -15
  40. {icadkit-0.3.0 → icadkit-0.3.7}/scripts/verify_install.py +1 -7
  41. icadkit-0.3.7/scripts/verify_native_corpus.py +424 -0
  42. {icadkit-0.3.0 → icadkit-0.3.7}/src/icadkit/__init__.py +83 -1
  43. {icadkit-0.3.0 → icadkit-0.3.7}/src/icadkit/_core.pyi +117 -1
  44. {icadkit-0.3.0 → icadkit-0.3.7}/src/icadkit/_csg_occt.py +90 -5
  45. {icadkit-0.3.0 → icadkit-0.3.7}/src/icadkit/_preview_bridge.py +50 -2
  46. icadkit-0.3.7/src/icadkit/_saved_occt.py +353 -0
  47. {icadkit-0.3.0 → icadkit-0.3.7}/src/icadkit/_viewer/viewer.js +10 -3
  48. {icadkit-0.3.0 → icadkit-0.3.7}/src/icadkit/cli.py +369 -25
  49. {icadkit-0.3.0 → icadkit-0.3.7}/src/icadkit/csg.py +166 -13
  50. {icadkit-0.3.0 → icadkit-0.3.7}/src/icadkit/document.py +82 -1
  51. icadkit-0.3.7/src/icadkit/drawing.py +304 -0
  52. {icadkit-0.3.0 → icadkit-0.3.7}/src/icadkit/models.py +15 -0
  53. {icadkit-0.3.0 → icadkit-0.3.7}/src/icadkit/native.py +79 -5
  54. icadkit-0.3.7/src/icadkit/parameters.py +446 -0
  55. {icadkit-0.3.0 → icadkit-0.3.7}/src/icadkit/parts.py +158 -26
  56. {icadkit-0.3.0 → icadkit-0.3.7}/src/icadkit/preview.py +3 -9
  57. icadkit-0.3.7/src/icadkit/references.py +713 -0
  58. {icadkit-0.3.0 → icadkit-0.3.7}/src/icadkit/saved.py +121 -16
  59. icadkit-0.3.7/src/icadkit/trailer.py +327 -0
  60. {icadkit-0.3.0 → icadkit-0.3.7}/src/icadkit/viewer.py +555 -55
  61. icadkit-0.3.7/src/icadkit/views.py +114 -0
  62. icadkit-0.3.7/tests/drawing_fixtures.py +94 -0
  63. {icadkit-0.3.0 → icadkit-0.3.7}/tests/fixture_builders.py +13 -0
  64. {icadkit-0.3.0 → icadkit-0.3.7}/tests/geometry_fixtures.py +47 -5
  65. icadkit-0.3.7/tests/parameter_fixtures.py +82 -0
  66. {icadkit-0.3.0 → icadkit-0.3.7}/tests/part_fixtures.py +10 -0
  67. icadkit-0.3.7/tests/saved_fixtures.py +512 -0
  68. icadkit-0.3.7/tests/test_api.py +50 -0
  69. {icadkit-0.3.0 → icadkit-0.3.7}/tests/test_cli.py +1 -1
  70. {icadkit-0.3.0 → icadkit-0.3.7}/tests/test_csg.py +280 -6
  71. {icadkit-0.3.0 → icadkit-0.3.7}/tests/test_distribution.py +4 -2
  72. icadkit-0.3.7/tests/test_drawing.py +391 -0
  73. icadkit-0.3.7/tests/test_extrusion.py +162 -0
  74. {icadkit-0.3.0 → icadkit-0.3.7}/tests/test_followup_parts.py +108 -8
  75. {icadkit-0.3.0 → icadkit-0.3.7}/tests/test_geometry.py +169 -7
  76. icadkit-0.3.7/tests/test_legacy_parts.py +139 -0
  77. icadkit-0.3.7/tests/test_mirrors.py +192 -0
  78. {icadkit-0.3.0 → icadkit-0.3.7}/tests/test_native.py +12 -6
  79. icadkit-0.3.7/tests/test_native_corpus.py +257 -0
  80. icadkit-0.3.7/tests/test_parameters.py +222 -0
  81. icadkit-0.3.7/tests/test_part_profiles.py +131 -0
  82. {icadkit-0.3.0 → icadkit-0.3.7}/tests/test_part_semantics.py +16 -11
  83. {icadkit-0.3.0 → icadkit-0.3.7}/tests/test_preview.py +2 -10
  84. icadkit-0.3.7/tests/test_profile_shapes.py +296 -0
  85. icadkit-0.3.7/tests/test_references.py +407 -0
  86. icadkit-0.3.7/tests/test_saved.py +786 -0
  87. icadkit-0.3.7/tests/test_trailer.py +489 -0
  88. {icadkit-0.3.0 → icadkit-0.3.7}/tests/test_v7_parts.py +5 -5
  89. icadkit-0.3.7/tests/test_v8l4_boundary.py +139 -0
  90. icadkit-0.3.7/tests/test_version_geometry.py +180 -0
  91. icadkit-0.3.7/tests/trailer_fixtures.py +98 -0
  92. icadkit-0.3.7/tests/viewer_assembly_browser.mjs +102 -0
  93. {icadkit-0.3.0 → icadkit-0.3.7}/tests/viewer_browser.mjs +13 -6
  94. icadkit-0.3.7/tests/viewer_mirror_browser.mjs +83 -0
  95. {icadkit-0.3.0 → icadkit-0.3.7}/uv.lock +8 -8
  96. icadkit-0.3.0/corpus/README.md +0 -26
  97. icadkit-0.3.0/crates/icad-core/src/native.rs +0 -219
  98. icadkit-0.3.0/crates/icad-python/src/document.rs +0 -301
  99. icadkit-0.3.0/docs/changelog.md +0 -109
  100. icadkit-0.3.0/docs/roadmap.md +0 -216
  101. icadkit-0.3.0/docs/saved-bodies.md +0 -117
  102. icadkit-0.3.0/docs/support.md +0 -100
  103. icadkit-0.3.0/src/icadkit/_saved_occt.py +0 -183
  104. icadkit-0.3.0/tests/saved_fixtures.py +0 -117
  105. icadkit-0.3.0/tests/test_api.py +0 -19
  106. icadkit-0.3.0/tests/test_saved.py +0 -409
  107. {icadkit-0.3.0 → icadkit-0.3.7}/COMMERCIAL-LICENSE.md +0 -0
  108. {icadkit-0.3.0 → icadkit-0.3.7}/LICENSE +0 -0
  109. {icadkit-0.3.0 → icadkit-0.3.7}/LICENSES/Apache-2.0.txt +0 -0
  110. {icadkit-0.3.0 → icadkit-0.3.7}/LICENSES/PolyForm-Noncommercial-1.0.0.md +0 -0
  111. {icadkit-0.3.0 → icadkit-0.3.7}/LICENSES/parasolid-core-MIT.txt +0 -0
  112. {icadkit-0.3.0 → icadkit-0.3.7}/corpus/generate.py +0 -0
  113. {icadkit-0.3.0 → icadkit-0.3.7}/corpus/public.jsonl +0 -0
  114. {icadkit-0.3.0 → icadkit-0.3.7}/crates/icad-core/Cargo.toml +0 -0
  115. {icadkit-0.3.0 → icadkit-0.3.7}/crates/icad-core/src/compression.rs +0 -0
  116. {icadkit-0.3.0 → icadkit-0.3.7}/crates/icad-core/src/error.rs +0 -0
  117. {icadkit-0.3.0 → icadkit-0.3.7}/crates/icad-core/src/header.rs +0 -0
  118. {icadkit-0.3.0 → icadkit-0.3.7}/crates/icad-core/src/limits.rs +0 -0
  119. {icadkit-0.3.0 → icadkit-0.3.7}/crates/icad-core/src/provenance.rs +0 -0
  120. {icadkit-0.3.0 → icadkit-0.3.7}/crates/icad-core/src/record.rs +0 -0
  121. {icadkit-0.3.0 → icadkit-0.3.7}/crates/icad-core/src/schema.rs +0 -0
  122. {icadkit-0.3.0 → icadkit-0.3.7}/crates/icad-core/tests/header.rs +0 -0
  123. {icadkit-0.3.0 → icadkit-0.3.7}/crates/icad-python/Cargo.toml +0 -0
  124. {icadkit-0.3.0 → icadkit-0.3.7}/crates/icad-python/src/geometry.rs +0 -0
  125. {icadkit-0.3.0 → icadkit-0.3.7}/crates/icad-python/src/lib.rs +0 -0
  126. {icadkit-0.3.0 → icadkit-0.3.7}/crates/icad-python/src/schema.rs +0 -0
  127. {icadkit-0.3.0 → icadkit-0.3.7}/docs/license.md +0 -0
  128. {icadkit-0.3.0 → icadkit-0.3.7}/scripts/check_public_tree.py +0 -0
  129. {icadkit-0.3.0 → icadkit-0.3.7}/scripts/test_publication.py +0 -0
  130. {icadkit-0.3.0 → icadkit-0.3.7}/scripts/verify_corpus.py +0 -0
  131. {icadkit-0.3.0 → icadkit-0.3.7}/src/icadkit/__main__.py +0 -0
  132. {icadkit-0.3.0 → icadkit-0.3.7}/src/icadkit/_viewer/index.html +0 -0
  133. {icadkit-0.3.0 → icadkit-0.3.7}/src/icadkit/_viewer/viewer.css +0 -0
  134. {icadkit-0.3.0 → icadkit-0.3.7}/src/icadkit/_viewer_io.py +0 -0
  135. {icadkit-0.3.0 → icadkit-0.3.7}/src/icadkit/api.py +0 -0
  136. {icadkit-0.3.0 → icadkit-0.3.7}/src/icadkit/errors.py +0 -0
  137. {icadkit-0.3.0 → icadkit-0.3.7}/src/icadkit/geometry.py +0 -0
  138. {icadkit-0.3.0 → icadkit-0.3.7}/src/icadkit/py.typed +0 -0
  139. {icadkit-0.3.0 → icadkit-0.3.7}/src/icadkit/schema.py +0 -0
  140. {icadkit-0.3.0 → icadkit-0.3.7}/tests/conftest.py +0 -0
  141. {icadkit-0.3.0 → icadkit-0.3.7}/tests/preview_fixtures.py +0 -0
  142. {icadkit-0.3.0 → icadkit-0.3.7}/tests/test_corpus.py +0 -0
  143. {icadkit-0.3.0 → icadkit-0.3.7}/tests/test_inspect.py +0 -0
  144. {icadkit-0.3.0 → icadkit-0.3.7}/tests/test_native_round.py +0 -0
  145. {icadkit-0.3.0 → icadkit-0.3.7}/tests/test_parts.py +0 -0
  146. {icadkit-0.3.0 → icadkit-0.3.7}/tests/test_resource_cli.py +0 -0
  147. {icadkit-0.3.0 → icadkit-0.3.7}/tests/test_resources.py +0 -0
  148. {icadkit-0.3.0 → icadkit-0.3.7}/tests/test_viewer.py +0 -0
@@ -89,7 +89,7 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
89
89
 
90
90
  [[package]]
91
91
  name = "icad-core"
92
- version = "0.3.0"
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.0"
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.1"
145
+ version = "0.3.7"
146
146
  source = "registry+https://github.com/rust-lang/crates.io-index"
147
- checksum = "fa625646afc2be83fa25bdbfa453eb7aac9976d17d968f71d9f7e4a448ddcac8"
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.0"
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.1"
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.1 (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.0
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,23 +32,36 @@ 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.0** adds:
35
+ Version **0.3.7** adds:
36
36
 
37
- - A [native file viewer](docs/viewer.md) with a part tree, stored properties,
38
- selection and visibility controls. Qualified boxes, cylinders, full spheres,
39
- cones/frusta and full ring tori use their saved frames.
40
- - Broader [part access](docs/parts.md): V7L7 traversal, bounded V8L1/V8L2
41
- inventories and binary attributes retained with ownership and raw bytes.
42
- - Optional [V7L7 boolean evaluation](docs/csg.md) and
43
- [saved final body display](docs/saved-bodies.md) for V7L7/V8L3, including
44
- imported solids, shared resources and bounded analytic surfaces.
45
- - Updated exact V34 Parasolid support through `parasolid-core 0.3.1`, including
46
- qualified toroidal resources without an external catalog.
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
+
57
+ Version 0.3.0 added the [native file viewer](docs/viewer.md), broader
58
+ [part access](docs/parts.md), optional [V7L7 boolean evaluation](docs/csg.md)
59
+ and [saved final body display](docs/saved-bodies.md).
47
60
 
48
61
  icadkit is experimental. Unsupported geometry remains in the part inventory;
49
62
  unknown values and source ranges are preserved. Part frames, native primitive
50
63
  frames and embedded resource coordinates have separate contracts. Complete
51
- assembly geometry, inherited attributes and drawings remain unsupported.
64
+ assembly geometry, inherited attributes and complete drawing reconstruction remain unsupported.
52
65
  Read the [support boundaries](docs/support.md) and [release notes](docs/changelog.md).
53
66
 
54
67
  Run `icadkit view model.icd` to open qualified native primitives and their
@@ -60,7 +73,7 @@ The base reader supports standard GIL-enabled CPython 3.10–3.14. Wheel targets
60
73
  are Linux x86_64 (glibc 2.28+), Windows x86_64 and macOS ARM64 (11+):
61
74
 
62
75
  ```sh
63
- python -m pip install icadkit==0.3.0
76
+ python -m pip install icadkit
64
77
  ```
65
78
 
66
79
  The native extension bundles `parasolid-core` and has no mandatory Python
@@ -69,7 +82,7 @@ explicit compatible catalog is needed only for schemas absent from the built-in
69
82
  profiles. Release files are available on the
70
83
  [GitHub releases page](https://github.com/monozukuri-ai/icadkit/releases).
71
84
 
72
- For preview/GLB, install `python -m pip install 'icadkit[preview]==0.3.0'`.
85
+ For preview/GLB, install `python -m pip install 'icadkit[preview]'`.
73
86
  The optional OCCT dependency requires glibc 2.31+ on Linux; see
74
87
  [preview requirements](docs/preview.md#dependencies-and-validation).
75
88
  To build from a source checkout or sdist, install Rust 1.88+ and a C linker,
@@ -98,8 +111,9 @@ Qualified V7L7 part frames use millimetres and are evaluated relative to the
98
111
  saved root frame. Qualified standalone primitive owners also expose geometry and saved
99
112
  entity appearance. The separate [CSG API](docs/csg.md) and
100
113
  `uv run --extra preview icadkit view model.icd --csg` evaluate qualified
101
- box/cylinder unions, differences and intersections. Unknown programs retain
102
- 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.
103
117
  The [saved final body mode](docs/saved-bodies.md), `view --saved-brep`, also
104
118
  displays qualified V7L7/V8L3 final bodies and imported solids, including bounded
105
119
  spherical, conical and toroidal surfaces. V8L3 resource sharing preserves each
@@ -112,8 +126,14 @@ native cones/frusta and full ring tori. The updated exact V34 profile in
112
126
  `parasolid-core 0.3.1` removes the catalog requirement for qualified toroidal
113
127
  resources.
114
128
 
115
- Qualified V8L3 part frames use millimetres. Mirrored frames and external-file
116
- loading remain unsupported. Extended information is stored text, not interpreted
129
+ Version 0.3.5 extends qualified millimetre frames and bounded
130
+ native/saved geometry to V7L6/V7L7 and V8L1/V8L2/V8L3, including internal mirrors.
131
+ Signed occurrence orientation is separate from already placed geometry; see
132
+ [mirror semantics](docs/parts.md#coordinate-frames-and-units). Explicit
133
+ [external-reference resolution](docs/references.md) now composes qualified child
134
+ and grandchild placements, including mirrors, through `read_assembly()` or
135
+ `icadkit view model.icd --reference-root /path/to/bundle`. Saved names, resolved
136
+ paths, hashes and missing/ambiguous references remain separate. Extended information is stored text, not interpreted
117
137
  typed engineering properties. Check each scope's status before relying on its values.
118
138
 
119
139
  ## Embedded geometry
@@ -4,23 +4,36 @@ 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.0** adds:
8
-
9
- - A [native file viewer](docs/viewer.md) with a part tree, stored properties,
10
- selection and visibility controls. Qualified boxes, cylinders, full spheres,
11
- cones/frusta and full ring tori use their saved frames.
12
- - Broader [part access](docs/parts.md): V7L7 traversal, bounded V8L1/V8L2
13
- inventories and binary attributes retained with ownership and raw bytes.
14
- - Optional [V7L7 boolean evaluation](docs/csg.md) and
15
- [saved final body display](docs/saved-bodies.md) for V7L7/V8L3, including
16
- imported solids, shared resources and bounded analytic surfaces.
17
- - Updated exact V34 Parasolid support through `parasolid-core 0.3.1`, including
18
- qualified toroidal resources without an external catalog.
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
+
29
+ Version 0.3.0 added the [native file viewer](docs/viewer.md), broader
30
+ [part access](docs/parts.md), optional [V7L7 boolean evaluation](docs/csg.md)
31
+ and [saved final body display](docs/saved-bodies.md).
19
32
 
20
33
  icadkit is experimental. Unsupported geometry remains in the part inventory;
21
34
  unknown values and source ranges are preserved. Part frames, native primitive
22
35
  frames and embedded resource coordinates have separate contracts. Complete
23
- assembly geometry, inherited attributes and drawings remain unsupported.
36
+ assembly geometry, inherited attributes and complete drawing reconstruction remain unsupported.
24
37
  Read the [support boundaries](docs/support.md) and [release notes](docs/changelog.md).
25
38
 
26
39
  Run `icadkit view model.icd` to open qualified native primitives and their
@@ -32,7 +45,7 @@ The base reader supports standard GIL-enabled CPython 3.10–3.14. Wheel targets
32
45
  are Linux x86_64 (glibc 2.28+), Windows x86_64 and macOS ARM64 (11+):
33
46
 
34
47
  ```sh
35
- python -m pip install icadkit==0.3.0
48
+ python -m pip install icadkit
36
49
  ```
37
50
 
38
51
  The native extension bundles `parasolid-core` and has no mandatory Python
@@ -41,7 +54,7 @@ explicit compatible catalog is needed only for schemas absent from the built-in
41
54
  profiles. Release files are available on the
42
55
  [GitHub releases page](https://github.com/monozukuri-ai/icadkit/releases).
43
56
 
44
- For preview/GLB, install `python -m pip install 'icadkit[preview]==0.3.0'`.
57
+ For preview/GLB, install `python -m pip install 'icadkit[preview]'`.
45
58
  The optional OCCT dependency requires glibc 2.31+ on Linux; see
46
59
  [preview requirements](docs/preview.md#dependencies-and-validation).
47
60
  To build from a source checkout or sdist, install Rust 1.88+ and a C linker,
@@ -70,8 +83,9 @@ Qualified V7L7 part frames use millimetres and are evaluated relative to the
70
83
  saved root frame. Qualified standalone primitive owners also expose geometry and saved
71
84
  entity appearance. The separate [CSG API](docs/csg.md) and
72
85
  `uv run --extra preview icadkit view model.icd --csg` evaluate qualified
73
- box/cylinder unions, differences and intersections. Unknown programs retain
74
- 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.
75
89
  The [saved final body mode](docs/saved-bodies.md), `view --saved-brep`, also
76
90
  displays qualified V7L7/V8L3 final bodies and imported solids, including bounded
77
91
  spherical, conical and toroidal surfaces. V8L3 resource sharing preserves each
@@ -84,8 +98,14 @@ native cones/frusta and full ring tori. The updated exact V34 profile in
84
98
  `parasolid-core 0.3.1` removes the catalog requirement for qualified toroidal
85
99
  resources.
86
100
 
87
- Qualified V8L3 part frames use millimetres. Mirrored frames and external-file
88
- loading remain unsupported. Extended information is stored text, not interpreted
101
+ Version 0.3.5 extends qualified millimetre frames and bounded
102
+ native/saved geometry to V7L6/V7L7 and V8L1/V8L2/V8L3, including internal mirrors.
103
+ Signed occurrence orientation is separate from already placed geometry; see
104
+ [mirror semantics](docs/parts.md#coordinate-frames-and-units). Explicit
105
+ [external-reference resolution](docs/references.md) now composes qualified child
106
+ and grandchild placements, including mirrors, through `read_assembly()` or
107
+ `icadkit view model.icd --reference-root /path/to/bundle`. Saved names, resolved
108
+ paths, hashes and missing/ambiguous references remain separate. Extended information is stored text, not interpreted
89
109
  typed engineering properties. Check each scope's status before relying on its values.
90
110
 
91
111
  ## Embedded geometry
@@ -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.1` (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.
@@ -0,0 +1,57 @@
1
+ # Public regression corpus
2
+
3
+ These eight cases are authored synthetic framing/topology, not iCAD-produced
4
+ models. No vendor CAD payload, proprietary catalog or SDK is used. Project-authored
5
+ material is offered under PolyForm Noncommercial 1.0.0; see [LICENSE](../LICENSE).
6
+ The V30 scalar layouts come from the MIT/Apache-2.0 parasolid-core profile,
7
+ as documented in tests/geometry_fixtures.py.
8
+
9
+ The four wire cases describe endpoints (2, -1, 3) and (5, 3, 3), independently
10
+ giving length 5 in unspecified source units. They cover both byte orders and
11
+ raw/zlib owners. Other cases cover uninterpreted content, an unknown schema,
12
+ an invalid reference, and a bad zlib checksum. None is a geometric holdout.
13
+
14
+ public.jsonl pins generated bytes, provenance, expected scope and diagnostics.
15
+ The generator uses a stored DEFLATE block so hashes do not depend on zlib's
16
+ compression heuristics. The checker never rewrites expectations or skips inputs.
17
+
18
+ ```sh
19
+ python corpus/generate.py --output .local/public-corpus
20
+ uv run python scripts/verify_corpus.py --manifest corpus/public.jsonl \
21
+ --root .local/public-corpus --required
22
+ ```
23
+
24
+ The generators, manifest and tests are in the sdist. Generated ICD files are
25
+ excluded from both wheel and sdist. These synthetic cases verify specific
26
+ behaviors and do not establish general compatibility with vendor-produced files.
27
+
28
+ ## Caller-owned native regression data
29
+
30
+ `scripts/verify_native_corpus.py` checks an explicit JSON manifest without
31
+ starting iCAD. Each row pins an input SHA-256, its existing API snapshot,
32
+ `family_id` and `development`/`validation` partition. Optional SDK observations,
33
+ required companion files and intentionally absent dependencies have separate
34
+ entries. Supply each named input root explicitly with `--root NAME=PATH` and
35
+ pin the manifest itself with `--manifest-sha256` when recording a baseline.
36
+
37
+ The runner rejects missing/changed evidence and split families or shared CAD
38
+ payloads across different families. It reports unchanged reader behavior
39
+ separately from SDK comparison. Current SDK checks cover host child-part
40
+ hierarchy, saved names/properties and available world frames, not full geometry.
41
+ Resolved external descendants belong to their own document. An unloaded SDK
42
+ placeholder cannot certify saved comment/reference properties. A library-part
43
+ insertion oracle cannot certify the original file's raw document coordinates.
44
+ These fields remain explicitly partial or not comparable.
45
+ Repeated same-name parent paths remain partial where occurrence ownership cannot
46
+ be independently matched; equal counts and list ordering are not proof.
47
+
48
+ The manifest and actual CAD/SDK data are not included. Tests construct independent
49
+ synthetic evidence. An unchanged unsupported result passes the regression check
50
+ but does not qualify that file as newly supported.
51
+
52
+ The explicit [assembly resolver](../docs/references.md) has separate synthetic
53
+ tests in `tests/test_references.py` and optional browser checks in
54
+ `tests/viewer_assembly_browser.mjs`. The single-file corpus snapshot is unchanged
55
+ by resolution. Private P5 SDK bundles additionally check child/grandchild frames,
56
+ dependency updates, missing targets, mirrors and placed geometry; these bundles
57
+ and their proprietary catalogs are not distributed.
@@ -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.1` (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.1 (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
+ }
@@ -7,7 +7,8 @@ use crate::provenance::sha256;
7
7
  use crate::record::record_info;
8
8
  use crate::{
9
9
  ByteOrder, ByteRange, Diagnostic, Encoding, ErrorKind, Extraction, InspectError, Inspection,
10
- ReadLimits, RecordInfo, ResourceRef, SourceRef, UnparsedRange, inspect_bytes,
10
+ ReadLimits, RecordInfo, ResourceAssociation, ResourceRef, SourceRef, UnparsedRange,
11
+ inspect_bytes,
11
12
  };
12
13
 
13
14
  /// Immutable owned input and a structural resource index. Construction never
@@ -21,6 +22,7 @@ pub struct Document {
21
22
  source_sha256: String,
22
23
  records: Vec<RecordInfo>,
23
24
  resources: Vec<ResourceRef>,
25
+ associations: Vec<ResourceAssociation>,
24
26
  unparsed_ranges: Vec<UnparsedRange>,
25
27
  diagnostics: Vec<Diagnostic>,
26
28
  resource_index_complete: bool,
@@ -43,6 +45,14 @@ impl Document {
43
45
  pub fn resources(&self) -> &[ResourceRef] {
44
46
  &self.resources
45
47
  }
48
+ /// Saved entity-to-resource records, in source order. Presence does not
49
+ /// establish that the entity or the resource is otherwise qualified.
50
+ pub fn associations(&self) -> &[ResourceAssociation] {
51
+ &self.associations
52
+ }
53
+ pub(crate) fn all_bytes(&self) -> &[u8] {
54
+ &self.data
55
+ }
46
56
  pub fn unparsed_ranges(&self) -> &[UnparsedRange] {
47
57
  &self.unparsed_ranges
48
58
  }
@@ -122,6 +132,7 @@ impl Document {
122
132
  source_sha256,
123
133
  records: Vec::new(),
124
134
  resources: Vec::new(),
135
+ associations: Vec::new(),
125
136
  unparsed_ranges: Vec::new(),
126
137
  diagnostics: Vec::new(),
127
138
  resource_index_complete: true,
@@ -419,6 +430,26 @@ impl Document {
419
430
  "view entity has an unobserved length",
420
431
  ))?;
421
432
  }
433
+ if kind == 0x88 {
434
+ // The fixed record names one saved entity, one resource
435
+ // number and that entity's frame. Its other words stay opaque.
436
+ let mut frame = [0.0; 9];
437
+ for (i, value) in frame.iter_mut().enumerate() {
438
+ let at = position + 24 + 8 * i;
439
+ let mut raw = [0; 8];
440
+ raw.copy_from_slice(&self.data[at..at + 8]);
441
+ *value = order.f64(raw);
442
+ }
443
+ self.associations.push(ResourceAssociation {
444
+ byte_range: ByteRange {
445
+ start: position as u64,
446
+ end: next as u64,
447
+ },
448
+ entity_source_id: self.word(position + 4)?,
449
+ resource_source_id: self.word(position + 8)?,
450
+ frame,
451
+ });
452
+ }
422
453
  self.opaque(position, next, "entity_metadata", "USR");
423
454
  }
424
455
  position = next;
@@ -561,4 +592,17 @@ impl Document {
561
592
  self.limits.resource(range.end - range.start, range.start)?;
562
593
  Ok(&self.data[range.start as usize..range.end as usize])
563
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
+ }
564
608
  }
@@ -13,6 +13,8 @@ mod reader;
13
13
  mod record;
14
14
  mod resource;
15
15
  mod schema;
16
+ mod trailer;
17
+ mod views;
16
18
 
17
19
  pub use document::Document;
18
20
  pub use error::{Diagnostic, ErrorKind, InspectError};
@@ -25,20 +27,28 @@ pub use native::{NativeEntityRecord, NativePrimitiveRecord};
25
27
  pub use parasolid::{
26
28
  GeometryDiagnostic, GeometryError, GeometryResult, GeometryStatus, SchemaSelection,
27
29
  };
28
- pub use parts::{PartAttributeRecord, PartIndex, PartLimits, PartOpaqueRange, PartRecord};
30
+ pub use parts::{
31
+ PartAttributeRecord, PartIndex, PartLimits, PartOpaqueRange, PartProfileInfo, PartRecord,
32
+ PartViewRecord,
33
+ };
29
34
  pub use provenance::{Extraction, SourceRef};
30
35
  pub use reader::ByteOrder;
31
36
  pub use record::{ByteRange, RecordInfo};
32
- pub use resource::{Encoding, ResourceRef};
37
+ pub use resource::{Encoding, ResourceAssociation, ResourceRef};
33
38
  pub use schema::SchemaCatalog;
39
+ pub use trailer::{
40
+ TrailerBlock, TrailerBlockData, TrailerEdge, TrailerFace, TrailerIndex, TrailerLimits,
41
+ TrailerParameterLine, TrailerSurface, TrailerTable, TrailerView,
42
+ };
43
+ pub use views::{ViewEntry, ViewIndex, ViewLimits, ViewRecord};
34
44
 
35
45
  use parasolid_core::{BuiltinProfileRegistry, ParseError};
36
46
 
37
47
  /// Version of this Rust crate, in Cargo SemVer notation.
38
48
  pub const VERSION: &str = env!("CARGO_PKG_VERSION");
39
49
 
40
- /// Exact registry dependency; checked against the manifest and lock in CI.
41
- pub const PARASOLID_CORE_VERSION: &str = "0.3.1";
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");
42
52
 
43
53
  /// Metadata of the compiled Parasolid backend, not ICD format coverage.
44
54
  #[derive(Debug, Clone, PartialEq, Eq)]
@@ -75,7 +85,8 @@ mod tests {
75
85
  assert!(!info.builtin_profile_ids.is_empty());
76
86
  let registry = BuiltinProfileRegistry::compiled()?;
77
87
  let covered = SchemaKey::parse("SCH_3000310_30000_13006")?;
78
- let uncovered = SchemaKey::parse("SCH_2601246_26105_13006")?;
88
+ // A neighbouring modeller build is a different key, never a fallback.
89
+ let uncovered = SchemaKey::parse("SCH_3000311_30000_13006")?;
79
90
  assert!(registry.provider_for_key(&covered).is_some());
80
91
  assert!(registry.provider_for_key(&uncovered).is_none());
81
92
  Ok(())