Files
OneCAD-Draft/crates/ocs_doc_api/src/ops.rs
T

490 lines
16 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! Write operations — the typed, transport-agnostic vocabulary for changing the
//! document. The `Operation` enum is **hand-maintained** (append-only)
//! in `src/gen/ops_gen.rs` — it is NOT derived from the spec by build.rs; the
//! spec's `op` names must each map to a variant here (asserted by a test). This
//! module re-exports it and holds the hand-written payload mirrors.
use serde::{Deserialize, Serialize};
pub use crate::gen::Operation;
/// An XDATA record payload: one registered application name plus its typed
/// value list. This is a plain-data, serde-compatible mirror of
/// `acadrust::xdata::ExtendedDataRecord` so the wire DTO stays independent of
/// the host dependency.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct XDataRecord {
pub application_name: String,
pub values: Vec<XDataValue>,
}
/// A single XDATA value. Mirrors `acadrust::xdata::XDataValue`.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum XDataValue {
String(String),
ControlString(String),
LayerName(String),
BinaryData(Vec<u8>),
Handle(u64),
Point3D([f64; 3]),
Position3D([f64; 3]),
Displacement3D([f64; 3]),
Direction3D([f64; 3]),
Real(f64),
Distance(f64),
ScaleFactor(f64),
Integer16(i16),
Integer32(i32),
}
/// Construction spec for an `XRECORD` object. Mirrors the acadrust
/// `XRecord` payload (name + cloning flags + group-code entries) in a
/// serde-compatible, host-independent form.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct XRecordSpec {
pub name: String,
pub cloning_flags: XRecordCloningFlags,
pub entries: Vec<XRecordEntry>,
}
/// XRecord cloning behavior flags. Mirror of
/// `acadrust::objects::DictionaryCloningFlags`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
pub enum XRecordCloningFlags {
#[default]
NotApplicable,
KeepExisting,
UseClone,
XrefName,
Name,
UnmangleName,
}
/// One XRECORD group-code entry.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct XRecordEntry {
pub code: i32,
pub value: XRecordValue,
}
/// A single XRECORD value. Mirrors `acadrust::objects::XRecordValue`.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum XRecordValue {
String(String),
Double(f64),
Int16(i16),
Int32(i32),
Int64(i64),
Byte(u8),
Bool(bool),
Handle(u64),
Point3D([f64; 3]),
Chunk(Vec<u8>),
}
/// Boolean operation kind for [`Operation::SolidBoolean`].
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum BoolOp {
Union,
Intersection,
Difference,
}
/// A plain-data color value. Mirrors `acadrust::types::Color` for wire
/// independence from the host dependency.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum Color {
ByLayer,
None,
ByBlock,
Index(u8),
Rgb { r: u8, g: u8, b: u8 },
}
impl Color {
pub const WHITE: Color = Color::Index(7);
}
/// A plain-data line weight. Mirrors `acadrust::types::LineWeight`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
pub enum LineWeight {
#[default]
ByLayer,
ByBlock,
Default,
/// Specific line weight in 1/100 mm.
Value(i16),
}
/// Layer visibility/lock flags.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
pub struct LayerFlags {
pub frozen: bool,
pub locked: bool,
pub frozen_in_new_viewport: bool,
pub off: bool,
}
/// A plain-data layer table entry. Mirrors `acadrust::tables::Layer`.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct LayerInfo {
pub name: String,
pub flags: LayerFlags,
pub color: Color,
pub line_type: String,
pub line_weight: LineWeight,
pub plot_style: String,
pub is_plottable: bool,
}
impl LayerInfo {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
flags: LayerFlags::default(),
color: Color::WHITE,
line_type: "Continuous".to_string(),
line_weight: LineWeight::Default,
plot_style: String::new(),
is_plottable: true,
}
}
/// The normalized (trimmed + uppercased) lookup key for this layer name.
pub fn normalized_name(&self) -> String {
crate::layer::normalize_layer_name(&self.name)
}
}
/// Construction spec for a B-rep solid primitive (plain-data mirror of the
/// non-serde `cadkernel::brep::make::*` arguments).
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub enum SolidPrimitive {
Cuboid {
origin: [f64; 3],
size: [f64; 3],
},
Sphere {
centre: [f64; 3],
radius: f64,
},
Cylinder {
base: [f64; 3],
radius: f64,
height: f64,
},
Cone {
base: [f64; 3],
radius: f64,
height: f64,
},
Torus {
centre: [f64; 3],
major_radius: f64,
minor_radius: f64,
},
Wedge {
origin: [f64; 3],
size: [f64; 3],
},
}
/// Construction spec for a minimal 2D curve entity (phase-1 set; profiles/inputs).
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Curve2Spec {
Line {
start: [f64; 3],
end: [f64; 3],
/// Target layer name. `None` places the entity on the current layer.
layer: Option<String>,
},
Circle {
centre: [f64; 3],
radius: f64,
/// Target layer name. `None` places the entity on the current layer.
layer: Option<String>,
},
Polyline {
points: Vec<[f64; 3]>,
closed: bool,
/// Target layer name. `None` places the entity on the current layer.
layer: Option<String>,
},
Point {
position: [f64; 3],
/// Target layer name. `None` places the entity on the current layer.
layer: Option<String>,
},
/// Circular arc, counter-clockwise from `start_angle` to `end_angle` (radians).
Arc {
centre: [f64; 3],
radius: f64,
start_angle: f64,
end_angle: f64,
/// Target layer name. `None` places the entity on the current layer.
layer: Option<String>,
},
/// Ellipse: `major_axis` is the major-axis endpoint relative to `centre`;
/// `ratio` = minor/major. `start`/`end` parameters 0..2π (full ellipse = 0..2π).
Ellipse {
centre: [f64; 3],
major_axis: [f64; 3],
ratio: f64,
start: f64,
end: f64,
/// Target layer name. `None` places the entity on the current layer.
layer: Option<String>,
},
/// NURBS spline (control points + knots + weights; `degree` typically 3).
Spline {
degree: i32,
control_points: Vec<[f64; 3]>,
knots: Vec<f64>,
weights: Vec<f64>,
/// Target layer name. `None` places the entity on the current layer.
layer: Option<String>,
},
/// A ray from `origin` along `direction` (bounded at origin only).
Ray {
origin: [f64; 3],
direction: [f64; 3],
/// Target layer name. `None` places the entity on the current layer.
layer: Option<String>,
},
/// An infinite construction line through `origin` along `direction`.
XLine {
origin: [f64; 3],
direction: [f64; 3],
/// Target layer name. `None` places the entity on the current layer.
layer: Option<String>,
},
}
impl Curve2Spec {
/// The target layer name, if any.
pub fn layer(&self) -> Option<&str> {
match self {
Curve2Spec::Line { layer, .. }
| Curve2Spec::Circle { layer, .. }
| Curve2Spec::Polyline { layer, .. }
| Curve2Spec::Point { layer, .. }
| Curve2Spec::Arc { layer, .. }
| Curve2Spec::Ellipse { layer, .. }
| Curve2Spec::Spline { layer, .. }
| Curve2Spec::Ray { layer, .. }
| Curve2Spec::XLine { layer, .. } => layer.as_deref(),
}
}
}
/// A generic entity-construction payload used by the bulk op
/// [`crate::ops::Operation::CreateMany`]. Mirrors the per-family construction
/// specs so one bulk op can carry many homogeneous (or mixed) creations.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum EntitySpec {
Curve(Curve2Spec),
Solid(SolidPrimitive),
}
impl EntitySpec {
/// The target layer name for this spec, if explicitly set.
pub fn layer(&self) -> Option<&str> {
match self {
EntitySpec::Curve(c) => c.layer(),
EntitySpec::Solid(_) => None,
}
}
}
/// Construction spec for a block reference (`INSERT`): place the block
/// `block_name` (must exist as a BlockRecord) at `insert_point` with uniform
/// `scale` and `rotation` (radians, about Z).
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct InsertSpec {
pub block_name: String,
pub insert_point: [f64; 3],
pub scale: f64,
pub rotation: f64,
}
/// Construction spec for a paper-space `VIEWPORT`: a `width`×`height` viewport
/// centered at `center` (paper space), looking at `view_target` (model space,
/// WCS) with `view_height` (model-space height visible; the viewport's zoom).
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ViewportSpec {
pub center: [f64; 3],
pub width: f64,
pub height: f64,
pub view_target: [f64; 3],
pub view_height: f64,
}
/// Construction spec for a single-line `TEXT` annotation.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct TextSpec {
pub value: String,
pub insertion_point: [f64; 3],
pub height: f64,
pub rotation: f64,
}
/// Construction spec for a multi-line `MTEXT` annotation.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct MTextSpec {
pub value: String,
pub insertion_point: [f64; 3],
pub height: f64,
}
/// Construction spec for a `HATCH` with a single closed polyline boundary
/// (straight segments). `solid` selects solid fill vs a pattern (pattern naming
/// is a later refinement).
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct HatchSpec {
/// Closed boundary as an ordered polyline (first==last implied; closed).
pub boundary: Vec<[f64; 2]>,
pub solid: bool,
}
/// Construction spec for a linear `DIMENSION`: the two measured points and the
/// dimension-line definition point.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct DimensionSpec {
pub first_point: [f64; 3],
pub second_point: [f64; 3],
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 an `ATTDEF` (attribute definition): the tag, prompt,
/// and default value for an in-block attribute, at an insertion point.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct AttributeDefinitionSpec {
pub tag: String,
pub prompt: String,
pub default_value: String,
pub insertion_point: [f64; 3],
pub height: f64,
pub rotation: f64,
}
/// Construction spec for a `TABLE`: an insertion point plus a grid of cell
/// strings (`data[row][column]`).
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct TableSpec {
pub insertion_point: [f64; 3],
/// Grid of cell text values, rows × columns.
pub data: Vec<Vec<String>>,
}
/// 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.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RasterImageSpec {
pub file_path: String,
pub insertion_point: [f64; 3],
pub u_vector: [f64; 3],
pub v_vector: [f64; 3],
/// Pixel size (width, height).
pub size: [f64; 2],
}
/// A rigid similarity (rotation + translation + optional uniform scale/reflection)
/// as a plain-data mirror of `cadkernel::brep::transform`'s `Placement`
/// (non-serde). Columns are the new basis axes; `origin` is the translation.
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub struct PlacementSpec {
pub x_axis: [f64; 3],
pub y_axis: [f64; 3],
pub z_axis: [f64; 3],
pub origin: [f64; 3],
}
impl PlacementSpec {
/// Identity placement (no transform).
pub const IDENTITY: PlacementSpec = PlacementSpec {
x_axis: [1.0, 0.0, 0.0],
y_axis: [0.0, 1.0, 0.0],
z_axis: [0.0, 0.0, 1.0],
origin: [0.0, 0.0, 0.0],
};
/// Pure translation to `origin` (axes unchanged).
pub fn at(origin: [f64; 3]) -> Self {
Self {
origin,
..Self::IDENTITY
}
}
}
/// The item-count cap for a single bulk op envelope: bounds
/// host-side execution time and payload. Over-cap → `ApiError::Validation`.
pub const BULK_ITEM_CAP: usize = 100_000;
/// Convenience accessors used by the facade/executor.
impl crate::gen::Operation {
/// The op name used in `ApiError::Validation { op, .. }`.
pub fn op_name(&self) -> &'static str {
use crate::gen::Operation::*;
match self {
CreateSolid(_) => "CreateSolid",
CreateCurve(_) => "CreateCurve",
Extrude { .. } => "Extrude",
Revolve { .. } => "Revolve",
Transform { .. } => "Transform",
SolidBoolean { .. } => "SolidBoolean",
AddVertex { .. } => "AddVertex",
Delete { .. } => "Delete",
CreateMany(_) => "CreateMany",
TransformMany { .. } => "TransformMany",
DeleteMany(_) => "DeleteMany",
CreateInsert(_) => "CreateInsert",
CreateViewport(_) => "CreateViewport",
CreateText(_) => "CreateText",
CreateMText(_) => "CreateMText",
SetTextContent { .. } => "SetTextContent",
CreateHatch(_) => "CreateHatch",
CreateDimensionLinear(_) => "CreateDimensionLinear",
SetAttribute { .. } => "SetAttribute",
SetViewportView { .. } => "SetViewportView",
CreateRasterImage(_) => "CreateRasterImage",
Loft { .. } => "Loft",
CreateDimensionRadius(_) => "CreateDimensionRadius",
CreateDimensionDiameter(_) => "CreateDimensionDiameter",
CreateDimensionAngular(_) => "CreateDimensionAngular",
CreateAttributeDefinition(_) => "CreateAttributeDefinition",
CreateTable(_) => "CreateTable",
CreateDimensionAngular2Ln(_) => "CreateDimensionAngular2Ln",
SetXData { .. } => "SetXData",
SetXDataMany(_) => "SetXDataMany",
CreateXRecord(_) => "CreateXRecord",
SetXRecord { .. } => "SetXRecord",
CreateLayer(_) => "CreateLayer",
UpdateLayer { .. } => "UpdateLayer",
DeleteLayer { .. } => "DeleteLayer",
SetEntityLayer { .. } => "SetEntityLayer",
}
}
}