icadkit 0.2.0__tar.gz → 0.3.0__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 (108) hide show
  1. {icadkit-0.2.0 → icadkit-0.3.0}/Cargo.lock +4 -4
  2. {icadkit-0.2.0 → icadkit-0.3.0}/Cargo.toml +2 -2
  3. {icadkit-0.2.0 → icadkit-0.3.0}/LICENSES/rust-dependencies.txt +1 -1
  4. {icadkit-0.2.0 → icadkit-0.3.0}/PKG-INFO +41 -18
  5. {icadkit-0.2.0 → icadkit-0.3.0}/README.md +41 -18
  6. {icadkit-0.2.0 → icadkit-0.3.0}/THIRD_PARTY_NOTICES.md +1 -1
  7. {icadkit-0.2.0 → icadkit-0.3.0}/crates/icad-core/LICENSE +2 -2
  8. {icadkit-0.2.0 → icadkit-0.3.0}/crates/icad-core/src/lib.rs +2 -2
  9. {icadkit-0.2.0 → icadkit-0.3.0}/crates/icad-core/src/native.rs +65 -5
  10. {icadkit-0.2.0 → icadkit-0.3.0}/crates/icad-core/src/parts.rs +259 -46
  11. {icadkit-0.2.0 → icadkit-0.3.0}/crates/icad-python/LICENSE +2 -2
  12. {icadkit-0.2.0 → icadkit-0.3.0}/crates/icad-python/src/document.rs +10 -0
  13. {icadkit-0.2.0 → icadkit-0.3.0}/docs/api.md +5 -2
  14. icadkit-0.3.0/docs/changelog.md +109 -0
  15. icadkit-0.3.0/docs/csg.md +99 -0
  16. {icadkit-0.2.0 → icadkit-0.3.0}/docs/native.md +44 -6
  17. {icadkit-0.2.0 → icadkit-0.3.0}/docs/parts.md +64 -5
  18. {icadkit-0.2.0 → icadkit-0.3.0}/docs/preview.md +6 -2
  19. {icadkit-0.2.0 → icadkit-0.3.0}/docs/roadmap.md +86 -2
  20. icadkit-0.3.0/docs/saved-bodies.md +117 -0
  21. {icadkit-0.2.0 → icadkit-0.3.0}/docs/support.md +33 -20
  22. icadkit-0.3.0/docs/viewer.md +126 -0
  23. {icadkit-0.2.0 → icadkit-0.3.0}/pyproject.toml +1 -0
  24. {icadkit-0.2.0 → icadkit-0.3.0}/scripts/check_license.py +1 -2
  25. {icadkit-0.2.0 → icadkit-0.3.0}/scripts/verify_artifacts.py +32 -4
  26. {icadkit-0.2.0 → icadkit-0.3.0}/src/icadkit/__init__.py +39 -0
  27. {icadkit-0.2.0 → icadkit-0.3.0}/src/icadkit/_core.pyi +2 -1
  28. icadkit-0.3.0/src/icadkit/_csg_occt.py +268 -0
  29. {icadkit-0.2.0 → icadkit-0.3.0}/src/icadkit/_preview_bridge.py +18 -3
  30. icadkit-0.3.0/src/icadkit/_saved_occt.py +183 -0
  31. icadkit-0.3.0/src/icadkit/_viewer/index.html +34 -0
  32. icadkit-0.3.0/src/icadkit/_viewer/viewer.css +51 -0
  33. icadkit-0.3.0/src/icadkit/_viewer/viewer.js +356 -0
  34. icadkit-0.3.0/src/icadkit/_viewer_io.py +121 -0
  35. {icadkit-0.2.0 → icadkit-0.3.0}/src/icadkit/cli.py +148 -8
  36. icadkit-0.3.0/src/icadkit/csg.py +550 -0
  37. {icadkit-0.2.0 → icadkit-0.3.0}/src/icadkit/native.py +20 -7
  38. {icadkit-0.2.0 → icadkit-0.3.0}/src/icadkit/parts.py +165 -7
  39. {icadkit-0.2.0 → icadkit-0.3.0}/src/icadkit/preview.py +1 -22
  40. icadkit-0.3.0/src/icadkit/saved.py +387 -0
  41. icadkit-0.3.0/src/icadkit/viewer.py +629 -0
  42. {icadkit-0.2.0 → icadkit-0.3.0}/tests/part_fixtures.py +15 -3
  43. icadkit-0.3.0/tests/saved_fixtures.py +117 -0
  44. {icadkit-0.2.0 → icadkit-0.3.0}/tests/test_api.py +2 -3
  45. {icadkit-0.2.0 → icadkit-0.3.0}/tests/test_cli.py +1 -1
  46. icadkit-0.3.0/tests/test_csg.py +411 -0
  47. {icadkit-0.2.0 → icadkit-0.3.0}/tests/test_distribution.py +2 -0
  48. icadkit-0.3.0/tests/test_followup_parts.py +160 -0
  49. {icadkit-0.2.0 → icadkit-0.3.0}/tests/test_geometry.py +4 -4
  50. {icadkit-0.2.0 → icadkit-0.3.0}/tests/test_native.py +49 -8
  51. icadkit-0.3.0/tests/test_native_round.py +95 -0
  52. icadkit-0.3.0/tests/test_saved.py +409 -0
  53. icadkit-0.3.0/tests/test_v7_parts.py +366 -0
  54. icadkit-0.3.0/tests/test_viewer.py +347 -0
  55. icadkit-0.3.0/tests/viewer_browser.mjs +160 -0
  56. icadkit-0.2.0/docs/changelog.md +0 -54
  57. {icadkit-0.2.0 → icadkit-0.3.0}/COMMERCIAL-LICENSE.md +0 -0
  58. {icadkit-0.2.0 → icadkit-0.3.0}/LICENSE +0 -0
  59. {icadkit-0.2.0 → icadkit-0.3.0}/LICENSES/Apache-2.0.txt +0 -0
  60. {icadkit-0.2.0 → icadkit-0.3.0}/LICENSES/PolyForm-Noncommercial-1.0.0.md +0 -0
  61. {icadkit-0.2.0 → icadkit-0.3.0}/LICENSES/parasolid-core-MIT.txt +0 -0
  62. {icadkit-0.2.0 → icadkit-0.3.0}/corpus/README.md +0 -0
  63. {icadkit-0.2.0 → icadkit-0.3.0}/corpus/generate.py +0 -0
  64. {icadkit-0.2.0 → icadkit-0.3.0}/corpus/public.jsonl +0 -0
  65. {icadkit-0.2.0 → icadkit-0.3.0}/crates/icad-core/Cargo.toml +0 -0
  66. {icadkit-0.2.0 → icadkit-0.3.0}/crates/icad-core/src/compression.rs +0 -0
  67. {icadkit-0.2.0 → icadkit-0.3.0}/crates/icad-core/src/document.rs +0 -0
  68. {icadkit-0.2.0 → icadkit-0.3.0}/crates/icad-core/src/error.rs +0 -0
  69. {icadkit-0.2.0 → icadkit-0.3.0}/crates/icad-core/src/header.rs +0 -0
  70. {icadkit-0.2.0 → icadkit-0.3.0}/crates/icad-core/src/limits.rs +0 -0
  71. {icadkit-0.2.0 → icadkit-0.3.0}/crates/icad-core/src/parasolid.rs +0 -0
  72. {icadkit-0.2.0 → icadkit-0.3.0}/crates/icad-core/src/provenance.rs +0 -0
  73. {icadkit-0.2.0 → icadkit-0.3.0}/crates/icad-core/src/reader.rs +0 -0
  74. {icadkit-0.2.0 → icadkit-0.3.0}/crates/icad-core/src/record.rs +0 -0
  75. {icadkit-0.2.0 → icadkit-0.3.0}/crates/icad-core/src/resource.rs +0 -0
  76. {icadkit-0.2.0 → icadkit-0.3.0}/crates/icad-core/src/schema.rs +0 -0
  77. {icadkit-0.2.0 → icadkit-0.3.0}/crates/icad-core/tests/header.rs +0 -0
  78. {icadkit-0.2.0 → icadkit-0.3.0}/crates/icad-core/tests/resources.rs +0 -0
  79. {icadkit-0.2.0 → icadkit-0.3.0}/crates/icad-python/Cargo.toml +0 -0
  80. {icadkit-0.2.0 → icadkit-0.3.0}/crates/icad-python/src/brep.rs +0 -0
  81. {icadkit-0.2.0 → icadkit-0.3.0}/crates/icad-python/src/geometry.rs +0 -0
  82. {icadkit-0.2.0 → icadkit-0.3.0}/crates/icad-python/src/lib.rs +0 -0
  83. {icadkit-0.2.0 → icadkit-0.3.0}/crates/icad-python/src/schema.rs +0 -0
  84. {icadkit-0.2.0 → icadkit-0.3.0}/docs/license.md +0 -0
  85. {icadkit-0.2.0 → icadkit-0.3.0}/scripts/check_public_tree.py +0 -0
  86. {icadkit-0.2.0 → icadkit-0.3.0}/scripts/test_publication.py +0 -0
  87. {icadkit-0.2.0 → icadkit-0.3.0}/scripts/verify_corpus.py +0 -0
  88. {icadkit-0.2.0 → icadkit-0.3.0}/scripts/verify_install.py +0 -0
  89. {icadkit-0.2.0 → icadkit-0.3.0}/src/icadkit/__main__.py +0 -0
  90. {icadkit-0.2.0 → icadkit-0.3.0}/src/icadkit/api.py +0 -0
  91. {icadkit-0.2.0 → icadkit-0.3.0}/src/icadkit/document.py +0 -0
  92. {icadkit-0.2.0 → icadkit-0.3.0}/src/icadkit/errors.py +0 -0
  93. {icadkit-0.2.0 → icadkit-0.3.0}/src/icadkit/geometry.py +0 -0
  94. {icadkit-0.2.0 → icadkit-0.3.0}/src/icadkit/models.py +0 -0
  95. {icadkit-0.2.0 → icadkit-0.3.0}/src/icadkit/py.typed +0 -0
  96. {icadkit-0.2.0 → icadkit-0.3.0}/src/icadkit/schema.py +0 -0
  97. {icadkit-0.2.0 → icadkit-0.3.0}/tests/conftest.py +0 -0
  98. {icadkit-0.2.0 → icadkit-0.3.0}/tests/fixture_builders.py +0 -0
  99. {icadkit-0.2.0 → icadkit-0.3.0}/tests/geometry_fixtures.py +0 -0
  100. {icadkit-0.2.0 → icadkit-0.3.0}/tests/preview_fixtures.py +0 -0
  101. {icadkit-0.2.0 → icadkit-0.3.0}/tests/test_corpus.py +0 -0
  102. {icadkit-0.2.0 → icadkit-0.3.0}/tests/test_inspect.py +0 -0
  103. {icadkit-0.2.0 → icadkit-0.3.0}/tests/test_part_semantics.py +0 -0
  104. {icadkit-0.2.0 → icadkit-0.3.0}/tests/test_parts.py +0 -0
  105. {icadkit-0.2.0 → icadkit-0.3.0}/tests/test_preview.py +0 -0
  106. {icadkit-0.2.0 → icadkit-0.3.0}/tests/test_resource_cli.py +0 -0
  107. {icadkit-0.2.0 → icadkit-0.3.0}/tests/test_resources.py +0 -0
  108. {icadkit-0.2.0 → icadkit-0.3.0}/uv.lock +0 -0
@@ -89,7 +89,7 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
89
89
 
90
90
  [[package]]
91
91
  name = "icad-core"
92
- version = "0.2.0"
92
+ version = "0.3.0"
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.2.0"
102
+ version = "0.3.0"
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.0"
145
+ version = "0.3.1"
146
146
  source = "registry+https://github.com/rust-lang/crates.io-index"
147
- checksum = "5de85a20a5b7dc7afb453f1114c1c44f27236c6447e1bd26e12227d87333adef"
147
+ checksum = "fa625646afc2be83fa25bdbfa453eb7aac9976d17d968f71d9f7e4a448ddcac8"
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.2.0"
6
+ version = "0.3.0"
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.0"
12
+ parasolid-core = "=0.3.1"
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.0 (MIT AND Apache-2.0) ===
137
+ === parasolid-core 0.3.1 (MIT AND Apache-2.0) ===
138
138
  MIT License
139
139
 
140
140
  Copyright (c) 2026 parasolid-kit contributors
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: icadkit
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Classifier: Development Status :: 2 - Pre-Alpha
5
5
  Classifier: Programming Language :: Python :: 3 :: Only
6
6
  Classifier: Programming Language :: Python :: Implementation :: CPython
@@ -32,23 +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.2.0** adds:
35
+ Version **0.3.0** adds:
36
36
 
37
- - [Native part access](docs/parts.md): hierarchy, internal snapshot definitions,
38
- unresolved external references, millimetre local/world part frames, comments
39
- and extended text, with per-part Python rows.
40
- - [Native parameters and appearance](docs/native.md): qualified box/cylinder
41
- dimensions and global frames, saved entity palette indices, visibility and layers.
42
- - The exact iCAD V34 `SCH_3401212_34101_13006` Parasolid profile through
43
- `parasolid-core 0.3.0`, without an external catalog for qualified resources.
44
- - Optional [resource preview and GLB export](docs/preview.md), with explicit
45
- source units and a local browser viewer.
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.
46
47
 
47
48
  icadkit is experimental. Unsupported geometry remains in the part inventory;
48
49
  unknown values and source ranges are preserved. Part frames, native primitive
49
50
  frames and embedded resource coordinates have separate contracts. Complete
50
51
  assembly geometry, inherited attributes and drawings remain unsupported.
51
- Read the [support boundaries](docs/support.md) and [changes since 0.1.0](docs/changelog.md).
52
+ Read the [support boundaries](docs/support.md) and [release notes](docs/changelog.md).
53
+
54
+ Run `icadkit view model.icd` to open qualified native primitives and their
55
+ part properties. The base viewer works without the preview extra.
52
56
 
53
57
  ## Installation
54
58
 
@@ -56,7 +60,7 @@ The base reader supports standard GIL-enabled CPython 3.10–3.14. Wheel targets
56
60
  are Linux x86_64 (glibc 2.28+), Windows x86_64 and macOS ARM64 (11+):
57
61
 
58
62
  ```sh
59
- python -m pip install icadkit==0.2.0
63
+ python -m pip install icadkit==0.3.0
60
64
  ```
61
65
 
62
66
  The native extension bundles `parasolid-core` and has no mandatory Python
@@ -65,7 +69,7 @@ explicit compatible catalog is needed only for schemas absent from the built-in
65
69
  profiles. Release files are available on the
66
70
  [GitHub releases page](https://github.com/monozukuri-ai/icadkit/releases).
67
71
 
68
- For preview/GLB, install `python -m pip install 'icadkit[preview]==0.2.0'`.
72
+ For preview/GLB, install `python -m pip install 'icadkit[preview]==0.3.0'`.
69
73
  The optional OCCT dependency requires glibc 2.31+ on Linux; see
70
74
  [preview requirements](docs/preview.md#dependencies-and-validation).
71
75
  To build from a source checkout or sdist, install Rust 1.88+ and a C linker,
@@ -88,10 +92,29 @@ for part in parts.walk(include_root=False):
88
92
  rows = parts.to_rows() # JSON-compatible rows; not certified BOM quantities.
89
93
  ```
90
94
 
91
- The qualified native profile is the observed little-endian V8L3 `3DGLOBAL`
92
- layout. Part frames use millimetres. Mirrored frames and external-file loading
93
- remain unsupported. Extended information is stored text, not interpreted typed
94
- engineering properties. Check each scope's status before relying on its values.
95
+ The reader supports the observed little-endian V7L7 part layout:
96
+ hierarchy, names, comments, extended text and saved external reference names.
97
+ Qualified V7L7 part frames use millimetres and are evaluated relative to the
98
+ saved root frame. Qualified standalone primitive owners also expose geometry and saved
99
+ entity appearance. The separate [CSG API](docs/csg.md) and
100
+ `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.
103
+ The [saved final body mode](docs/saved-bodies.md), `view --saved-brep`, also
104
+ displays qualified V7L7/V8L3 final bodies and imported solids, including bounded
105
+ spherical, conical and toroidal surfaces. V8L3 resource sharing preserves each
106
+ occurrence's saved placement. An explicit schema catalog is needed when the
107
+ exact built-in profile lacks a required type. Counted metadata framing also
108
+ extends part inventories while preserving unknown records and diagnostics.
109
+ Version 0.3.0 also preserves bounded binary attributes as raw owned records,
110
+ reads V8L1/V8L2 part inventories without assigning units or geometry, and displays
111
+ native cones/frusta and full ring tori. The updated exact V34 profile in
112
+ `parasolid-core 0.3.1` removes the catalog requirement for qualified toroidal
113
+ resources.
114
+
115
+ Qualified V8L3 part frames use millimetres. Mirrored frames and external-file
116
+ loading remain unsupported. Extended information is stored text, not interpreted
117
+ typed engineering properties. Check each scope's status before relying on its values.
95
118
 
96
119
  ## Embedded geometry
97
120
 
@@ -4,23 +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.2.0** adds:
8
-
9
- - [Native part access](docs/parts.md): hierarchy, internal snapshot definitions,
10
- unresolved external references, millimetre local/world part frames, comments
11
- and extended text, with per-part Python rows.
12
- - [Native parameters and appearance](docs/native.md): qualified box/cylinder
13
- dimensions and global frames, saved entity palette indices, visibility and layers.
14
- - The exact iCAD V34 `SCH_3401212_34101_13006` Parasolid profile through
15
- `parasolid-core 0.3.0`, without an external catalog for qualified resources.
16
- - Optional [resource preview and GLB export](docs/preview.md), with explicit
17
- source units and a local browser viewer.
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.
18
19
 
19
20
  icadkit is experimental. Unsupported geometry remains in the part inventory;
20
21
  unknown values and source ranges are preserved. Part frames, native primitive
21
22
  frames and embedded resource coordinates have separate contracts. Complete
22
23
  assembly geometry, inherited attributes and drawings remain unsupported.
23
- Read the [support boundaries](docs/support.md) and [changes since 0.1.0](docs/changelog.md).
24
+ Read the [support boundaries](docs/support.md) and [release notes](docs/changelog.md).
25
+
26
+ Run `icadkit view model.icd` to open qualified native primitives and their
27
+ part properties. The base viewer works without the preview extra.
24
28
 
25
29
  ## Installation
26
30
 
@@ -28,7 +32,7 @@ The base reader supports standard GIL-enabled CPython 3.10–3.14. Wheel targets
28
32
  are Linux x86_64 (glibc 2.28+), Windows x86_64 and macOS ARM64 (11+):
29
33
 
30
34
  ```sh
31
- python -m pip install icadkit==0.2.0
35
+ python -m pip install icadkit==0.3.0
32
36
  ```
33
37
 
34
38
  The native extension bundles `parasolid-core` and has no mandatory Python
@@ -37,7 +41,7 @@ explicit compatible catalog is needed only for schemas absent from the built-in
37
41
  profiles. Release files are available on the
38
42
  [GitHub releases page](https://github.com/monozukuri-ai/icadkit/releases).
39
43
 
40
- For preview/GLB, install `python -m pip install 'icadkit[preview]==0.2.0'`.
44
+ For preview/GLB, install `python -m pip install 'icadkit[preview]==0.3.0'`.
41
45
  The optional OCCT dependency requires glibc 2.31+ on Linux; see
42
46
  [preview requirements](docs/preview.md#dependencies-and-validation).
43
47
  To build from a source checkout or sdist, install Rust 1.88+ and a C linker,
@@ -60,10 +64,29 @@ for part in parts.walk(include_root=False):
60
64
  rows = parts.to_rows() # JSON-compatible rows; not certified BOM quantities.
61
65
  ```
62
66
 
63
- The qualified native profile is the observed little-endian V8L3 `3DGLOBAL`
64
- layout. Part frames use millimetres. Mirrored frames and external-file loading
65
- remain unsupported. Extended information is stored text, not interpreted typed
66
- engineering properties. Check each scope's status before relying on its values.
67
+ The reader supports the observed little-endian V7L7 part layout:
68
+ hierarchy, names, comments, extended text and saved external reference names.
69
+ Qualified V7L7 part frames use millimetres and are evaluated relative to the
70
+ saved root frame. Qualified standalone primitive owners also expose geometry and saved
71
+ entity appearance. The separate [CSG API](docs/csg.md) and
72
+ `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.
75
+ The [saved final body mode](docs/saved-bodies.md), `view --saved-brep`, also
76
+ displays qualified V7L7/V8L3 final bodies and imported solids, including bounded
77
+ spherical, conical and toroidal surfaces. V8L3 resource sharing preserves each
78
+ occurrence's saved placement. An explicit schema catalog is needed when the
79
+ exact built-in profile lacks a required type. Counted metadata framing also
80
+ extends part inventories while preserving unknown records and diagnostics.
81
+ Version 0.3.0 also preserves bounded binary attributes as raw owned records,
82
+ reads V8L1/V8L2 part inventories without assigning units or geometry, and displays
83
+ native cones/frusta and full ring tori. The updated exact V34 profile in
84
+ `parasolid-core 0.3.1` removes the catalog requirement for qualified toroidal
85
+ resources.
86
+
87
+ Qualified V8L3 part frames use millimetres. Mirrored frames and external-file
88
+ loading remain unsupported. Extended information is stored text, not interpreted
89
+ typed engineering properties. Check each scope's status before relying on its values.
67
90
 
68
91
  ## Embedded geometry
69
92
 
@@ -4,7 +4,7 @@ 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.0` (MIT AND Apache-2.0)
7
+ Binary distributions also contain `parasolid-core 0.3.1` (MIT AND Apache-2.0)
8
8
  and PyO3 (MIT OR Apache-2.0, MIT selected). The source metadata declares
9
9
  `PolyForm-Noncommercial-1.0.0`; the combined Python distribution declares
10
10
  `PolyForm-Noncommercial-1.0.0 AND MIT AND Apache-2.0`. These expressions describe
@@ -108,7 +108,7 @@ 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.0` (MIT AND Apache-2.0)
111
+ Binary distributions also contain `parasolid-core 0.3.1` (MIT AND Apache-2.0)
112
112
  and PyO3 (MIT OR Apache-2.0, MIT selected). The source metadata declares
113
113
  `PolyForm-Noncommercial-1.0.0`; the combined Python distribution declares
114
114
  `PolyForm-Noncommercial-1.0.0 AND MIT AND Apache-2.0`. These expressions describe
@@ -582,7 +582,7 @@ IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
582
582
  DEALINGS IN THE SOFTWARE.
583
583
 
584
584
 
585
- === parasolid-core 0.3.0 (MIT AND Apache-2.0) ===
585
+ === parasolid-core 0.3.1 (MIT AND Apache-2.0) ===
586
586
  MIT License
587
587
 
588
588
  Copyright (c) 2026 parasolid-kit contributors
@@ -25,7 +25,7 @@ pub use native::{NativeEntityRecord, NativePrimitiveRecord};
25
25
  pub use parasolid::{
26
26
  GeometryDiagnostic, GeometryError, GeometryResult, GeometryStatus, SchemaSelection,
27
27
  };
28
- pub use parts::{PartIndex, PartLimits, PartOpaqueRange, PartRecord};
28
+ pub use parts::{PartAttributeRecord, PartIndex, PartLimits, PartOpaqueRange, PartRecord};
29
29
  pub use provenance::{Extraction, SourceRef};
30
30
  pub use reader::ByteOrder;
31
31
  pub use record::{ByteRange, RecordInfo};
@@ -38,7 +38,7 @@ use parasolid_core::{BuiltinProfileRegistry, ParseError};
38
38
  pub const VERSION: &str = env!("CARGO_PKG_VERSION");
39
39
 
40
40
  /// Exact registry dependency; checked against the manifest and lock in CI.
41
- pub const PARASOLID_CORE_VERSION: &str = "0.3.0";
41
+ pub const PARASOLID_CORE_VERSION: &str = "0.3.1";
42
42
 
43
43
  /// Metadata of the compiled Parasolid backend, not ICD format coverage.
44
44
  #[derive(Debug, Clone, PartialEq, Eq)]
@@ -4,9 +4,12 @@ use crate::{ByteRange, Diagnostic, ErrorKind, Status};
4
4
  #[derive(Debug, Clone)]
5
5
  pub struct NativePrimitiveRecord {
6
6
  pub kind: &'static str,
7
- /// Global frame: origin, Z axis, X axis. Values are in millimetres.
7
+ /// Stored frame: origin, Z axis, X axis, in millimetres. V8L3 is global;
8
+ /// V7L7 requires inverse(saved root frame) before exposing global placement.
8
9
  pub frame: [f64; 9],
9
10
  /// Box: height, xmin, ymin, xmax, ymax. Cylinder: radius, height.
11
+ /// Full sphere: radius, repeated radius, pi. Cone: height, four zero offsets,
12
+ /// base radius, top radius. Torus: full sweep, major radius, minor radius, zero.
10
13
  pub parameters: Vec<f64>,
11
14
  }
12
15
 
@@ -40,8 +43,8 @@ impl NativeEntityRecord {
40
43
  }
41
44
  }
42
45
 
43
- pub(crate) fn read_entity(bytes: &[u8], byte_range: ByteRange) -> NativeEntityRecord {
44
- let mut result = NativeEntityRecord {
46
+ fn undecoded_entity(bytes: &[u8], byte_range: ByteRange) -> NativeEntityRecord {
47
+ NativeEntityRecord {
45
48
  byte_range,
46
49
  source_id: None,
47
50
  raw_type: (bytes.len() >= 16).then(|| word(bytes, 12) >> 24),
@@ -53,13 +56,41 @@ pub(crate) fn read_entity(bytes: &[u8], byte_range: ByteRange) -> NativeEntityRe
53
56
  geometry_status: Status::Unsupported,
54
57
  primitive: None,
55
58
  diagnostics: Vec::new(),
56
- };
59
+ }
60
+ }
61
+
62
+ pub(crate) fn read_opaque_entity(bytes: &[u8], byte_range: ByteRange) -> NativeEntityRecord {
63
+ let mut result = undecoded_entity(bytes, byte_range);
64
+ result.issue(
65
+ ErrorKind::Unsupported,
66
+ "native.v7_owner",
67
+ 0,
68
+ "V7L7 owner is not a complete standalone primitive list; entities remain opaque",
69
+ );
70
+ result
71
+ }
72
+
73
+ pub(crate) fn read_inventory_entity(bytes: &[u8], byte_range: ByteRange) -> NativeEntityRecord {
74
+ let mut result = undecoded_entity(bytes, byte_range);
75
+ result.issue(
76
+ ErrorKind::Unsupported,
77
+ "native.inventory_profile",
78
+ 0,
79
+ "V8L1/V8L2 inventory retains entities without evaluating geometry or appearance",
80
+ );
81
+ result
82
+ }
83
+
84
+ pub(crate) fn read_entity(bytes: &[u8], byte_range: ByteRange) -> NativeEntityRecord {
85
+ let mut result = undecoded_entity(bytes, byte_range);
57
86
  // Layer, saved visibility and palette index are qualified only for these
58
87
  // exact native layouts. A Parasolid body has a different attribute layout.
59
88
  let shape = match result.raw_type {
60
89
  Some(75) => Some((160, 0x56440088, "box")),
61
90
  Some(71) => Some((136, 0x50440070, "cylinder")),
62
91
  Some(72) => Some((144, 0x53440078, "sphere")),
92
+ Some(68) => Some((176, 0x57440098, "cone")),
93
+ Some(74) => Some((152, 0x54440080, "torus")),
63
94
  _ => None,
64
95
  };
65
96
  let layout = shape.is_some_and(|(length, marker, _)| {
@@ -106,7 +137,7 @@ pub(crate) fn read_entity(bytes: &[u8], byte_range: ByteRange) -> NativeEntityRe
106
137
  result.color_index = Some(color);
107
138
  result.appearance_status = Status::Complete;
108
139
  }
109
- if kind == "sphere" || result.is_mirror == Some(true) {
140
+ if result.is_mirror == Some(true) {
110
141
  result.issue(
111
142
  ErrorKind::Unsupported,
112
143
  "native.primitive",
@@ -134,6 +165,12 @@ pub(crate) fn read_entity(bytes: &[u8], byte_range: ByteRange) -> NativeEntityRe
134
165
  && values[13] > values[11]
135
166
  && (values[12] - values[10]).is_finite()
136
167
  && (values[13] - values[11]).is_finite()
168
+ } else if kind == "sphere" {
169
+ values[9] > 0.0
170
+ } else if kind == "cone" {
171
+ values[9] > 0.0 && values[14] > 0.0 && values[15] >= 0.0
172
+ } else if kind == "torus" {
173
+ values[10] > 0.0 && values[11] > 0.0 && (values[10] + values[11]).is_finite()
137
174
  } else {
138
175
  values[9] > 0.0 && values[10] > 0.0
139
176
  };
@@ -147,6 +184,29 @@ pub(crate) fn read_entity(bytes: &[u8], byte_range: ByteRange) -> NativeEntityRe
147
184
  );
148
185
  return result;
149
186
  }
187
+ if kind == "sphere" && (values[10] != values[9] || values[11] != std::f64::consts::PI) {
188
+ result.issue(
189
+ ErrorKind::Unsupported,
190
+ "native.sphere_extent",
191
+ 128,
192
+ "Only the qualified full-sphere extent is supported",
193
+ );
194
+ return result;
195
+ }
196
+ if (kind == "cone" && values[10..14].iter().any(|v| *v != 0.0))
197
+ || (kind == "torus"
198
+ && (values[9] != std::f64::consts::TAU
199
+ || values[12] != 0.0
200
+ || values[10] <= values[11]))
201
+ {
202
+ result.issue(
203
+ ErrorKind::Unsupported,
204
+ "native.primitive_extent",
205
+ 120,
206
+ "Only coaxial circular cones and full ring tori are qualified",
207
+ );
208
+ return result;
209
+ }
150
210
  let mut frame = [0.0; 9];
151
211
  frame.copy_from_slice(&values[..9]);
152
212
  result.primitive = Some(NativePrimitiveRecord {