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