ocs_doc_api: Phase 4 set_view + viewport-view query

- SetViewportView op + GetViewportView query (append-only).
- backend set_viewport_view (update Viewport.view_target/view_height) + viewport_view.
- facade Entity::set_view/viewport_view (Viewport returns Entity).
- spec Viewport methods; api_reference + binding_schema regenerated; mocks + baseline.
- Test phase4_set_view_and_view_query -> 609 host lib + 3 consistency green.
- Phase 4 complete.
This commit is contained in:
Sebastian committed 2026-09-06 10:16:27 +02:00
1 parent 67655add72
commit e6c132e0eb
15 files changed
+187 -7

No files matched your search

+6
View File
@@ -75,6 +75,12 @@ pub trait DocApiBackend {
/// The entities inside a block definition (read-only traversal), as views.
fn block_entities(&self, block_name: &str) -> ApiResult<Vec<EntityView>>;
/// Set a viewport's view target + zoom height in place. Viewport-only.
fn set_viewport_view(&mut self, id: ObjectId, view_target: [f64; 3], view_height: f64) -> ApiResult<()>;
/// A viewport's view (target WCS + zoom height). Viewport-only.
fn viewport_view(&self, id: ObjectId) -> ApiResult<([f64; 3], f64)>;
/// Can `id` be modified in place right now (exists, is the expected family,
/// not on a locked layer)? Read-only pre-check used before mutations.
/// Default: existence + not-locked (backends narrow the family check).
+14
View File
@@ -237,6 +237,16 @@ pub fn apply_op<B: DocApiBackend>(b: &mut B, op: Operation) -> ApiResult<Receipt
b.finalize_op();
OpOutcome::Updated(*id)
}
Operation::SetViewportView { id, view_target, view_height } => {
b.can_modify(*id).map_err(|e| match e {
ApiError::UnknownId(_) => ApiError::validation(name, format!("unknown ObjectId {id:?}")),
other => other,
})?;
b.push_undo(name);
b.set_viewport_view(*id, *view_target, *view_height)?;
b.finalize_op();
OpOutcome::Updated(*id)
}
};
Ok(Receipt {
outcome: Some(outcome),
@@ -279,6 +289,10 @@ pub fn apply_queries<B: DocApiBackend>(b: &mut B, queries: Vec<Query>) -> ApiRes
Query::GetDimensionMeasurement { id } => QueryResult::DimensionMeasurement(b.dimension_measurement(*id)?),
Query::GetAttributes { id } => QueryResult::Attributes(b.attributes(*id)?),
Query::GetBlockEntities { block_name } => QueryResult::BlockEntities(b.block_entities(block_name)?),
Query::GetViewportView { id } => {
let (target, height) = b.viewport_view(*id)?;
QueryResult::ViewportView { target, height }
}
};
results.push(r);
}
+12
View File
@@ -309,6 +309,18 @@ impl Entity {
self.session.apply_op(Operation::SetAttribute { id: self.id, tag: tag.to_string(), value: value.to_string() })?;
Ok(())
}
/// This viewport's view (target WCS + zoom height). Viewport-only.
pub fn viewport_view(&self) -> ApiResult<([f64; 3], f64)> {
match self.session.one_query(Query::GetViewportView { id: self.id })? {
QueryResult::ViewportView { target, height } => Ok((target, height)),
_ => Err(ApiError::Transport("unexpected viewport-view result".into())),
}
}
/// Retarget / re-zoom this viewport (one undo step). Viewport-only.
pub fn set_view(&self, view_target: [f64; 3], view_height: f64) -> ApiResult<()> {
self.session.apply_op(Operation::SetViewportView { id: self.id, view_target, view_height })?;
Ok(())
}
pub fn as_solid(&self) -> Option<Solid> {
// Typed downcast is validated by the view's kind.
matches!(self.view().ok()?.kind.as_str(), "Solid3D").then(|| Solid::new(self.session.clone(), self.id))
@@ -158,6 +158,11 @@ Paper-space viewport: a width×height window at center looking at view_target wi
- **create_viewport**(`center: [f64; 3], width: f64, height: f64, view_target: [f64; 3], view_height: f64`) -> `Entity`
### Methods
- **viewport_view**(``) -> `([f64; 3], f64)` — query `GetViewportView`
- **set_view**(`view_target: [f64; 3], view_height: f64`) -> `()` — op `SetViewportView`
## `Entity` (acadrust `RasterImage`, collection `entities`)
Raster image (read-mostly): GetEntity kind + coarse bounds (insertion + u*width + v*height); generic delete. No typed create in v1.
+33 -1
View File
@@ -339,7 +339,39 @@
"acadrust_variant": "Viewport",
"collection": "entities",
"handle": "Entity",
"methods": [],
"methods": [
{
"args": [],
"bulk": false,
"fixed": null,
"kind": "query",
"name": "viewport_view",
"op": null,
"query": "GetViewportView",
"read_only": true,
"returns": "([f64; 3], f64)"
},
{
"args": [
{
"name": "view_target",
"ty": "[f64; 3]"
},
{
"name": "view_height",
"ty": "f64"
}
],
"bulk": false,
"fixed": null,
"kind": "op",
"name": "set_view",
"op": "SetViewportView",
"query": null,
"read_only": false,
"returns": "()"
}
],
"name": "Viewport"
},
{
+2
View File
@@ -42,4 +42,6 @@ pub enum Operation {
CreateDimensionLinear(DimensionSpec),
// attributes
SetAttribute { id: ObjectId, tag: String, value: String },
// viewport view
SetViewportView { id: ObjectId, view_target: [f64; 3], view_height: f64 },
}
+2
View File
@@ -30,4 +30,6 @@ pub enum Query {
GetAttributes { id: ObjectId },
/// The entity ids + kinds inside a block definition (read-only traversal).
GetBlockEntities { block_name: String },
/// A viewport's view (target + zoom height).
GetViewportView { id: ObjectId },
}
+1
View File
@@ -170,6 +170,7 @@ impl crate::gen::Operation {
CreateHatch(_) => "CreateHatch",
CreateDimensionLinear(_) => "CreateDimensionLinear",
SetAttribute { .. } => "SetAttribute",
SetViewportView { .. } => "SetViewportView",
}
}
}
+3
View File
@@ -53,6 +53,8 @@ pub enum QueryResult {
Attributes(Vec<(String, String)>),
/// The entities inside a block definition (read-only traversal).
BlockEntities(Vec<EntityView>),
/// A viewport's view: target point (WCS) + zoom height.
ViewportView { target: [f64; 3], height: f64 },
}
/// Convenience: the query name for diagnostics.
@@ -71,6 +73,7 @@ impl crate::gen::Query {
GetDimensionMeasurement { .. } => "GetDimensionMeasurement",
GetAttributes { .. } => "GetAttributes",
GetBlockEntities { .. } => "GetBlockEntities",
GetViewportView { .. } => "GetViewportView",
}
}
}