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