1use ogeom_geom::{Curve, Curve3d as _, PlanarCurve};
5use ogeom_math::{KnotVector, Transform};
6
7use crate::{EdgeRepr, Model, Shape, TShapeId};
8
9#[must_use]
26pub fn face_content(model: &Model, face: &Shape) -> Option<Vec<u8>> {
27 let mut out = Vec::new();
28 let data = model.node(face)?.data().as_face()?;
29 let geometry = model.geometry();
30 let datums = model.datums();
31 text(&mut out, format_args!("F{:?}", face.orientation()));
32 placement(&mut out, face.transform(datums).ok()?);
33 text(
34 &mut out,
35 format_args!(
36 "{:?}{}{:?}",
37 data.tolerance,
38 data.natural_restriction,
39 geometry.surface(data.surface)?
40 ),
41 );
42 let mut met: Vec<TShapeId> = Vec::new();
43 let wires = model.ordered_children_of(face).ok()?;
44 count(&mut out, wires.len());
45 for wire in wires {
46 text(&mut out, format_args!("W{:?}", wire.orientation()));
47 placement(&mut out, wire.transform(datums).ok()?);
48 let edges = model.ordered_children_of(&wire).ok()?;
49 count(&mut out, edges.len());
50 for edge in edges {
51 let at = met
52 .iter()
53 .position(|&e| e == edge.node())
54 .unwrap_or_else(|| {
55 met.push(edge.node());
56 met.len() - 1
57 });
58 let e = model.node(&edge)?.data().as_edge()?;
59 text(&mut out, format_args!("E{at}{:?}", edge.orientation()));
60 placement(&mut out, edge.transform(datums).ok()?);
61 text(
62 &mut out,
63 format_args!(
64 "{:?}{}{}{}",
65 e.tolerance,
66 e.degenerate,
67 e.same_parameter(),
68 e.representations.len()
69 ),
70 );
71 for repr in &e.representations {
72 match repr {
73 EdgeRepr::Curve3d {
74 curve,
75 location,
76 range,
77 } => {
78 out.push(b'C');
79 space_curve(&mut out, geometry.curve(*curve)?);
80 placement(&mut out, location.composed(datums).ok()?);
81 bits(&mut out, &[range.0, range.1]);
82 }
83 EdgeRepr::PCurve {
84 curve,
85 surface,
86 location,
87 range,
88 } => {
89 out.push(b'P');
90 planar_curve(&mut out, geometry.pcurve(*curve)?);
91 out.push(u8::from(*surface == data.surface));
92 placement(&mut out, location.composed(datums).ok()?);
93 bits(&mut out, &[range.0, range.1]);
94 }
95 EdgeRepr::Seam {
96 forward,
97 reversed,
98 surface,
99 location,
100 range,
101 } => {
102 out.push(b'S');
103 planar_curve(&mut out, geometry.pcurve(*forward)?);
104 planar_curve(&mut out, geometry.pcurve(*reversed)?);
105 out.push(u8::from(*surface == data.surface));
106 placement(&mut out, location.composed(datums).ok()?);
107 bits(&mut out, &[range.0, range.1]);
108 }
109 EdgeRepr::PolygonOnTriangulation { .. } => return None,
110 other => {
111 out.push(b'R');
112 text(&mut out, format_args!("{other:?}"));
113 }
114 }
115 }
116 let vertices = model.ordered_children_of(&edge).ok()?;
117 count(&mut out, vertices.len());
118 for vertex in vertices {
119 let v = model.node(&vertex)?.data().as_vertex()?;
120 text(&mut out, format_args!("V{:?}", vertex.orientation()));
121 placement(&mut out, vertex.transform(datums).ok()?);
122 bits(&mut out, &[v.point.x, v.point.y, v.point.z]);
123 text(&mut out, format_args!("{:?}", v.tolerance));
124 }
125 }
126 }
127 Some(out)
128}
129
130fn count(out: &mut Vec<u8>, n: usize) {
132 out.extend_from_slice(&(n as u64).to_le_bytes());
133}
134
135fn text(out: &mut Vec<u8>, args: std::fmt::Arguments<'_>) {
137 let written = args.to_string();
138 count(out, written.len());
139 out.extend_from_slice(written.as_bytes());
140}
141
142fn bits(out: &mut Vec<u8>, values: &[f64]) {
144 for x in values {
145 out.extend_from_slice(&x.to_bits().to_le_bytes());
146 }
147}
148
149fn placement(out: &mut Vec<u8>, transform: Transform) {
151 if transform == Transform::IDENTITY {
152 out.push(b'I');
153 } else {
154 out.push(b'T');
155 text(out, format_args!("{transform:?}"));
156 }
157}
158
159fn knots(out: &mut Vec<u8>, knots: &KnotVector) {
160 count(out, knots.degree());
161 count(out, knots.knots().len());
162 bits(out, knots.knots());
163}
164
165fn space_curve(out: &mut Vec<u8>, curve: &Curve) {
168 match curve {
169 Curve::BSpline(spline) => {
170 out.push(b'B');
171 out.push(u8::from(spline.is_rational()));
172 out.push(u8::from(spline.is_periodic()));
173 knots(out, spline.knots());
174 count(out, spline.control_points().len());
175 for c in spline.control_points() {
176 bits(out, &[c.scaled.x, c.scaled.y, c.scaled.z, c.weight]);
177 }
178 }
179 other => {
180 out.push(b'D');
181 text(out, format_args!("{other:?}"));
182 }
183 }
184}
185
186fn planar_curve(out: &mut Vec<u8>, curve: &PlanarCurve) {
188 match curve {
189 PlanarCurve::BSpline(spline) => {
190 out.push(b'B');
191 out.push(u8::from(spline.is_rational()));
192 knots(out, spline.knots());
193 count(out, spline.control_points().len());
194 for c in spline.control_points() {
195 bits(out, &[c.scaled.x, c.scaled.y, c.weight]);
196 }
197 }
198 other => {
199 out.push(b'D');
200 text(out, format_args!("{other:?}"));
201 }
202 }
203}