Add ocs_doc_api: object-oriented CAD entity API (v2)

New crate crates/ocs_doc_api: object-centric facade (DocApi -> Document ->
collections -> typed handles), transport-agnostic wire layer (DocApiEnvelope =
single op | read-only query batch), per-op autocommit (no write transactions),
bulk ops with upfront-validation all-or-nothing, structured ApiError, and
build-time codegen (spec/entities.toml -> ops/query enums, api_reference.md,
binding_schema.json).

ocs_plugin_api: append-only PluginRequest::DocApiRequest / PluginResponse::
DocApiResponse (serde_bytes payload) + defaulted HostApi::doc_api_dispatch.

Host: DocApiBackend impl for HostSession (src/app/doc_api.rs) mapping to scene
primitives (solid_models lift-on-miss, register_prepared_solid_model, meshes
metrics), entity conversions (doc_api_convert.rs), HostSession accessors +
doc_api_dispatch override.

Tests: 592 host lib (incl. 7 DocApi integration tests: create/boolean/query,
unknown-id, transform-many all-or-nothing, query-batch cap, 2D/geometric/DWG
roundtrips), 8 crate unit tests. Examples + README/ARCHITECTURE/IMPLEMENTATION docs.
This commit is contained in:
Sebastian committed 2026-09-06 00:15:27 +02:00
1 parent 9129c85f97
commit e41086b058
44 files changed
+4837 -12

No files matched your search

+115
View File
@@ -0,0 +1,115 @@
# ocs_doc_api — API reference (auto-generated)
Envelope version: `1`
Do NOT edit: regenerated by `build.rs` from `spec/entities.toml`.
## `Solid` (acadrust `Solid3D`, collection `solids`)
B-rep solid. Host resolves bodies via the solid_models cache (lift-on-miss from ACIS SAT).
### Constructors (`doc.solids()`)
- **create_cuboid**(`origin: [f64; 3], size: [f64; 3]`) -> `Solid`
- **create_sphere**(`centre: [f64; 3], radius: f64`) -> `Solid`
- **create_cylinder**(`base: [f64; 3], radius: f64, height: f64`) -> `Solid`
- **create_cone**(`base: [f64; 3], radius: f64, height: f64`) -> `Solid`
- **create_torus**(`centre: [f64; 3], major_radius: f64, minor_radius: f64`) -> `Solid`
- **create_wedge**(`origin: [f64; 3], size: [f64; 3]`) -> `Solid`
- **extrude**(`profile: EntityRef, direction: [f64; 3]`) -> `Solid` — **not yet supported** (returns `ApiError::Unsupported`)
- **revolve**(`profile: EntityRef, pivot: [f64; 3], axis: [f64; 3], angle: f64`) -> `Solid` — **not yet supported** (returns `ApiError::Unsupported`)
### Methods
- **intersect**(`other: Solid`) -> `Solid` — op `SolidBoolean`
- **union**(`other: Solid`) -> `Solid` — op `SolidBoolean`
- **subtract**(`other: Solid`) -> `Solid` — op `SolidBoolean`
- **volume**(``) -> `f64` — query `GetVolume`
- **centroid**(``) -> `[f64; 3]` — query `GetCentroid`
- **intersects**(`other: Solid`) -> `bool` — query `GetIntersects`
## `Line` (acadrust `Line`, collection `curves`)
### Constructors (`doc.curves()`)
- **create_line**(`start: [f64; 3], end: [f64; 3]`) -> `Line`
## `Circle` (acadrust `Circle`, collection `curves`)
### Constructors (`doc.curves()`)
- **create_circle**(`centre: [f64; 3], radius: f64`) -> `Circle`
## `Polyline` (acadrust `LwPolyline`, collection `curves`)
### Constructors (`doc.curves()`)
- **create_polyline**(`points: &[[f64; 3]], closed: bool`) -> `Polyline`
### Methods
- **add_vertex**(`at: usize, point: [f64; 3]`) -> `()` — op `AddVertex` — **not yet supported** (returns `ApiError::Unsupported`)
## `Point` (acadrust `Point`, collection `curves`)
### Constructors (`doc.curves()`)
- **create_point**(`position: [f64; 3]`) -> `Point`
- **create_points**(`positions: &[[f64; 3]]`) -> `Vec<Point>` *(bulk op)*
## Generic methods (every handle)
Every typed handle (`Solid`, `Line`, `Circle`, `Polyline`, `Point`, `Entity`) is a
`Copy`, `Send`, `Sync` token `{ ObjectId, session }` and supports:
- **`id()` -> `ObjectId`** — the stable entity identity.
- **`bounds()` -> `Aabb`** — coarse bounding box (solids lift-on-miss; 2D entities
computed; later families may be `Unsupported`).
- **`transform(placement)`** — in-place rigid similarity (same `ObjectId`). **v1:
solids only.**
- **`delete()`** — remove the entity (one undo step).
`Entity` additionally has `view()` (id + kind + bounds) and `as_solid()` (typed
downcast when `kind == "Solid3D"`).
## Collections & cross-cutting
- **`DocApi`** — root: `document(tab)`, `active_tab()`, `alive()`.
- **`Document`** — `solids()` / `curves()` / `entities()` factories + lookup,
`revision()`, `assert_revision(rev)` (read-guard), `query_batch(|q| …)` (read-only
batch, one round-trip, **no revision bump**).
- **`EntityCollection`** — `get(id) -> Entity`, `delete(id)`,
`transform_many(&ids, placement)`, `delete_many(&ids)`.
- **`OpGroup`** — best-effort client-side failure cleanup (`track` / `commit` /
`compensate`). **Not** a transaction: no atomicity, no rollback.
## Bulk ops — single op, all-or-nothing, item-capped
`CreateMany` / `TransformMany` / `DeleteMany` are **single** write ops: one undo
step, one publish, and **all-or-nothing via upfront validation** (no rollback).
Item-capped at `BULK_ITEM_CAP = 100_000` to bound host execution. Use them for
bulk data (N ≳ a few hundred); per-op autocommit is the right tool for
modeling-scale work.
## Semantics
- **Per-op autocommit, no write transactions.** Every write op is ONE atomic host
call = one undo step. Multi-op write transactions were removed (security/
integrity review).
- **Per-op atomicity.** Validate + compute geometry **before** any mutation; a
failed op applies nothing and records no undo step. `erase_sources` booleans run
only on success.
- **Structured errors.** `ApiError::{Validation, Geometry, UnknownId, Unsupported,
Transport}`; bulk validation names the failing index; a stale handle returns
`UnknownId` (never a panic).
## Kernel mapping
| op | kernel call | returns |
|---|---|---|
| CreateSolid.Cuboid | `cadkernel::brep::make::cuboid` | Option<Body> |
| CreateSolid.Sphere | `cadkernel::brep::make::sphere` | Option<Body> |
| SolidBoolean | `cadkernel::brep::combine` | Result<Body, Snag> |
| Transform | `cadkernel::brep::transform` | Option<Body> |
| GetBounds | `cadkernel::brep::body_bounds` | Option<Aabb> |
| GetVolume | `cadkernel::brep::mesh_body + divergence` | computed |