1#![allow(clippy::must_use_candidate)]
12
13use crate::RefGraph;
14use crate::StepModel;
15use crate::scene::{Ctx, Scene};
16use crate::generated::model as m;
20
21impl Scene<'_> {
26 pub fn all_solids(&self) -> impl Iterator<Item = Solid<'_>> + '_ {
29 let cx = self.ctx();
30 let manifold = (0..cx.model.manifold_solid_brep_arena.items.len())
31 .map(move |i| Solid::from_id(cx, m::ManifoldSolidBrepId(i)));
32 let with_voids = (0..cx.model.brep_with_voids_arena.items.len())
33 .map(move |i| Solid::from_void_id(cx, m::BrepWithVoidsId(i)));
34 manifold.chain(with_voids)
35 }
36
37 pub fn all_faces(&self) -> impl Iterator<Item = Face<'_>> + '_ {
39 let cx = self.ctx();
40 let advanced = (0..cx.model.advanced_face_arena.items.len()).map(move |i| Face {
41 cx,
42 which: FaceImpl::Advanced(m::AdvancedFaceId(i)),
43 });
44 let surfaces = (0..cx.model.face_surface_arena.items.len()).map(move |i| Face {
45 cx,
46 which: FaceImpl::Surface(m::FaceSurfaceId(i)),
47 });
48 advanced.chain(surfaces)
49 }
50
51 pub fn all_edges(&self) -> impl Iterator<Item = Edge<'_>> + '_ {
53 let cx = self.ctx();
54 (0..cx.model.edge_curve_arena.items.len()).map(move |i| Edge {
55 cx,
56 id: m::EdgeCurveId(i),
57 })
58 }
59
60 pub fn all_vertices(&self) -> impl Iterator<Item = Vertex<'_>> + '_ {
62 let cx = self.ctx();
63 (0..cx.model.vertex_point_arena.items.len()).map(move |i| Vertex {
64 cx,
65 id: m::VertexPointId(i),
66 })
67 }
68
69 pub fn all_points(&self) -> impl Iterator<Item = Point<'_>> + '_ {
71 let cx = self.ctx();
72 (0..cx.model.cartesian_point_arena.items.len()).map(move |i| Point {
73 cx,
74 id: m::CartesianPointId(i),
75 })
76 }
77}
78
79#[derive(Clone, Copy)]
86pub struct Solid<'m> {
87 cx: Ctx<'m>,
88 which: SolidImpl,
89}
90
91#[derive(Clone, Copy)]
92enum SolidImpl {
93 Manifold(m::ManifoldSolidBrepId),
94 WithVoids(m::BrepWithVoidsId),
95}
96
97impl<'m> Solid<'m> {
98 pub(crate) fn from_id(cx: Ctx<'m>, id: m::ManifoldSolidBrepId) -> Self {
102 Solid {
103 cx,
104 which: SolidImpl::Manifold(id),
105 }
106 }
107
108 pub(crate) fn from_void_id(cx: Ctx<'m>, id: m::BrepWithVoidsId) -> Self {
110 Solid {
111 cx,
112 which: SolidImpl::WithVoids(id),
113 }
114 }
115
116 fn name_and_outer(&self) -> (&'m str, &'m m::ClosedShellRef) {
119 match self.which {
120 SolidImpl::Manifold(i) => {
121 let s = self.cx.model.manifold_solid_brep_arena.get(i.0);
122 (&s.name, &s.outer)
123 }
124 SolidImpl::WithVoids(i) => {
125 let s = self.cx.model.brep_with_voids_arena.get(i.0);
126 (&s.name, &s.outer)
127 }
128 }
129 }
130
131 pub fn name(&self) -> &'m str {
132 self.name_and_outer().0
133 }
134
135 pub fn key(&self) -> m::EntityKey {
138 match self.which {
139 SolidImpl::Manifold(i) => m::EntityKey::ManifoldSolidBrep(i),
140 SolidImpl::WithVoids(i) => m::EntityKey::BrepWithVoids(i),
141 }
142 }
143
144 pub fn color(&self) -> Option<crate::scene::presentation::Rgb> {
146 crate::scene::presentation::colour_of(self.cx, self.key())
147 }
148
149 pub fn transparency(&self) -> Option<f64> {
152 crate::scene::presentation::transparency_of(self.cx, self.key())
153 }
154
155 pub fn layer(&self) -> Option<&'m str> {
157 crate::scene::presentation::layer_of(self.cx, self.key())
158 }
159
160 pub fn is_visible(&self) -> bool {
163 crate::scene::presentation::is_visible(self.cx, self.key())
164 }
165
166 pub fn faces(&self) -> impl Iterator<Item = Face<'m>> + 'm {
168 let cx = self.cx;
169 resolve_closed_shell(cx.model, self.name_and_outer().1)
170 .into_iter()
171 .flat_map(|shell| shell.cfs_faces.iter())
172 .filter_map(move |fr| Face::from_ref(cx, fr))
173 }
174
175 pub fn voids(&self) -> Vec<Vec<Face<'m>>> {
178 let cx = self.cx;
179 let SolidImpl::WithVoids(id) = self.which else {
180 return Vec::new();
181 };
182 cx.model
183 .brep_with_voids_arena
184 .get(id.0)
185 .voids
186 .iter()
187 .map(|ocs| {
188 let shell = match ocs {
189 m::OrientedClosedShellRef::OrientedClosedShell(o) => resolve_closed_shell(
190 cx.model,
191 &cx.model
192 .oriented_closed_shell_arena
193 .get(o.0)
194 .closed_shell_element,
195 ),
196 m::OrientedClosedShellRef::Complex(_) => None,
197 };
198 shell
199 .into_iter()
200 .flat_map(|s| s.cfs_faces.iter())
201 .filter_map(|fr| Face::from_ref(cx, fr))
202 .collect()
203 })
204 .collect()
205 }
206}
207
208#[derive(Clone, Copy)]
213enum FaceImpl {
214 Advanced(m::AdvancedFaceId),
215 Surface(m::FaceSurfaceId),
216}
217
218#[derive(Clone, Copy)]
221pub struct Face<'m> {
222 cx: Ctx<'m>,
223 which: FaceImpl,
224}
225
226impl<'m> Face<'m> {
227 pub(crate) fn from_advanced_face(cx: Ctx<'m>, id: m::AdvancedFaceId) -> Self {
230 Face {
231 cx,
232 which: FaceImpl::Advanced(id),
233 }
234 }
235
236 fn from_ref(cx: Ctx<'m>, r: &m::FaceRef) -> Option<Self> {
237 match r {
238 m::FaceRef::AdvancedFace(i) => Some(Face {
239 cx,
240 which: FaceImpl::Advanced(*i),
241 }),
242 m::FaceRef::FaceSurface(i) => Some(Face {
243 cx,
244 which: FaceImpl::Surface(*i),
245 }),
246 m::FaceRef::Face(_) | m::FaceRef::Complex(_) => None,
248 }
249 }
250
251 fn parts(&self) -> (&'m str, &'m [m::FaceBoundRef], &'m m::SurfaceRef, bool) {
254 match self.which {
255 FaceImpl::Advanced(i) => {
256 let f = self.cx.model.advanced_face_arena.get(i.0);
257 (&f.name, &f.bounds, &f.face_geometry, f.same_sense)
258 }
259 FaceImpl::Surface(i) => {
260 let f = self.cx.model.face_surface_arena.get(i.0);
261 (&f.name, &f.bounds, &f.face_geometry, f.same_sense)
262 }
263 }
264 }
265
266 pub fn name(&self) -> &'m str {
267 self.parts().0
268 }
269
270 pub fn same_sense(&self) -> bool {
271 self.parts().3
272 }
273
274 pub fn surface(&self) -> Surface<'m> {
276 Surface {
277 cx: self.cx,
278 r: self.parts().2,
279 }
280 }
281
282 pub fn bounds(&self) -> impl Iterator<Item = Bound<'m>> + 'm {
284 let cx = self.cx;
285 self.parts()
286 .1
287 .iter()
288 .filter_map(move |br| Bound::from_ref(cx, br))
289 }
290
291 fn boundary_points(&self) -> Vec<[f64; 3]> {
298 let mut points = Vec::new();
299 for bound in self.bounds() {
300 for edge in bound.edges() {
301 if let Some(n) = edge.to_nurbs() {
302 points.extend(n.control_points);
303 } else {
304 for v in [edge.start(), edge.end()].into_iter().flatten() {
305 if let Some(pt) = v.point() {
306 points.push(pt.xyz());
307 }
308 }
309 }
310 }
311 }
312 points
313 }
314
315 pub fn to_nurbs(&self) -> Option<crate::scene::nurbs::NurbsSurface> {
323 if let Some(n) = self.surface().to_nurbs() {
324 return Some(n);
325 }
326 let cx = self.cx;
327 let pts = self.boundary_points();
328 match self.surface().kind() {
329 SurfaceKind::Plane(p) => crate::scene::nurbs::plane_patch(cx, p, &pts),
330 SurfaceKind::Cylindrical(c) => {
331 crate::scene::nurbs::cylinder_cone_patch(cx, &c.position, c.radius, 0.0, &pts)
332 }
333 SurfaceKind::Conical(c) => crate::scene::nurbs::cylinder_cone_patch(
334 cx,
335 &c.position,
336 c.radius,
337 c.semi_angle,
338 &pts,
339 ),
340 SurfaceKind::LinearExtrusion(s) => {
341 let profile = Curve::from_curve_ref(cx, &s.swept_curve).to_nurbs()?;
342 crate::scene::nurbs::extrude_patch(cx, &profile, &s.extrusion_axis, &pts)
343 }
344 SurfaceKind::Revolution(s) => {
349 let CurveKind::Line(line) = Curve::from_curve_ref(cx, &s.swept_curve).kind() else {
350 return None;
351 };
352 let frame = crate::scene::nurbs::axis1_frame(cx, &s.axis_position)?;
353 let seg = crate::scene::nurbs::revolved_line_segment(cx, line, frame, &pts)?;
354 Some(crate::scene::nurbs::revolve_curve(&seg, frame))
355 }
356 _ => None,
357 }
358 }
359
360 pub fn key(&self) -> m::EntityKey {
363 match self.which {
364 FaceImpl::Advanced(i) => m::EntityKey::AdvancedFace(i),
365 FaceImpl::Surface(i) => m::EntityKey::FaceSurface(i),
366 }
367 }
368
369 pub fn color(&self) -> Option<crate::scene::presentation::Rgb> {
371 crate::scene::presentation::colour_of(self.cx, self.key())
372 }
373
374 pub fn transparency(&self) -> Option<f64> {
377 crate::scene::presentation::transparency_of(self.cx, self.key())
378 }
379
380 pub fn layer(&self) -> Option<&'m str> {
382 crate::scene::presentation::layer_of(self.cx, self.key())
383 }
384
385 pub fn is_visible(&self) -> bool {
388 crate::scene::presentation::is_visible(self.cx, self.key())
389 }
390
391 pub fn solid(&self) -> Option<Solid<'m>> {
395 let rg = self.cx.ref_graph();
396 for &r in rg.referrers(self.key()) {
397 if let m::EntityKey::ClosedShell(cs) = r {
398 if let Some(which) = closed_shell_to_solid(rg, cs) {
399 return Some(Solid { cx: self.cx, which });
400 }
401 }
402 }
403 None
404 }
405}
406
407#[derive(Clone, Copy)]
413pub struct Surface<'m> {
414 cx: Ctx<'m>,
415 r: &'m m::SurfaceRef,
416}
417
418#[derive(Clone, Copy, Debug)]
421pub enum SurfaceKind<'m> {
422 Plane(&'m m::Plane),
423 Cylindrical(&'m m::CylindricalSurface),
424 Conical(&'m m::ConicalSurface),
425 Spherical(&'m m::SphericalSurface),
426 Toroidal(&'m m::ToroidalSurface),
427 BSpline(&'m m::BSplineSurface),
428 BSplineWithKnots(&'m m::BSplineSurfaceWithKnots),
429 LinearExtrusion(&'m m::SurfaceOfLinearExtrusion),
430 Revolution(&'m m::SurfaceOfRevolution),
431 QuasiUniform(&'m m::QuasiUniformSurface),
432 Uniform(&'m m::UniformSurface),
433 Bezier(&'m m::BezierSurface),
434 Other(&'static str),
435}
436
437impl<'m> Surface<'m> {
438 pub fn key(&self) -> m::EntityKey {
441 self.r.entity_key()
442 }
443
444 pub fn to_nurbs(&self) -> Option<crate::scene::nurbs::NurbsSurface> {
450 let cx = self.cx;
451 match self.r {
452 m::SurfaceRef::SphericalSurface(i) => {
453 crate::scene::nurbs::sphere_to_nurbs(cx, cx.model.spherical_surface_arena.get(i.0))
454 }
455 m::SurfaceRef::ToroidalSurface(i) => {
456 crate::scene::nurbs::torus_to_nurbs(cx, cx.model.toroidal_surface_arena.get(i.0))
457 }
458 m::SurfaceRef::BSplineSurfaceWithKnots(i) => {
459 crate::scene::nurbs::bspline_surf_wk_to_nurbs(
460 cx,
461 cx.model.b_spline_surface_with_knots_arena.get(i.0),
462 )
463 }
464 m::SurfaceRef::Complex(i) => crate::scene::nurbs::complex_bspline_surface_to_nurbs(
466 cx,
467 &cx.model.complex_unit_arena.get(i.0).parts,
468 ),
469 m::SurfaceRef::SurfaceOfRevolution(i) => {
472 let s = cx.model.surface_of_revolution_arena.get(i.0);
473 let profile = Curve::from_curve_ref(cx, &s.swept_curve).to_nurbs()?;
474 let frame = crate::scene::nurbs::axis1_frame(cx, &s.axis_position)?;
475 Some(crate::scene::nurbs::revolve_curve(&profile, frame))
476 }
477 m::SurfaceRef::UniformSurface(i) => {
479 let s = cx.model.uniform_surface_arena.get(i.0);
480 crate::scene::nurbs::uniform_family_surface_to_nurbs(
481 cx,
482 (s.u_degree, s.v_degree),
483 &s.control_points_list,
484 crate::scene::nurbs::KnotFamily::Uniform,
485 )
486 }
487 m::SurfaceRef::QuasiUniformSurface(i) => {
488 let s = cx.model.quasi_uniform_surface_arena.get(i.0);
489 crate::scene::nurbs::uniform_family_surface_to_nurbs(
490 cx,
491 (s.u_degree, s.v_degree),
492 &s.control_points_list,
493 crate::scene::nurbs::KnotFamily::QuasiUniform,
494 )
495 }
496 m::SurfaceRef::BezierSurface(i) => {
497 let s = cx.model.bezier_surface_arena.get(i.0);
498 crate::scene::nurbs::uniform_family_surface_to_nurbs(
499 cx,
500 (s.u_degree, s.v_degree),
501 &s.control_points_list,
502 crate::scene::nurbs::KnotFamily::Bezier,
503 )
504 }
505 _ => None,
506 }
507 }
508
509 pub fn kind(&self) -> SurfaceKind<'m> {
510 let model = self.cx.model;
511 match self.r {
512 m::SurfaceRef::Plane(i) => SurfaceKind::Plane(model.plane_arena.get(i.0)),
513 m::SurfaceRef::CylindricalSurface(i) => {
514 SurfaceKind::Cylindrical(model.cylindrical_surface_arena.get(i.0))
515 }
516 m::SurfaceRef::ConicalSurface(i) => {
517 SurfaceKind::Conical(model.conical_surface_arena.get(i.0))
518 }
519 m::SurfaceRef::SphericalSurface(i) => {
520 SurfaceKind::Spherical(model.spherical_surface_arena.get(i.0))
521 }
522 m::SurfaceRef::ToroidalSurface(i) => {
523 SurfaceKind::Toroidal(model.toroidal_surface_arena.get(i.0))
524 }
525 m::SurfaceRef::BSplineSurface(i) => {
526 SurfaceKind::BSpline(model.b_spline_surface_arena.get(i.0))
527 }
528 m::SurfaceRef::BSplineSurfaceWithKnots(i) => {
529 SurfaceKind::BSplineWithKnots(model.b_spline_surface_with_knots_arena.get(i.0))
530 }
531 m::SurfaceRef::BezierSurface(i) => {
532 SurfaceKind::Bezier(model.bezier_surface_arena.get(i.0))
533 }
534 m::SurfaceRef::BoundedSurface(_) => SurfaceKind::Other("BOUNDED_SURFACE"),
535 m::SurfaceRef::DegenerateToroidalSurface(_) => {
536 SurfaceKind::Other("DEGENERATE_TOROIDAL_SURFACE")
537 }
538 m::SurfaceRef::ElementarySurface(_) => SurfaceKind::Other("ELEMENTARY_SURFACE"),
539 m::SurfaceRef::OffsetSurface(_) => SurfaceKind::Other("OFFSET_SURFACE"),
540 m::SurfaceRef::QuasiUniformSurface(i) => {
541 SurfaceKind::QuasiUniform(model.quasi_uniform_surface_arena.get(i.0))
542 }
543 m::SurfaceRef::RationalBSplineSurface(_) => {
544 SurfaceKind::Other("RATIONAL_B_SPLINE_SURFACE")
545 }
546 m::SurfaceRef::Surface(_) => SurfaceKind::Other("SURFACE"),
547 m::SurfaceRef::SurfaceOfLinearExtrusion(i) => {
548 SurfaceKind::LinearExtrusion(model.surface_of_linear_extrusion_arena.get(i.0))
549 }
550 m::SurfaceRef::SurfaceOfRevolution(i) => {
551 SurfaceKind::Revolution(model.surface_of_revolution_arena.get(i.0))
552 }
553 m::SurfaceRef::SweptSurface(_) => SurfaceKind::Other("SWEPT_SURFACE"),
554 m::SurfaceRef::UniformSurface(i) => {
555 SurfaceKind::Uniform(model.uniform_surface_arena.get(i.0))
556 }
557 m::SurfaceRef::Complex(_) => SurfaceKind::Other("COMPLEX"),
558 }
559 }
560}
561
562#[derive(Clone, Copy)]
567enum BoundImpl {
568 Inner(m::FaceBoundId),
569 Outer(m::FaceOuterBoundId),
570}
571
572#[derive(Clone, Copy)]
574pub struct Bound<'m> {
575 cx: Ctx<'m>,
576 which: BoundImpl,
577}
578
579impl<'m> Bound<'m> {
580 fn from_ref(cx: Ctx<'m>, r: &m::FaceBoundRef) -> Option<Self> {
581 match r {
582 m::FaceBoundRef::FaceBound(i) => Some(Bound {
583 cx,
584 which: BoundImpl::Inner(*i),
585 }),
586 m::FaceBoundRef::FaceOuterBound(i) => Some(Bound {
587 cx,
588 which: BoundImpl::Outer(*i),
589 }),
590 m::FaceBoundRef::Complex(_) => None,
591 }
592 }
593
594 pub fn is_outer(&self) -> bool {
596 matches!(self.which, BoundImpl::Outer(_))
597 }
598
599 pub fn key(&self) -> m::EntityKey {
601 match self.which {
602 BoundImpl::Inner(i) => m::EntityKey::FaceBound(i),
603 BoundImpl::Outer(i) => m::EntityKey::FaceOuterBound(i),
604 }
605 }
606
607 fn loop_ref(&self) -> &'m m::LoopRef {
608 match self.which {
609 BoundImpl::Inner(i) => &self.cx.model.face_bound_arena.get(i.0).bound,
610 BoundImpl::Outer(i) => &self.cx.model.face_outer_bound_arena.get(i.0).bound,
611 }
612 }
613
614 pub fn orientation(&self) -> bool {
620 match self.which {
621 BoundImpl::Inner(i) => self.cx.model.face_bound_arena.get(i.0).orientation,
622 BoundImpl::Outer(i) => self.cx.model.face_outer_bound_arena.get(i.0).orientation,
623 }
624 }
625
626 pub fn edges(&self) -> impl Iterator<Item = Edge<'m>> + 'm {
630 self.oriented_edges().map(|(e, _)| e)
631 }
632
633 pub fn oriented_edges(&self) -> impl Iterator<Item = (Edge<'m>, bool)> + 'm {
638 let cx = self.cx;
639 resolve_edge_loop(cx.model, self.loop_ref())
640 .into_iter()
641 .flat_map(|el| el.edge_list.iter())
642 .filter_map(move |oer| {
643 let oe = resolve_oriented_edge(cx.model, oer)?;
644 Some((Edge::from_edge_ref(cx, &oe.edge_element)?, oe.orientation))
645 })
646 }
647}
648
649#[derive(Clone, Copy)]
655pub struct Edge<'m> {
656 cx: Ctx<'m>,
657 id: m::EdgeCurveId,
658}
659
660impl<'m> Edge<'m> {
661 pub(crate) fn from_id(cx: Ctx<'m>, id: m::EdgeCurveId) -> Self {
664 Edge { cx, id }
665 }
666
667 fn from_edge_ref(cx: Ctx<'m>, r: &m::EdgeRef) -> Option<Self> {
668 match r {
669 m::EdgeRef::EdgeCurve(i) => Some(Edge { cx, id: *i }),
670 m::EdgeRef::Edge(_) | m::EdgeRef::OrientedEdge(_) | m::EdgeRef::Complex(_) => None,
672 }
673 }
674
675 fn raw(&self) -> &'m m::EdgeCurve {
676 self.cx.model.edge_curve_arena.get(self.id.0)
677 }
678
679 pub fn key(&self) -> m::EntityKey {
682 m::EntityKey::EdgeCurve(self.id)
683 }
684
685 pub fn start(&self) -> Option<Vertex<'m>> {
686 Vertex::from_ref(self.cx, &self.raw().edge_start)
687 }
688
689 pub fn end(&self) -> Option<Vertex<'m>> {
690 Vertex::from_ref(self.cx, &self.raw().edge_end)
691 }
692
693 pub fn curve(&self) -> Curve<'m> {
695 Curve::from_curve_ref(self.cx, &self.raw().edge_geometry)
696 }
697
698 pub fn same_sense(&self) -> bool {
703 self.raw().same_sense
704 }
705
706 pub fn to_nurbs(&self) -> Option<crate::scene::nurbs::NurbsCurve> {
713 let cx = self.cx;
714 let coords = |v: Option<Vertex<'m>>| Some(v?.point()?.xyz());
715 let (Some(p0), Some(p1)) = (coords(self.start()), coords(self.end())) else {
716 cx.warn("EDGE_CURVE.to_nurbs: unresolved edge vertex".to_owned());
717 return None;
718 };
719 let raw = self.raw();
720 crate::scene::nurbs::edge_to_nurbs(cx, &raw.edge_geometry, p0, p1, raw.same_sense)
721 }
722}
723
724#[derive(Clone, Copy)]
731pub struct Curve<'m> {
732 cx: Ctx<'m>,
733 which: CurveImpl,
734}
735
736#[derive(Clone, Copy, Debug)]
739pub enum CurveKind<'m> {
740 Line(&'m m::Line),
741 Circle(&'m m::Circle),
742 Ellipse(&'m m::Ellipse),
743 BSpline(&'m m::BSplineCurve),
744 BSplineWithKnots(&'m m::BSplineCurveWithKnots),
745 Trimmed(&'m m::TrimmedCurve),
746 Polyline(&'m m::Polyline),
747 Composite(&'m m::CompositeCurve),
748 QuasiUniform(&'m m::QuasiUniformCurve),
749 Uniform(&'m m::UniformCurve),
750 Bezier(&'m m::BezierCurve),
751 SurfaceCurve(&'m m::SurfaceCurve),
752 SeamCurve(&'m m::SeamCurve),
753 BoundedSurfaceCurve(&'m m::BoundedSurfaceCurve),
754 IntersectionCurve(&'m m::IntersectionCurve),
755 Other(&'static str),
756}
757
758macro_rules! curve_impl {
764 ($( $V:ident, $id:ident );+ $(;)?) => {
765 #[derive(Clone, Copy)]
766 enum CurveImpl {
767 $( $V(m::$id), )+
768 Complex(m::ComplexUnitId),
769 }
770
771 impl<'m> Curve<'m> {
772 pub fn key(&self) -> m::EntityKey {
775 match self.which {
776 $( CurveImpl::$V(i) => m::EntityKey::$V(i), )+
777 CurveImpl::Complex(i) => m::EntityKey::ComplexUnit(i),
778 }
779 }
780
781 pub(crate) fn from_curve_ref(cx: Ctx<'m>, r: &m::CurveRef) -> Self {
782 let which = match r {
783 $( m::CurveRef::$V(i) => CurveImpl::$V(*i), )+
784 m::CurveRef::Complex(i) => CurveImpl::Complex(*i),
785 };
786 Curve { cx, which }
787 }
788
789 pub(crate) fn from_model_item(
792 cx: Ctx<'m>,
793 r: &m::GeometricModelItemRef,
794 ) -> Option<Self> {
795 let which = match r {
796 $( m::GeometricModelItemRef::$V(i) => CurveImpl::$V(*i), )+
797 _ => return None,
798 };
799 Some(Curve { cx, which })
800 }
801 }
802 };
803}
804
805curve_impl! {
806 BSplineCurve, BSplineCurveId;
807 BSplineCurveWithKnots, BSplineCurveWithKnotsId;
808 BezierCurve, BezierCurveId;
809 BoundedCurve, BoundedCurveId;
810 BoundedPcurve, BoundedPcurveId;
811 BoundedSurfaceCurve, BoundedSurfaceCurveId;
812 Circle, CircleId;
813 CompositeCurve, CompositeCurveId;
814 Conic, ConicId;
815 Curve, CurveId;
816 Ellipse, EllipseId;
817 Hyperbola, HyperbolaId;
818 IntersectionCurve, IntersectionCurveId;
819 Line, LineId;
820 Pcurve, PcurveId;
821 Polyline, PolylineId;
822 QuasiUniformCurve, QuasiUniformCurveId;
823 RationalBSplineCurve, RationalBSplineCurveId;
824 SeamCurve, SeamCurveId;
825 SurfaceCurve, SurfaceCurveId;
826 TrimmedCurve, TrimmedCurveId;
827 UniformCurve, UniformCurveId;
828}
829
830impl<'m> Curve<'m> {
831 pub fn color(&self) -> Option<crate::scene::presentation::Rgb> {
833 crate::scene::presentation::curve_colour_of(self.cx, self.key())
834 }
835
836 pub fn width(&self) -> Option<f64> {
839 crate::scene::presentation::curve_width_of(self.cx, self.key())
840 }
841
842 pub fn line_font(&self) -> Option<&'m str> {
845 crate::scene::presentation::curve_font_of(self.cx, self.key())
846 }
847
848 pub fn to_nurbs(&self) -> Option<crate::scene::nurbs::NurbsCurve> {
855 let cx = self.cx;
856 match self.which {
857 CurveImpl::Circle(i) => {
858 crate::scene::nurbs::circle_to_nurbs(cx, cx.model.circle_arena.get(i.0))
859 }
860 CurveImpl::Ellipse(i) => {
861 crate::scene::nurbs::ellipse_to_nurbs(cx, cx.model.ellipse_arena.get(i.0))
862 }
863 CurveImpl::BSplineCurveWithKnots(i) => crate::scene::nurbs::bspline_wk_to_nurbs(
864 cx,
865 cx.model.b_spline_curve_with_knots_arena.get(i.0),
866 ),
867 CurveImpl::Complex(i) => crate::scene::nurbs::complex_bspline_curve_to_nurbs(
869 cx,
870 &cx.model.complex_unit_arena.get(i.0).parts,
871 ),
872 CurveImpl::TrimmedCurve(i) => {
874 crate::scene::nurbs::trimmed_to_nurbs(cx, cx.model.trimmed_curve_arena.get(i.0))
875 }
876 CurveImpl::UniformCurve(i) => {
878 let c = cx.model.uniform_curve_arena.get(i.0);
879 crate::scene::nurbs::uniform_family_curve_to_nurbs(
880 cx,
881 c.degree,
882 &c.control_points_list,
883 crate::scene::nurbs::KnotFamily::Uniform,
884 )
885 }
886 CurveImpl::QuasiUniformCurve(i) => {
887 let c = cx.model.quasi_uniform_curve_arena.get(i.0);
888 crate::scene::nurbs::uniform_family_curve_to_nurbs(
889 cx,
890 c.degree,
891 &c.control_points_list,
892 crate::scene::nurbs::KnotFamily::QuasiUniform,
893 )
894 }
895 CurveImpl::BezierCurve(i) => {
896 let c = cx.model.bezier_curve_arena.get(i.0);
897 crate::scene::nurbs::uniform_family_curve_to_nurbs(
898 cx,
899 c.degree,
900 &c.control_points_list,
901 crate::scene::nurbs::KnotFamily::Bezier,
902 )
903 }
904 CurveImpl::Polyline(i) => {
905 crate::scene::nurbs::polyline_to_nurbs(cx, cx.model.polyline_arena.get(i.0))
906 }
907 CurveImpl::CompositeCurve(i) => {
909 crate::scene::nurbs::composite_to_nurbs(cx, cx.model.composite_curve_arena.get(i.0))
910 }
911 CurveImpl::SurfaceCurve(i) => crate::scene::nurbs::surface_curve_3d_to_nurbs(
913 cx,
914 &cx.model.surface_curve_arena.get(i.0).curve_3d,
915 ),
916 CurveImpl::SeamCurve(i) => crate::scene::nurbs::surface_curve_3d_to_nurbs(
917 cx,
918 &cx.model.seam_curve_arena.get(i.0).curve_3d,
919 ),
920 CurveImpl::BoundedSurfaceCurve(i) => crate::scene::nurbs::surface_curve_3d_to_nurbs(
921 cx,
922 &cx.model.bounded_surface_curve_arena.get(i.0).curve_3d,
923 ),
924 CurveImpl::IntersectionCurve(i) => crate::scene::nurbs::surface_curve_3d_to_nurbs(
925 cx,
926 &cx.model.intersection_curve_arena.get(i.0).curve_3d,
927 ),
928 _ => None,
929 }
930 }
931
932 pub fn kind(&self) -> CurveKind<'m> {
933 let model = self.cx.model;
934 match self.which {
935 CurveImpl::Line(i) => CurveKind::Line(model.line_arena.get(i.0)),
936 CurveImpl::Circle(i) => CurveKind::Circle(model.circle_arena.get(i.0)),
937 CurveImpl::Ellipse(i) => CurveKind::Ellipse(model.ellipse_arena.get(i.0)),
938 CurveImpl::BSplineCurve(i) => CurveKind::BSpline(model.b_spline_curve_arena.get(i.0)),
939 CurveImpl::BSplineCurveWithKnots(i) => {
940 CurveKind::BSplineWithKnots(model.b_spline_curve_with_knots_arena.get(i.0))
941 }
942 CurveImpl::TrimmedCurve(i) => CurveKind::Trimmed(model.trimmed_curve_arena.get(i.0)),
943 CurveImpl::BezierCurve(i) => CurveKind::Bezier(model.bezier_curve_arena.get(i.0)),
944 CurveImpl::BoundedCurve(_) => CurveKind::Other("BOUNDED_CURVE"),
945 CurveImpl::BoundedPcurve(_) => CurveKind::Other("BOUNDED_PCURVE"),
946 CurveImpl::BoundedSurfaceCurve(i) => {
947 CurveKind::BoundedSurfaceCurve(model.bounded_surface_curve_arena.get(i.0))
948 }
949 CurveImpl::CompositeCurve(i) => {
950 CurveKind::Composite(model.composite_curve_arena.get(i.0))
951 }
952 CurveImpl::Conic(_) => CurveKind::Other("CONIC"),
953 CurveImpl::Curve(_) => CurveKind::Other("CURVE"),
954 CurveImpl::Hyperbola(_) => CurveKind::Other("HYPERBOLA"),
955 CurveImpl::IntersectionCurve(i) => {
956 CurveKind::IntersectionCurve(model.intersection_curve_arena.get(i.0))
957 }
958 CurveImpl::Pcurve(_) => CurveKind::Other("PCURVE"),
959 CurveImpl::Polyline(i) => CurveKind::Polyline(model.polyline_arena.get(i.0)),
960 CurveImpl::QuasiUniformCurve(i) => {
961 CurveKind::QuasiUniform(model.quasi_uniform_curve_arena.get(i.0))
962 }
963 CurveImpl::RationalBSplineCurve(_) => CurveKind::Other("RATIONAL_B_SPLINE_CURVE"),
964 CurveImpl::SeamCurve(i) => CurveKind::SeamCurve(model.seam_curve_arena.get(i.0)),
965 CurveImpl::SurfaceCurve(i) => {
966 CurveKind::SurfaceCurve(model.surface_curve_arena.get(i.0))
967 }
968 CurveImpl::UniformCurve(i) => CurveKind::Uniform(model.uniform_curve_arena.get(i.0)),
969 CurveImpl::Complex(_) => CurveKind::Other("COMPLEX"),
970 }
971 }
972}
973
974#[derive(Clone, Copy)]
980pub struct Vertex<'m> {
981 cx: Ctx<'m>,
982 id: m::VertexPointId,
983}
984
985impl<'m> Vertex<'m> {
986 fn from_ref(cx: Ctx<'m>, r: &m::VertexRef) -> Option<Self> {
987 match r {
988 m::VertexRef::VertexPoint(i) => Some(Vertex { cx, id: *i }),
989 m::VertexRef::Vertex(_) | m::VertexRef::Complex(_) => None,
990 }
991 }
992
993 pub fn key(&self) -> m::EntityKey {
995 m::EntityKey::VertexPoint(self.id)
996 }
997
998 pub fn point(&self) -> Option<Point<'m>> {
1000 let r = &self
1001 .cx
1002 .model
1003 .vertex_point_arena
1004 .get(self.id.0)
1005 .vertex_geometry;
1006 match r {
1007 m::PointRef::CartesianPoint(i) => Some(Point {
1008 cx: self.cx,
1009 id: *i,
1010 }),
1011 m::PointRef::ApllPoint(_)
1012 | m::PointRef::ApllPointWithSurface(_)
1013 | m::PointRef::Point(_)
1014 | m::PointRef::Complex(_) => None,
1015 }
1016 }
1017
1018 pub fn edges(&self) -> impl Iterator<Item = Edge<'m>> + 'm {
1022 let cx = self.cx;
1023 let rg = cx.ref_graph();
1024 let mut out: Vec<Edge<'m>> = Vec::new();
1025 for &r in rg.referrers(m::EntityKey::VertexPoint(self.id)) {
1026 if let m::EntityKey::EdgeCurve(eid) = r {
1027 if !out.iter().any(|e| e.id == eid) {
1028 out.push(Edge { cx, id: eid });
1029 }
1030 }
1031 }
1032 out.into_iter()
1033 }
1034}
1035
1036#[derive(Clone, Copy)]
1038pub struct Point<'m> {
1039 cx: Ctx<'m>,
1040 id: m::CartesianPointId,
1041}
1042
1043impl<'m> Point<'m> {
1044 pub(crate) fn from_id(cx: Ctx<'m>, id: m::CartesianPointId) -> Self {
1047 Point { cx, id }
1048 }
1049
1050 pub fn key(&self) -> m::EntityKey {
1052 m::EntityKey::CartesianPoint(self.id)
1053 }
1054
1055 pub fn xyz(&self) -> [f64; 3] {
1059 let c = self.coords();
1060 [
1061 c.first().copied().unwrap_or(0.0),
1062 c.get(1).copied().unwrap_or(0.0),
1063 c.get(2).copied().unwrap_or(0.0),
1064 ]
1065 }
1066
1067 pub fn coords(&self) -> &'m [f64] {
1068 &self
1069 .cx
1070 .model
1071 .cartesian_point_arena
1072 .get(self.id.0)
1073 .coordinates
1074 }
1075}
1076
1077fn closed_shell_to_solid(rg: &RefGraph, cs: m::ClosedShellId) -> Option<SolidImpl> {
1086 for &r in rg.referrers(m::EntityKey::ClosedShell(cs)) {
1087 match r {
1088 m::EntityKey::ManifoldSolidBrep(msb) => return Some(SolidImpl::Manifold(msb)),
1089 m::EntityKey::BrepWithVoids(bwv) => return Some(SolidImpl::WithVoids(bwv)),
1090 m::EntityKey::OrientedClosedShell(ocs) => {
1091 for &r2 in rg.referrers(m::EntityKey::OrientedClosedShell(ocs)) {
1092 match r2 {
1093 m::EntityKey::ManifoldSolidBrep(msb) => {
1094 return Some(SolidImpl::Manifold(msb));
1095 }
1096 m::EntityKey::BrepWithVoids(bwv) => return Some(SolidImpl::WithVoids(bwv)),
1097 _ => {}
1098 }
1099 }
1100 }
1101 _ => {}
1102 }
1103 }
1104 None
1105}
1106
1107fn resolve_closed_shell<'m>(
1110 model: &'m StepModel,
1111 r: &m::ClosedShellRef,
1112) -> Option<&'m m::ClosedShell> {
1113 match r {
1114 m::ClosedShellRef::ClosedShell(i) => Some(model.closed_shell_arena.get(i.0)),
1115 m::ClosedShellRef::OrientedClosedShell(i) => {
1116 let oc = model.oriented_closed_shell_arena.get(i.0);
1117 resolve_closed_shell(model, &oc.closed_shell_element)
1118 }
1119 m::ClosedShellRef::Complex(_) => None,
1120 }
1121}
1122
1123fn resolve_edge_loop<'m>(model: &'m StepModel, r: &m::LoopRef) -> Option<&'m m::EdgeLoop> {
1125 match r {
1126 m::LoopRef::EdgeLoop(i) => Some(model.edge_loop_arena.get(i.0)),
1127 m::LoopRef::Loop(_)
1128 | m::LoopRef::PolyLoop(_)
1129 | m::LoopRef::VertexLoop(_)
1130 | m::LoopRef::Complex(_) => None,
1131 }
1132}
1133
1134fn resolve_oriented_edge<'m>(
1136 model: &'m StepModel,
1137 r: &m::OrientedEdgeRef,
1138) -> Option<&'m m::OrientedEdge> {
1139 match r {
1140 m::OrientedEdgeRef::OrientedEdge(i) => Some(model.oriented_edge_arena.get(i.0)),
1141 m::OrientedEdgeRef::Complex(_) => None,
1142 }
1143}