ocs_doc_api: Phase 2c-ii — dimension sub-types (radius/diameter/angular)

- CreateDimensionRadius/CreateDimensionDiameter (DimensionRadialSpec) +
  CreateDimensionAngular (DimensionAngularSpec) ops (append-only).
- backend add_dimension_radius/diameter (DimensionRadius/DimensionDiameter::new)
  + add_dimension_angular (DimensionAngular3Pt::new computes angle);
  dimension_measurement returns degrees for angular sub-types.
- facade create_dimension_radius/diameter/angular; spec constructors; api_reference
  + binding_schema regenerated; mocks + baseline.
- Test phase2cii_dimension_radius_diameter_angular -> 613 host lib + 3 consistency green.
This commit is contained in:
Sebastian committed 2026-09-06 12:31:23 +02:00
1 parent 2522979285
commit 8d8c120880
12 files changed
+205 -3

No files matched your search

+9
View File
@@ -63,6 +63,15 @@ pub trait DocApiBackend {
/// Add a linear `DIMENSION`; returns the fresh `ObjectId`.
fn add_dimension_linear(&mut self, spec: &crate::ops::DimensionSpec) -> ApiResult<ObjectId>;
/// Add a radial `DIMENSION`; returns the fresh `ObjectId`.
fn add_dimension_radius(&mut self, spec: &crate::ops::DimensionRadialSpec) -> ApiResult<ObjectId>;
/// Add a diameter `DIMENSION`; returns the fresh `ObjectId`.
fn add_dimension_diameter(&mut self, spec: &crate::ops::DimensionRadialSpec) -> ApiResult<ObjectId>;
/// Add a 3-point angular `DIMENSION`; returns the fresh `ObjectId`.
fn add_dimension_angular(&mut self, spec: &crate::ops::DimensionAngularSpec) -> ApiResult<ObjectId>;
/// A dimension's measured value (distance for linear/radius, degrees for angular).
fn dimension_measurement(&self, id: ObjectId) -> ApiResult<f64>;
+18
View File
@@ -269,6 +269,24 @@ pub fn apply_op<B: DocApiBackend>(b: &mut B, op: Operation) -> ApiResult<Receipt
b.finalize_op();
OpOutcome::NewId(id)
}
Operation::CreateDimensionRadius(spec) => {
b.push_undo(name);
let id = b.add_dimension_radius(spec)?;
b.finalize_op();
OpOutcome::NewId(id)
}
Operation::CreateDimensionDiameter(spec) => {
b.push_undo(name);
let id = b.add_dimension_diameter(spec)?;
b.finalize_op();
OpOutcome::NewId(id)
}
Operation::CreateDimensionAngular(spec) => {
b.push_undo(name);
let id = b.add_dimension_angular(spec)?;
b.finalize_op();
OpOutcome::NewId(id)
}
};
Ok(Receipt {
outcome: Some(outcome),
+26
View File
@@ -539,6 +539,32 @@ impl CurveCollection {
Ok(Entity::new(self.session.clone(), id))
}
/// A radial DIMENSION for the circle centered at `center` through `point`.
pub fn create_dimension_radius(&self, center: [f64; 3], point: [f64; 3]) -> ApiResult<Dimension> {
self.create_dim_radial(Operation::CreateDimensionRadius, center, point)
}
/// A diameter DIMENSION for the circle with chord points `center`/`point`.
pub fn create_dimension_diameter(&self, center: [f64; 3], point: [f64; 3]) -> ApiResult<Dimension> {
self.create_dim_radial(Operation::CreateDimensionDiameter, center, point)
}
fn create_dim_radial(
&self,
op: impl Fn(crate::ops::DimensionRadialSpec) -> Operation,
center: [f64; 3],
point: [f64; 3],
) -> ApiResult<Dimension> {
let receipt = self.session.apply_op(op(crate::ops::DimensionRadialSpec { center, point }))?;
let id = receipt.outcome.and_then(|o| o.new_id()).ok_or_else(|| ApiError::Transport("create_dimension returned no id".into()))?;
Ok(Dimension::new(self.session.clone(), id))
}
/// A 3-point angular DIMENSION (vertex + one point on each leg).
pub fn create_dimension_angular(&self, vertex: [f64; 3], first_point: [f64; 3], second_point: [f64; 3], arc_location: [f64; 3]) -> ApiResult<Dimension> {
let receipt = self.session.apply_op(Operation::CreateDimensionAngular(crate::ops::DimensionAngularSpec {
vertex, first_point, second_point, arc_location,
}))?;
let id = receipt.outcome.and_then(|o| o.new_id()).ok_or_else(|| ApiError::Transport("create_dimension returned no id".into()))?;
Ok(Dimension::new(self.session.clone(), id))
}
/// A linear DIMENSION between `first_point` and `second_point`, with the
/// dimension line placed at `definition_point`. `measurement()` reads the value.
pub fn create_dimension_linear(&self, first_point: [f64; 3], second_point: [f64; 3], definition_point: [f64; 3]) -> ApiResult<Dimension> {
@@ -133,6 +133,9 @@ Linear dimension between two measured points. measurement() reads the distance;
### Constructors (`doc.curves()`)
- **create_dimension_linear**(first_point: [f64; 3], second_point: [f64; 3], definition_point: [f64; 3]) -> `Dimension` — `CreateDimensionLinear`
- **create_dimension_radius**(center: [f64; 3], point: [f64; 3]) -> `Dimension` — `CreateDimensionRadius`
- **create_dimension_diameter**(center: [f64; 3], point: [f64; 3]) -> `Dimension` — `CreateDimensionDiameter`
- **create_dimension_angular**(vertex: [f64; 3], first_point: [f64; 3], second_point: [f64; 3], arc_location: [f64; 3]) -> `Dimension` — `CreateDimensionAngular`
### Methods
+5 -1
View File
@@ -7,7 +7,7 @@
use serde::{Deserialize, Serialize};
use crate::id::ObjectId;
use crate::ops::{BoolOp, Curve2Spec, DimensionSpec, EntitySpec, HatchSpec, InsertSpec, MTextSpec, PlacementSpec, RasterImageSpec, SolidPrimitive, TextSpec, ViewportSpec};
use crate::ops::{BoolOp, Curve2Spec, DimensionAngularSpec, DimensionRadialSpec, DimensionSpec, EntitySpec, HatchSpec, InsertSpec, MTextSpec, PlacementSpec, RasterImageSpec, SolidPrimitive, TextSpec, ViewportSpec};
/// A typed write operation (plan §5). Each variant is ONE atomic host call = one
/// undo step. Append new variants at the END only.
@@ -48,4 +48,8 @@ pub enum Operation {
CreateRasterImage(RasterImageSpec),
// multi-profile solid
Loft { profiles: Vec<ObjectId> },
// dimension sub-types
CreateDimensionRadius(DimensionRadialSpec),
CreateDimensionDiameter(DimensionRadialSpec),
CreateDimensionAngular(DimensionAngularSpec),
}
+23
View File
@@ -116,6 +116,26 @@ pub struct DimensionSpec {
pub definition_point: [f64; 3],
}
/// Construction spec for a radial/diameter `DIMENSION`: the circle center and a
/// point on the circle (radius) or a chord point (diameter).
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct DimensionRadialSpec {
/// Center of the arc/circle (radius) or first chord point (diameter).
pub center: [f64; 3],
/// A point on the arc/circle (radius) or the far chord point (diameter).
pub point: [f64; 3],
}
/// Construction spec for a 3-point angular `DIMENSION`: vertex + one point on
/// each leg, plus the dimension-arc location.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct DimensionAngularSpec {
pub vertex: [f64; 3],
pub first_point: [f64; 3],
pub second_point: [f64; 3],
pub arc_location: [f64; 3],
}
/// Construction spec for a `RASTER_IMAGE`: an image file placed at
/// `insertion_point` with per-pixel world-unit vectors `u_vector`/`v_vector` and
/// pixel `size` (width, height). The host auto-registers the ImageDefinition.
@@ -187,6 +207,9 @@ impl crate::gen::Operation {
SetViewportView { .. } => "SetViewportView",
CreateRasterImage(_) => "CreateRasterImage",
Loft { .. } => "Loft",
CreateDimensionRadius(_) => "CreateDimensionRadius",
CreateDimensionDiameter(_) => "CreateDimensionDiameter",
CreateDimensionAngular(_) => "CreateDimensionAngular",
}
}
}