truck_stepio/in/
alias.rs

1use crate::{self as truck_stepio};
2use derive_more::*;
3use serde::{Deserialize, Serialize};
4use truck_derivers::{DisplayByStep, StepCurve, StepLength, StepSurface};
5
6/// re-export structs in `truck-geometry` and `truck-polymesh`.
7pub mod re_exports {
8    pub use truck_geometry::prelude::*;
9    pub use truck_polymesh::*;
10}
11pub use re_exports::*;
12
13/// Errors that occur when converting STEP format
14pub type StepConvertingError = Box<dyn std::error::Error>;
15
16/// `ellipse`, realized in `truck`
17pub type Ellipse<P, M> = Processor<TrimmedCurve<UnitCircle<P>>, M>;
18/// `hyperbola`, realized in `truck`
19pub type Hyperbola<P, M> = Processor<TrimmedCurve<UnitHyperbola<P>>, M>;
20/// `parabola`, realized in `truck`
21pub type Parabola<P, M> = Processor<TrimmedCurve<UnitParabola<P>>, M>;
22/// `spherical_surface`, realized in `truck`
23pub type SphericalSurface = Processor<Sphere, Matrix4>;
24/// `cylindrical_surface`, realized in `truck`
25pub type CylindricalSurface = Processor<RevolutedCurve<Line<Point3>>, Matrix4>;
26/// `toroidal_surface`, realized in `truck`
27pub type ToroidalSurface = Processor<Torus, Matrix4>;
28/// `conical_surface`, realized in `truck`
29pub type ConicalSurface = Processor<RevolutedCurve<Line<Point3>>, Matrix4>;
30/// `surface_of_linear_extrusion`, realized in `truck`
31pub type StepExtrudedCurve = ExtrudedCurve<Curve3D, Vector3>;
32/// `surface_of_revolution`, realized in `truck`
33pub type StepRevolutedCurve = Processor<RevolutedCurve<Curve3D>, Matrix4>;
34/// `pcurve`, realized in `truck`
35pub type PCurve = truck_geometry::prelude::PCurve<Box<Curve2D>, Box<Surface>>;
36
37/// `conic` in 2D, realized in `truck`
38#[derive(
39    Clone,
40    Copy,
41    Debug,
42    PartialEq,
43    From,
44    Serialize,
45    Deserialize,
46    ParametricCurve,
47    BoundedCurve,
48    Cut,
49    Invertible,
50    ParameterDivision1D,
51    SearchParameterD1,
52    SearchNearestParameterD1,
53    TransformedM3,
54    StepLength,
55    DisplayByStep,
56    StepCurve,
57)]
58pub enum Conic2D {
59    Ellipse(Ellipse<Point2, Matrix3>),
60    Hyperbola(Hyperbola<Point2, Matrix3>),
61    Parabola(Parabola<Point2, Matrix3>),
62}
63
64/// `curve` in 2D, realized in `truck`
65#[derive(
66    Clone,
67    Debug,
68    PartialEq,
69    From,
70    Serialize,
71    Deserialize,
72    ParametricCurve,
73    BoundedCurve,
74    Cut,
75    Invertible,
76    ParameterDivision1D,
77    SearchParameterD1,
78    SearchNearestParameterD1,
79    TransformedM3,
80    StepLength,
81    DisplayByStep,
82    StepCurve,
83)]
84
85pub enum Curve2D {
86    Line(Line<Point2>),
87    Polyline(PolylineCurve<Point2>),
88    Conic(Conic2D),
89    BSplineCurve(BSplineCurve<Point2>),
90    NurbsCurve(NurbsCurve<Vector3>),
91}
92
93/// `conic` in 3D, realized in `truck`
94#[derive(
95    Clone,
96    Copy,
97    Debug,
98    PartialEq,
99    From,
100    Serialize,
101    Deserialize,
102    ParametricCurve,
103    BoundedCurve,
104    Cut,
105    Invertible,
106    ParameterDivision1D,
107    SearchParameterD1,
108    SearchNearestParameterD1,
109    TransformedM4,
110    StepLength,
111    DisplayByStep,
112    StepCurve,
113)]
114pub enum Conic3D {
115    Ellipse(Ellipse<Point3, Matrix4>),
116    Hyperbola(Hyperbola<Point3, Matrix4>),
117    Parabola(Parabola<Point3, Matrix4>),
118}
119
120/// `curve` in 3D, realized in `truck`
121#[derive(
122    Clone,
123    Debug,
124    PartialEq,
125    From,
126    Serialize,
127    Deserialize,
128    ParametricCurve,
129    BoundedCurve,
130    Cut,
131    Invertible,
132    ParameterDivision1D,
133    SearchParameterD1,
134    SearchNearestParameterD1,
135    TransformedM4,
136    StepLength,
137    DisplayByStep,
138    StepCurve,
139)]
140pub enum Curve3D {
141    Line(Line<Point3>),
142    Polyline(PolylineCurve<Point3>),
143    Conic(Conic3D),
144    BSplineCurve(BSplineCurve<Point3>),
145    PCurve(PCurve),
146    NurbsCurve(NurbsCurve<Vector4>),
147}
148
149/// `elementary_surface`, realized in `truck`
150#[derive(
151    Clone,
152    Copy,
153    Debug,
154    PartialEq,
155    Serialize,
156    Deserialize,
157    ParametricSurface3D,
158    ParameterDivision2D,
159    SearchParameterD2,
160    SearchNearestParameterD2,
161    Invertible,
162    TransformedM4,
163    StepLength,
164    DisplayByStep,
165    StepSurface,
166)]
167pub enum ElementarySurface {
168    Plane(Plane),
169    Sphere(SphericalSurface),
170    CylindricalSurface(CylindricalSurface),
171    ToroidalSurface(ToroidalSurface),
172    ConicalSurface(ConicalSurface),
173}
174
175/// `swept_surface`, realized in `truck`
176#[derive(
177    Clone,
178    Debug,
179    PartialEq,
180    Serialize,
181    Deserialize,
182    ParametricSurface3D,
183    ParameterDivision2D,
184    SearchParameterD2,
185    SearchNearestParameterD2,
186    Invertible,
187    TransformedM4,
188    StepLength,
189    DisplayByStep,
190    StepSurface,
191)]
192pub enum SweptCurve {
193    ExtrudedCurve(StepExtrudedCurve),
194    RevolutedCurve(StepRevolutedCurve),
195}
196
197/// `surface`, realized in `truck`
198#[derive(
199    Clone,
200    Debug,
201    PartialEq,
202    Serialize,
203    Deserialize,
204    ParametricSurface3D,
205    ParameterDivision2D,
206    SearchParameterD2,
207    SearchNearestParameterD2,
208    Invertible,
209    TransformedM4,
210    StepLength,
211    StepSurface,
212)]
213pub enum Surface {
214    ElementarySurface(Box<ElementarySurface>),
215    SweptCurve(Box<SweptCurve>),
216    BSplineSurface(Box<BSplineSurface<Point3>>),
217    NurbsSurface(Box<NurbsSurface<Vector4>>),
218}
219
220impl truck_stepio::out::DisplayByStep for Surface {
221    fn fmt(&self, idx: usize, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
222        use Surface::*;
223        match self {
224            ElementarySurface(x) => x.fmt(idx, f),
225            SweptCurve(x) => x.fmt(idx, f),
226            BSplineSurface(x) => x.fmt(idx, f),
227            NurbsSurface(x) => x.fmt(idx, f),
228        }
229    }
230}
231
232/// `spherical_surface`, realized in `truck`
233#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, StepSurface)]
234pub struct Sphere(pub truck_geometry::prelude::Sphere);
235
236impl truck_stepio::out::StepSurface for Processor<Sphere, Matrix4> {
237    #[inline(always)]
238    fn same_sense(&self) -> bool { self.orientation() }
239}
240
241mod sphere {
242    use super::*;
243    use std::f64::consts::PI;
244    use std::ops::Bound;
245    impl ParametricSurface for Sphere {
246        type Point = Point3;
247        type Vector = Vector3;
248        #[inline]
249        fn subs(&self, u: f64, v: f64) -> Point3 { self.0.subs(PI / 2.0 - v, u) }
250        #[inline]
251        fn uder(&self, u: f64, v: f64) -> Vector3 { self.0.vder(PI / 2.0 - v, u) }
252        #[inline]
253        fn vder(&self, u: f64, v: f64) -> Vector3 { -self.0.uder(PI / 2.0 - v, u) }
254        #[inline]
255        fn uuder(&self, u: f64, v: f64) -> Vector3 { self.0.vvder(PI / 2.0 - v, u) }
256        #[inline]
257        fn uvder(&self, u: f64, v: f64) -> Vector3 { -self.0.uvder(PI / 2.0 - v, u) }
258        #[inline]
259        fn vvder(&self, u: f64, v: f64) -> Vector3 { self.0.uuder(PI / 2.0 - v, u) }
260        #[inline]
261        fn parameter_range(&self) -> (ParameterRange, ParameterRange) {
262            (
263                (Bound::Included(0.0), Bound::Excluded(2.0 * PI)),
264                (Bound::Included(-PI / 2.0), Bound::Excluded(PI / 2.0)),
265            )
266        }
267        #[inline]
268        fn u_period(&self) -> Option<f64> { Some(2.0 * PI) }
269    }
270    impl ParametricSurface3D for Sphere {
271        #[inline]
272        fn normal(&self, u: f64, v: f64) -> Vector3 { self.0.normal(PI / 2.0 - v, u) }
273    }
274    impl SearchNearestParameter<D2> for Sphere {
275        type Point = Point3;
276        #[inline]
277        fn search_nearest_parameter<H: Into<SPHint2D>>(
278            &self,
279            point: Self::Point,
280            hint: H,
281            trials: usize,
282        ) -> Option<(f64, f64)> {
283            self.0
284                .search_nearest_parameter(point, hint, trials)
285                .map(|(u, v)| (v, PI / 2.0 - u))
286        }
287    }
288    impl SearchParameter<D2> for Sphere {
289        type Point = Point3;
290        #[inline]
291        fn search_parameter<H: Into<SPHint2D>>(
292            &self,
293            point: Self::Point,
294            hint: H,
295            trials: usize,
296        ) -> Option<(f64, f64)> {
297            self.0
298                .search_parameter(point, hint, trials)
299                .map(|(u, v)| (v, PI / 2.0 - u))
300        }
301    }
302    impl ParameterDivision2D for Sphere {
303        #[inline]
304        fn parameter_division(
305            &self,
306            ((u0, u1), (v0, v1)): ((f64, f64), (f64, f64)),
307            tol: f64,
308        ) -> (Vec<f64>, Vec<f64>) {
309            let range = ((PI / 2.0 - v1, PI / 2.0 - v0), (u0, u1));
310            let (udiv0, vdiv0) = self.0.parameter_division(range, tol);
311            let vdiv = udiv0.into_iter().map(|u| PI / 2.0 - u).collect();
312            (vdiv0, vdiv)
313        }
314    }
315
316    #[cfg(test)]
317    proptest::proptest! {
318        #[test]
319        fn surface(
320            center in proptest::array::uniform3(-100.0f64..100.0f64),
321            radius in 0.1f64..100.0f64,
322            (u, v) in (0.0..=2.0 * PI, -PI / 2.0..=PI / 2.0),
323        ) {
324            const EPS: f64 = 1.0e-3;
325            let sphere = Sphere(truck_geometry::prelude::Sphere::new(center.into(), radius));
326
327            let uder0 = sphere.uder(u, v);
328            let uder1 = (sphere.subs(u + EPS, v) - sphere.subs(u - EPS, v)) / (2.0 * EPS);
329            assert!(
330                (uder0 - uder1).magnitude2() < EPS,
331                "uder failed: {uder0:?}, {uder1:?}"
332            );
333
334            let vder0 = sphere.vder(u, v);
335            let vder1 = (sphere.subs(u, v + EPS) - sphere.subs(u, v - EPS)) / (2.0 * EPS);
336            assert!(
337                (vder0 - vder1).magnitude2() < EPS,
338                "vder failed: {vder0:?}, {vder1:?}"
339            );
340
341            let uuder0 = sphere.uuder(u, v);
342            let uuder1 = (sphere.uder(u + EPS, v) - sphere.uder(u - EPS, v)) / (2.0 * EPS);
343            assert!(
344                (uuder0 - uuder1).magnitude2() < EPS,
345                "uuder failed: {uuder0:?}, {uuder1:?}"
346            );
347
348            let uvder0 = sphere.uvder(u, v);
349            let uvder1 = (sphere.uder(u, v + EPS) - sphere.uder(u, v - EPS)) / (2.0 * EPS);
350            assert!(
351                (uvder0 - uvder1).magnitude2() < EPS,
352                "uvder failed: {uvder0:?}, {uvder1:?}"
353            );
354
355            let vvder0 = sphere.vvder(u, v);
356            let vvder1 = (sphere.vder(u, v + EPS) - sphere.vder(u, v - EPS)) / (2.0 * EPS);
357            assert!(
358                (vvder0 - vvder1).magnitude2() < EPS,
359                "vvder failed: {vvder0:?}, {vvder1:?}"
360            );
361
362            let n0 = sphere.normal(u, v);
363            let n1 = sphere.uder(u, v).cross(sphere.vder(u, v)).normalize();
364            assert!(
365                (n0 - n1).magnitude2() < EPS,
366                "normal failed: {n0:?}, {n1:?}"
367            );
368        }
369    }
370}
371
372impl truck_stepio::out::ConstStepLength for Processor<Sphere, Matrix4> {
373    const LENGTH: usize = Processor::<truck_geometry::prelude::Sphere, Matrix4>::LENGTH;
374}
375impl truck_stepio::out::StepLength for Processor<Sphere, Matrix4> {
376    fn step_length(&self) -> usize { <Self as truck_stepio::out::ConstStepLength>::LENGTH }
377}
378impl truck_stepio::out::DisplayByStep for Processor<Sphere, Matrix4> {
379    fn fmt(&self, idx: usize, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
380        Processor::new(self.entity().0)
381            .transformed(*self.transform())
382            .fmt(idx, f)
383    }
384}
385
386/// Implementation required to apply a closed surface division to a shape parsed from a STEP file.
387mod from_pcurve {
388    use super::{Curve2D, Curve3D, Surface};
389    use truck_geometry::prelude::*;
390
391    impl From<PCurve<Line<Point2>, Surface>> for Curve3D {
392        fn from(value: PCurve<Line<Point2>, Surface>) -> Self {
393            let (line, surface) = value.decompose();
394            Curve3D::PCurve(PCurve::new(Curve2D::Line(line).into(), surface.into()))
395        }
396    }
397}