Skip to main content

axiolid_model/
node.rs

1//! Closed set of format-neutral graph node families.
2
3use axiolid_core::{Aabb, Frame2, Frame3, Point2, Point3, Scalar, Transform3, Vec2, Vec3};
4use axiolid_curve::{Curve2, Curve3};
5use axiolid_mesh::{PolygonMesh, TriMesh};
6use axiolid_primitive::{HalfSpace, Primitive};
7use axiolid_profile::Profile;
8use axiolid_surface::Surface;
9use axiolid_topology::BRep;
10
11use crate::{
12    CurveRelation, CurveStation, InstanceAtStation, NodeId, OrientedCurveStation, SolidOperation,
13    SurfaceRelation,
14};
15
16/// Point constrained to a curve parameter.
17#[derive(Debug, Clone, Copy, PartialEq)]
18#[cfg_attr(
19    feature = "serde",
20    derive(serde::Serialize, serde::Deserialize),
21    serde(deny_unknown_fields)
22)]
23pub struct PointOnCurve {
24    /// Basis curve.
25    pub curve: NodeId,
26    /// Curve parameter.
27    pub parameter: Scalar,
28}
29
30/// Point constrained to surface parameters.
31#[derive(Debug, Clone, Copy, PartialEq)]
32#[cfg_attr(
33    feature = "serde",
34    derive(serde::Serialize, serde::Deserialize),
35    serde(deny_unknown_fields)
36)]
37pub struct PointOnSurface {
38    /// Basis surface.
39    pub surface: NodeId,
40    /// First parameter.
41    pub u: Scalar,
42    /// Second parameter.
43    pub v: Scalar,
44}
45
46/// Source-authored bounded open two-dimensional profile path.
47///
48/// This declaration preserves exact curve intent while carrying no area, width,
49/// closure edge, or evaluation instruction. Graph construction conservatively
50/// admits only known bounded-open forms, including finite source-open
51/// polylines, structurally valid finite B-splines, finite 2D trims with no
52/// exactly equal authored endpoints, and recursively valid relation chains.
53/// Endpoint inequality across arbitrary relations still requires geometric
54/// evaluation.
55#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
56#[cfg_attr(
57    feature = "serde",
58    derive(serde::Serialize, serde::Deserialize),
59    serde(deny_unknown_fields)
60)]
61pub struct OpenProfile {
62    /// Exact two-dimensional curve or curve relation authored as the path.
63    pub path: NodeId,
64}
65
66impl OpenProfile {
67    /// Declare `path` as a bounded open profile without implying area or width.
68    pub const fn new(path: NodeId) -> Self {
69        Self { path }
70    }
71}
72
73/// Reuse one graph node under a transform, preserving instancing.
74#[derive(Debug, Clone, Copy, PartialEq)]
75#[cfg_attr(
76    feature = "serde",
77    derive(serde::Serialize, serde::Deserialize),
78    serde(deny_unknown_fields)
79)]
80pub struct Instance {
81    /// Reused source node.
82    pub source: NodeId,
83    /// Local-to-parent transform.
84    pub transform: Transform3,
85}
86
87/// One node in an immutable geometry DAG.
88///
89/// The enum is non-exhaustive so representation growth is semver-compatible.
90/// Compilers must turn unknown/unsupported families into a structured
91/// `Unsupported` result rather than a wildcard no-op.
92#[non_exhaustive]
93#[derive(Debug, Clone, PartialEq)]
94#[cfg_attr(
95    feature = "serde",
96    derive(serde::Serialize, serde::Deserialize),
97    serde(deny_unknown_fields)
98)]
99pub enum GeometryNode {
100    /// Two-dimensional position.
101    Point2(Point2),
102    /// Three-dimensional position.
103    Point3(Point3),
104    /// Two-dimensional direction/vector.
105    Vector2(Vec2),
106    /// Three-dimensional direction/vector.
107    Vector3(Vec3),
108    /// Two-dimensional axis placement.
109    Frame2(Frame2),
110    /// Three-dimensional axis placement.
111    Frame3(Frame3),
112    /// Composed affine transform.
113    Transform(Transform3),
114    /// Dense two-dimensional point list.
115    PointList2(Vec<Point2>),
116    /// Dense three-dimensional point list.
117    PointList3(Vec<Point3>),
118    /// Atomic two-dimensional curve.
119    Curve2(Curve2),
120    /// Atomic three-dimensional curve.
121    Curve3(Curve3),
122    /// Curve composition/constraint.
123    CurveRelation(CurveRelation),
124    /// Point on a curve.
125    PointOnCurve(PointOnCurve),
126    /// Atomic surface.
127    Surface(Surface),
128    /// Surface composition/constraint.
129    SurfaceRelation(SurfaceRelation),
130    /// Point on a surface.
131    PointOnSurface(PointOnSurface),
132    /// Exact section profile with area semantics.
133    Profile(Profile),
134    /// Authored exact open profile path without area or width semantics.
135    OpenProfile(OpenProfile),
136    /// Exact primitive solid.
137    Primitive(Primitive),
138    /// Unbounded half-space.
139    HalfSpace(HalfSpace),
140    /// Solid construction instruction.
141    SolidOperation(SolidOperation),
142    /// Exact topological representation linked to graph curve/surface nodes.
143    BRep(BRep<NodeId>),
144    /// Polygonal n-gon mesh before triangulation.
145    PolygonMesh(PolygonMesh),
146    /// Triangle mesh.
147    TriMesh(TriMesh),
148    /// Axis-aligned bounds.
149    BoundingBox(Aabb),
150    /// Instanced/mapped geometry.
151    Instance(Instance),
152    /// Ordered geometric set or representation.
153    Collection(Vec<NodeId>),
154    /// A point and frame at a distance along a basis curve, offset in its
155    /// section frame (#241). See [`crate::station`].
156    CurveStation(CurveStation),
157    /// A curve station with an explicit in-section orientation (#246). See
158    /// [`crate::station`].
159    OrientedCurveStation(OrientedCurveStation),
160    /// A node reused in the frame of an oriented curve station (#264): a
161    /// curve, solid or surface placed along a basis curve. See
162    /// [`crate::station`].
163    InstanceAtStation(InstanceAtStation),
164}
165
166impl GeometryNode {
167    /// Direct graph dependencies in deterministic order.
168    pub fn references(&self) -> Vec<NodeId> {
169        let mut references = Vec::new();
170        match self {
171            Self::CurveRelation(value) => value.references(&mut references),
172            Self::PointOnCurve(value) => references.push(value.curve),
173            Self::SurfaceRelation(value) => value.references(&mut references),
174            Self::PointOnSurface(value) => references.push(value.surface),
175            Self::OpenProfile(value) => references.push(value.path),
176            Self::SolidOperation(value) => value.references(&mut references),
177            Self::BRep(value) => {
178                references.extend(value.edges().iter().filter_map(|edge| edge.curve));
179                // Pcurves are graph references too: omitting them here would
180                // let a referenced trim curve be pruned as unreachable.
181                references.extend(
182                    value
183                        .loops()
184                        .iter()
185                        .flat_map(|wire| wire.edges.iter())
186                        .filter_map(|use_| use_.pcurve),
187                );
188                references.extend(value.faces().iter().filter_map(|face| face.surface));
189            }
190            Self::Instance(value) => references.push(value.source),
191            Self::Collection(values) => references.extend(values.iter().copied()),
192            Self::CurveStation(value) => references.push(value.basis),
193            Self::OrientedCurveStation(value) => references.push(value.station.basis),
194            Self::InstanceAtStation(value) => {
195                references.extend([value.source, value.station.station.basis]);
196            }
197            Self::Point2(_)
198            | Self::Point3(_)
199            | Self::Vector2(_)
200            | Self::Vector3(_)
201            | Self::Frame2(_)
202            | Self::Frame3(_)
203            | Self::Transform(_)
204            | Self::PointList2(_)
205            | Self::PointList3(_)
206            | Self::Curve2(_)
207            | Self::Curve3(_)
208            | Self::Surface(_)
209            | Self::Profile(_)
210            | Self::Primitive(_)
211            | Self::HalfSpace(_)
212            | Self::PolygonMesh(_)
213            | Self::TriMesh(_)
214            | Self::BoundingBox(_) => {}
215        }
216        references
217    }
218}