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<'_>> + '_ {
28 let cx = self.ctx();
29 (0..cx.model.manifold_solid_brep_arena.items.len()).map(move |i| Solid {
30 cx,
31 id: m::ManifoldSolidBrepId(i),
32 })
33 }
34
35 pub fn all_faces(&self) -> impl Iterator<Item = Face<'_>> + '_ {
37 let cx = self.ctx();
38 let advanced = (0..cx.model.advanced_face_arena.items.len()).map(move |i| Face {
39 cx,
40 which: FaceImpl::Advanced(m::AdvancedFaceId(i)),
41 });
42 let surfaces = (0..cx.model.face_surface_arena.items.len()).map(move |i| Face {
43 cx,
44 which: FaceImpl::Surface(m::FaceSurfaceId(i)),
45 });
46 advanced.chain(surfaces)
47 }
48
49 pub fn all_edges(&self) -> impl Iterator<Item = Edge<'_>> + '_ {
51 let cx = self.ctx();
52 (0..cx.model.edge_curve_arena.items.len()).map(move |i| Edge {
53 cx,
54 id: m::EdgeCurveId(i),
55 })
56 }
57
58 pub fn all_vertices(&self) -> impl Iterator<Item = Vertex<'_>> + '_ {
60 let cx = self.ctx();
61 (0..cx.model.vertex_point_arena.items.len()).map(move |i| Vertex {
62 cx,
63 id: m::VertexPointId(i),
64 })
65 }
66
67 pub fn all_points(&self) -> impl Iterator<Item = Point<'_>> + '_ {
69 let cx = self.ctx();
70 (0..cx.model.cartesian_point_arena.items.len()).map(move |i| Point {
71 cx,
72 id: m::CartesianPointId(i),
73 })
74 }
75}
76
77#[derive(Clone, Copy)]
83pub struct Solid<'m> {
84 cx: Ctx<'m>,
85 id: m::ManifoldSolidBrepId,
86}
87
88impl<'m> Solid<'m> {
89 pub(crate) fn from_id(cx: Ctx<'m>, id: m::ManifoldSolidBrepId) -> Self {
92 Solid { cx, id }
93 }
94
95 fn raw(&self) -> &'m m::ManifoldSolidBrep {
96 self.cx.model.manifold_solid_brep_arena.get(self.id.0)
97 }
98
99 pub fn name(&self) -> &'m str {
100 &self.raw().name
101 }
102
103 pub fn key(&self) -> m::EntityKey {
106 m::EntityKey::ManifoldSolidBrep(self.id)
107 }
108
109 pub fn color(&self) -> Option<crate::scene::presentation::Rgb> {
111 crate::scene::presentation::colour_of(self.cx, self.key())
112 }
113
114 pub fn transparency(&self) -> Option<f64> {
117 crate::scene::presentation::transparency_of(self.cx, self.key())
118 }
119
120 pub fn layer(&self) -> Option<&'m str> {
122 crate::scene::presentation::layer_of(self.cx, self.key())
123 }
124
125 pub fn is_visible(&self) -> bool {
128 crate::scene::presentation::is_visible(self.cx, self.key())
129 }
130
131 pub fn faces(&self) -> impl Iterator<Item = Face<'m>> + 'm {
133 let cx = self.cx;
134 resolve_closed_shell(cx.model, &self.raw().outer)
135 .into_iter()
136 .flat_map(|shell| shell.cfs_faces.iter())
137 .filter_map(move |fr| Face::from_ref(cx, fr))
138 }
139}
140
141#[derive(Clone, Copy)]
146enum FaceImpl {
147 Advanced(m::AdvancedFaceId),
148 Surface(m::FaceSurfaceId),
149}
150
151#[derive(Clone, Copy)]
154pub struct Face<'m> {
155 cx: Ctx<'m>,
156 which: FaceImpl,
157}
158
159impl<'m> Face<'m> {
160 pub(crate) fn from_advanced_face(cx: Ctx<'m>, id: m::AdvancedFaceId) -> Self {
163 Face {
164 cx,
165 which: FaceImpl::Advanced(id),
166 }
167 }
168
169 fn from_ref(cx: Ctx<'m>, r: &m::FaceRef) -> Option<Self> {
170 match r {
171 m::FaceRef::AdvancedFace(i) => Some(Face {
172 cx,
173 which: FaceImpl::Advanced(*i),
174 }),
175 m::FaceRef::FaceSurface(i) => Some(Face {
176 cx,
177 which: FaceImpl::Surface(*i),
178 }),
179 m::FaceRef::Face(_) | m::FaceRef::Complex(_) => None,
181 }
182 }
183
184 fn parts(&self) -> (&'m str, &'m [m::FaceBoundRef], &'m m::SurfaceRef, bool) {
187 match self.which {
188 FaceImpl::Advanced(i) => {
189 let f = self.cx.model.advanced_face_arena.get(i.0);
190 (&f.name, &f.bounds, &f.face_geometry, f.same_sense)
191 }
192 FaceImpl::Surface(i) => {
193 let f = self.cx.model.face_surface_arena.get(i.0);
194 (&f.name, &f.bounds, &f.face_geometry, f.same_sense)
195 }
196 }
197 }
198
199 pub fn name(&self) -> &'m str {
200 self.parts().0
201 }
202
203 pub fn same_sense(&self) -> bool {
204 self.parts().3
205 }
206
207 pub fn surface(&self) -> Surface<'m> {
209 Surface {
210 cx: self.cx,
211 r: self.parts().2,
212 }
213 }
214
215 pub fn bounds(&self) -> impl Iterator<Item = Bound<'m>> + 'm {
217 let cx = self.cx;
218 self.parts()
219 .1
220 .iter()
221 .filter_map(move |br| Bound::from_ref(cx, br))
222 }
223
224 fn boundary_points(&self) -> Vec<[f64; 3]> {
231 let mut points = Vec::new();
232 for bound in self.bounds() {
233 for edge in bound.edges() {
234 if let Some(n) = edge.to_nurbs() {
235 points.extend(n.control_points);
236 } else {
237 for v in [edge.start(), edge.end()].into_iter().flatten() {
238 if let Some(pt) = v.point() {
239 points.push(pt.xyz());
240 }
241 }
242 }
243 }
244 }
245 points
246 }
247
248 pub fn to_nurbs(&self) -> Option<crate::scene::nurbs::NurbsSurface> {
256 if let Some(n) = self.surface().to_nurbs() {
257 return Some(n);
258 }
259 let cx = self.cx;
260 let pts = self.boundary_points();
261 match self.surface().kind() {
262 SurfaceKind::Plane(p) => crate::scene::nurbs::plane_patch(cx, p, &pts),
263 SurfaceKind::Cylindrical(c) => {
264 crate::scene::nurbs::cylinder_cone_patch(cx, &c.position, c.radius, 0.0, &pts)
265 }
266 SurfaceKind::Conical(c) => crate::scene::nurbs::cylinder_cone_patch(
267 cx,
268 &c.position,
269 c.radius,
270 c.semi_angle,
271 &pts,
272 ),
273 SurfaceKind::LinearExtrusion(s) => {
274 let profile = Curve::from_curve_ref(cx, &s.swept_curve).to_nurbs()?;
275 crate::scene::nurbs::extrude_patch(cx, &profile, &s.extrusion_axis, &pts)
276 }
277 SurfaceKind::Revolution(s) => {
282 let CurveKind::Line(line) = Curve::from_curve_ref(cx, &s.swept_curve).kind() else {
283 return None;
284 };
285 let frame = crate::scene::nurbs::axis1_frame(cx, &s.axis_position)?;
286 let seg = crate::scene::nurbs::revolved_line_segment(cx, line, frame, &pts)?;
287 Some(crate::scene::nurbs::revolve_curve(&seg, frame))
288 }
289 _ => None,
290 }
291 }
292
293 pub fn key(&self) -> m::EntityKey {
296 match self.which {
297 FaceImpl::Advanced(i) => m::EntityKey::AdvancedFace(i),
298 FaceImpl::Surface(i) => m::EntityKey::FaceSurface(i),
299 }
300 }
301
302 pub fn color(&self) -> Option<crate::scene::presentation::Rgb> {
304 crate::scene::presentation::colour_of(self.cx, self.key())
305 }
306
307 pub fn transparency(&self) -> Option<f64> {
310 crate::scene::presentation::transparency_of(self.cx, self.key())
311 }
312
313 pub fn layer(&self) -> Option<&'m str> {
315 crate::scene::presentation::layer_of(self.cx, self.key())
316 }
317
318 pub fn is_visible(&self) -> bool {
321 crate::scene::presentation::is_visible(self.cx, self.key())
322 }
323
324 pub fn solid(&self) -> Option<Solid<'m>> {
328 let rg = self.cx.ref_graph();
329 for &r in rg.referrers(self.key()) {
330 if let m::EntityKey::ClosedShell(cs) = r {
331 if let Some(msb) = closed_shell_to_solid(rg, cs) {
332 return Some(Solid::from_id(self.cx, msb));
333 }
334 }
335 }
336 None
337 }
338}
339
340#[derive(Clone, Copy)]
346pub struct Surface<'m> {
347 cx: Ctx<'m>,
348 r: &'m m::SurfaceRef,
349}
350
351#[derive(Clone, Copy, Debug)]
354pub enum SurfaceKind<'m> {
355 Plane(&'m m::Plane),
356 Cylindrical(&'m m::CylindricalSurface),
357 Conical(&'m m::ConicalSurface),
358 Spherical(&'m m::SphericalSurface),
359 Toroidal(&'m m::ToroidalSurface),
360 BSpline(&'m m::BSplineSurface),
361 BSplineWithKnots(&'m m::BSplineSurfaceWithKnots),
362 LinearExtrusion(&'m m::SurfaceOfLinearExtrusion),
363 Revolution(&'m m::SurfaceOfRevolution),
364 QuasiUniform(&'m m::QuasiUniformSurface),
365 Uniform(&'m m::UniformSurface),
366 Bezier(&'m m::BezierSurface),
367 Other(&'static str),
368}
369
370impl<'m> Surface<'m> {
371 pub fn key(&self) -> m::EntityKey {
374 self.r.entity_key()
375 }
376
377 pub fn to_nurbs(&self) -> Option<crate::scene::nurbs::NurbsSurface> {
383 let cx = self.cx;
384 match self.r {
385 m::SurfaceRef::SphericalSurface(i) => {
386 crate::scene::nurbs::sphere_to_nurbs(cx, cx.model.spherical_surface_arena.get(i.0))
387 }
388 m::SurfaceRef::ToroidalSurface(i) => {
389 crate::scene::nurbs::torus_to_nurbs(cx, cx.model.toroidal_surface_arena.get(i.0))
390 }
391 m::SurfaceRef::BSplineSurfaceWithKnots(i) => {
392 crate::scene::nurbs::bspline_surf_wk_to_nurbs(
393 cx,
394 cx.model.b_spline_surface_with_knots_arena.get(i.0),
395 )
396 }
397 m::SurfaceRef::Complex(i) => crate::scene::nurbs::complex_bspline_surface_to_nurbs(
399 cx,
400 &cx.model.complex_unit_arena.get(i.0).parts,
401 ),
402 m::SurfaceRef::SurfaceOfRevolution(i) => {
405 let s = cx.model.surface_of_revolution_arena.get(i.0);
406 let profile = Curve::from_curve_ref(cx, &s.swept_curve).to_nurbs()?;
407 let frame = crate::scene::nurbs::axis1_frame(cx, &s.axis_position)?;
408 Some(crate::scene::nurbs::revolve_curve(&profile, frame))
409 }
410 m::SurfaceRef::UniformSurface(i) => {
412 let s = cx.model.uniform_surface_arena.get(i.0);
413 crate::scene::nurbs::uniform_family_surface_to_nurbs(
414 cx,
415 (s.u_degree, s.v_degree),
416 &s.control_points_list,
417 crate::scene::nurbs::KnotFamily::Uniform,
418 )
419 }
420 m::SurfaceRef::QuasiUniformSurface(i) => {
421 let s = cx.model.quasi_uniform_surface_arena.get(i.0);
422 crate::scene::nurbs::uniform_family_surface_to_nurbs(
423 cx,
424 (s.u_degree, s.v_degree),
425 &s.control_points_list,
426 crate::scene::nurbs::KnotFamily::QuasiUniform,
427 )
428 }
429 m::SurfaceRef::BezierSurface(i) => {
430 let s = cx.model.bezier_surface_arena.get(i.0);
431 crate::scene::nurbs::uniform_family_surface_to_nurbs(
432 cx,
433 (s.u_degree, s.v_degree),
434 &s.control_points_list,
435 crate::scene::nurbs::KnotFamily::Bezier,
436 )
437 }
438 _ => None,
439 }
440 }
441
442 pub fn kind(&self) -> SurfaceKind<'m> {
443 let model = self.cx.model;
444 match self.r {
445 m::SurfaceRef::Plane(i) => SurfaceKind::Plane(model.plane_arena.get(i.0)),
446 m::SurfaceRef::CylindricalSurface(i) => {
447 SurfaceKind::Cylindrical(model.cylindrical_surface_arena.get(i.0))
448 }
449 m::SurfaceRef::ConicalSurface(i) => {
450 SurfaceKind::Conical(model.conical_surface_arena.get(i.0))
451 }
452 m::SurfaceRef::SphericalSurface(i) => {
453 SurfaceKind::Spherical(model.spherical_surface_arena.get(i.0))
454 }
455 m::SurfaceRef::ToroidalSurface(i) => {
456 SurfaceKind::Toroidal(model.toroidal_surface_arena.get(i.0))
457 }
458 m::SurfaceRef::BSplineSurface(i) => {
459 SurfaceKind::BSpline(model.b_spline_surface_arena.get(i.0))
460 }
461 m::SurfaceRef::BSplineSurfaceWithKnots(i) => {
462 SurfaceKind::BSplineWithKnots(model.b_spline_surface_with_knots_arena.get(i.0))
463 }
464 m::SurfaceRef::BezierSurface(i) => {
465 SurfaceKind::Bezier(model.bezier_surface_arena.get(i.0))
466 }
467 m::SurfaceRef::BoundedSurface(_) => SurfaceKind::Other("BOUNDED_SURFACE"),
468 m::SurfaceRef::DegenerateToroidalSurface(_) => {
469 SurfaceKind::Other("DEGENERATE_TOROIDAL_SURFACE")
470 }
471 m::SurfaceRef::ElementarySurface(_) => SurfaceKind::Other("ELEMENTARY_SURFACE"),
472 m::SurfaceRef::OffsetSurface(_) => SurfaceKind::Other("OFFSET_SURFACE"),
473 m::SurfaceRef::QuasiUniformSurface(i) => {
474 SurfaceKind::QuasiUniform(model.quasi_uniform_surface_arena.get(i.0))
475 }
476 m::SurfaceRef::RationalBSplineSurface(_) => {
477 SurfaceKind::Other("RATIONAL_B_SPLINE_SURFACE")
478 }
479 m::SurfaceRef::Surface(_) => SurfaceKind::Other("SURFACE"),
480 m::SurfaceRef::SurfaceOfLinearExtrusion(i) => {
481 SurfaceKind::LinearExtrusion(model.surface_of_linear_extrusion_arena.get(i.0))
482 }
483 m::SurfaceRef::SurfaceOfRevolution(i) => {
484 SurfaceKind::Revolution(model.surface_of_revolution_arena.get(i.0))
485 }
486 m::SurfaceRef::SweptSurface(_) => SurfaceKind::Other("SWEPT_SURFACE"),
487 m::SurfaceRef::UniformSurface(i) => {
488 SurfaceKind::Uniform(model.uniform_surface_arena.get(i.0))
489 }
490 m::SurfaceRef::Complex(_) => SurfaceKind::Other("COMPLEX"),
491 }
492 }
493}
494
495#[derive(Clone, Copy)]
500enum BoundImpl {
501 Inner(m::FaceBoundId),
502 Outer(m::FaceOuterBoundId),
503}
504
505#[derive(Clone, Copy)]
507pub struct Bound<'m> {
508 cx: Ctx<'m>,
509 which: BoundImpl,
510}
511
512impl<'m> Bound<'m> {
513 fn from_ref(cx: Ctx<'m>, r: &m::FaceBoundRef) -> Option<Self> {
514 match r {
515 m::FaceBoundRef::FaceBound(i) => Some(Bound {
516 cx,
517 which: BoundImpl::Inner(*i),
518 }),
519 m::FaceBoundRef::FaceOuterBound(i) => Some(Bound {
520 cx,
521 which: BoundImpl::Outer(*i),
522 }),
523 m::FaceBoundRef::Complex(_) => None,
524 }
525 }
526
527 pub fn is_outer(&self) -> bool {
529 matches!(self.which, BoundImpl::Outer(_))
530 }
531
532 pub fn key(&self) -> m::EntityKey {
534 match self.which {
535 BoundImpl::Inner(i) => m::EntityKey::FaceBound(i),
536 BoundImpl::Outer(i) => m::EntityKey::FaceOuterBound(i),
537 }
538 }
539
540 fn loop_ref(&self) -> &'m m::LoopRef {
541 match self.which {
542 BoundImpl::Inner(i) => &self.cx.model.face_bound_arena.get(i.0).bound,
543 BoundImpl::Outer(i) => &self.cx.model.face_outer_bound_arena.get(i.0).bound,
544 }
545 }
546
547 pub fn orientation(&self) -> bool {
553 match self.which {
554 BoundImpl::Inner(i) => self.cx.model.face_bound_arena.get(i.0).orientation,
555 BoundImpl::Outer(i) => self.cx.model.face_outer_bound_arena.get(i.0).orientation,
556 }
557 }
558
559 pub fn edges(&self) -> impl Iterator<Item = Edge<'m>> + 'm {
563 self.oriented_edges().map(|(e, _)| e)
564 }
565
566 pub fn oriented_edges(&self) -> impl Iterator<Item = (Edge<'m>, bool)> + 'm {
571 let cx = self.cx;
572 resolve_edge_loop(cx.model, self.loop_ref())
573 .into_iter()
574 .flat_map(|el| el.edge_list.iter())
575 .filter_map(move |oer| {
576 let oe = resolve_oriented_edge(cx.model, oer)?;
577 Some((Edge::from_edge_ref(cx, &oe.edge_element)?, oe.orientation))
578 })
579 }
580}
581
582#[derive(Clone, Copy)]
588pub struct Edge<'m> {
589 cx: Ctx<'m>,
590 id: m::EdgeCurveId,
591}
592
593impl<'m> Edge<'m> {
594 pub(crate) fn from_id(cx: Ctx<'m>, id: m::EdgeCurveId) -> Self {
597 Edge { cx, id }
598 }
599
600 fn from_edge_ref(cx: Ctx<'m>, r: &m::EdgeRef) -> Option<Self> {
601 match r {
602 m::EdgeRef::EdgeCurve(i) => Some(Edge { cx, id: *i }),
603 m::EdgeRef::Edge(_) | m::EdgeRef::OrientedEdge(_) | m::EdgeRef::Complex(_) => None,
605 }
606 }
607
608 fn raw(&self) -> &'m m::EdgeCurve {
609 self.cx.model.edge_curve_arena.get(self.id.0)
610 }
611
612 pub fn key(&self) -> m::EntityKey {
615 m::EntityKey::EdgeCurve(self.id)
616 }
617
618 pub fn start(&self) -> Option<Vertex<'m>> {
619 Vertex::from_ref(self.cx, &self.raw().edge_start)
620 }
621
622 pub fn end(&self) -> Option<Vertex<'m>> {
623 Vertex::from_ref(self.cx, &self.raw().edge_end)
624 }
625
626 pub fn curve(&self) -> Curve<'m> {
628 Curve::from_curve_ref(self.cx, &self.raw().edge_geometry)
629 }
630
631 pub fn same_sense(&self) -> bool {
636 self.raw().same_sense
637 }
638
639 pub fn to_nurbs(&self) -> Option<crate::scene::nurbs::NurbsCurve> {
646 let cx = self.cx;
647 let coords = |v: Option<Vertex<'m>>| Some(v?.point()?.xyz());
648 let (Some(p0), Some(p1)) = (coords(self.start()), coords(self.end())) else {
649 cx.warn("EDGE_CURVE.to_nurbs: unresolved edge vertex".to_owned());
650 return None;
651 };
652 let raw = self.raw();
653 crate::scene::nurbs::edge_to_nurbs(cx, &raw.edge_geometry, p0, p1, raw.same_sense)
654 }
655}
656
657#[derive(Clone, Copy)]
664pub struct Curve<'m> {
665 cx: Ctx<'m>,
666 which: CurveImpl,
667}
668
669#[derive(Clone, Copy, Debug)]
672pub enum CurveKind<'m> {
673 Line(&'m m::Line),
674 Circle(&'m m::Circle),
675 Ellipse(&'m m::Ellipse),
676 BSpline(&'m m::BSplineCurve),
677 BSplineWithKnots(&'m m::BSplineCurveWithKnots),
678 Trimmed(&'m m::TrimmedCurve),
679 Polyline(&'m m::Polyline),
680 Composite(&'m m::CompositeCurve),
681 QuasiUniform(&'m m::QuasiUniformCurve),
682 Uniform(&'m m::UniformCurve),
683 Bezier(&'m m::BezierCurve),
684 SurfaceCurve(&'m m::SurfaceCurve),
685 SeamCurve(&'m m::SeamCurve),
686 BoundedSurfaceCurve(&'m m::BoundedSurfaceCurve),
687 IntersectionCurve(&'m m::IntersectionCurve),
688 Other(&'static str),
689}
690
691macro_rules! curve_impl {
697 ($( $V:ident, $id:ident );+ $(;)?) => {
698 #[derive(Clone, Copy)]
699 enum CurveImpl {
700 $( $V(m::$id), )+
701 Complex(m::ComplexUnitId),
702 }
703
704 impl<'m> Curve<'m> {
705 pub fn key(&self) -> m::EntityKey {
708 match self.which {
709 $( CurveImpl::$V(i) => m::EntityKey::$V(i), )+
710 CurveImpl::Complex(i) => m::EntityKey::ComplexUnit(i),
711 }
712 }
713
714 pub(crate) fn from_curve_ref(cx: Ctx<'m>, r: &m::CurveRef) -> Self {
715 let which = match r {
716 $( m::CurveRef::$V(i) => CurveImpl::$V(*i), )+
717 m::CurveRef::Complex(i) => CurveImpl::Complex(*i),
718 };
719 Curve { cx, which }
720 }
721
722 pub(crate) fn from_model_item(
725 cx: Ctx<'m>,
726 r: &m::GeometricModelItemRef,
727 ) -> Option<Self> {
728 let which = match r {
729 $( m::GeometricModelItemRef::$V(i) => CurveImpl::$V(*i), )+
730 _ => return None,
731 };
732 Some(Curve { cx, which })
733 }
734 }
735 };
736}
737
738curve_impl! {
739 BSplineCurve, BSplineCurveId;
740 BSplineCurveWithKnots, BSplineCurveWithKnotsId;
741 BezierCurve, BezierCurveId;
742 BoundedCurve, BoundedCurveId;
743 BoundedPcurve, BoundedPcurveId;
744 BoundedSurfaceCurve, BoundedSurfaceCurveId;
745 Circle, CircleId;
746 CompositeCurve, CompositeCurveId;
747 Conic, ConicId;
748 Curve, CurveId;
749 Ellipse, EllipseId;
750 Hyperbola, HyperbolaId;
751 IntersectionCurve, IntersectionCurveId;
752 Line, LineId;
753 Pcurve, PcurveId;
754 Polyline, PolylineId;
755 QuasiUniformCurve, QuasiUniformCurveId;
756 RationalBSplineCurve, RationalBSplineCurveId;
757 SeamCurve, SeamCurveId;
758 SurfaceCurve, SurfaceCurveId;
759 TrimmedCurve, TrimmedCurveId;
760 UniformCurve, UniformCurveId;
761}
762
763impl<'m> Curve<'m> {
764 pub fn color(&self) -> Option<crate::scene::presentation::Rgb> {
766 crate::scene::presentation::curve_colour_of(self.cx, self.key())
767 }
768
769 pub fn width(&self) -> Option<f64> {
772 crate::scene::presentation::curve_width_of(self.cx, self.key())
773 }
774
775 pub fn line_font(&self) -> Option<&'m str> {
778 crate::scene::presentation::curve_font_of(self.cx, self.key())
779 }
780
781 pub fn to_nurbs(&self) -> Option<crate::scene::nurbs::NurbsCurve> {
788 let cx = self.cx;
789 match self.which {
790 CurveImpl::Circle(i) => {
791 crate::scene::nurbs::circle_to_nurbs(cx, cx.model.circle_arena.get(i.0))
792 }
793 CurveImpl::Ellipse(i) => {
794 crate::scene::nurbs::ellipse_to_nurbs(cx, cx.model.ellipse_arena.get(i.0))
795 }
796 CurveImpl::BSplineCurveWithKnots(i) => crate::scene::nurbs::bspline_wk_to_nurbs(
797 cx,
798 cx.model.b_spline_curve_with_knots_arena.get(i.0),
799 ),
800 CurveImpl::Complex(i) => crate::scene::nurbs::complex_bspline_curve_to_nurbs(
802 cx,
803 &cx.model.complex_unit_arena.get(i.0).parts,
804 ),
805 CurveImpl::TrimmedCurve(i) => {
807 crate::scene::nurbs::trimmed_to_nurbs(cx, cx.model.trimmed_curve_arena.get(i.0))
808 }
809 CurveImpl::UniformCurve(i) => {
811 let c = cx.model.uniform_curve_arena.get(i.0);
812 crate::scene::nurbs::uniform_family_curve_to_nurbs(
813 cx,
814 c.degree,
815 &c.control_points_list,
816 crate::scene::nurbs::KnotFamily::Uniform,
817 )
818 }
819 CurveImpl::QuasiUniformCurve(i) => {
820 let c = cx.model.quasi_uniform_curve_arena.get(i.0);
821 crate::scene::nurbs::uniform_family_curve_to_nurbs(
822 cx,
823 c.degree,
824 &c.control_points_list,
825 crate::scene::nurbs::KnotFamily::QuasiUniform,
826 )
827 }
828 CurveImpl::BezierCurve(i) => {
829 let c = cx.model.bezier_curve_arena.get(i.0);
830 crate::scene::nurbs::uniform_family_curve_to_nurbs(
831 cx,
832 c.degree,
833 &c.control_points_list,
834 crate::scene::nurbs::KnotFamily::Bezier,
835 )
836 }
837 CurveImpl::Polyline(i) => {
838 crate::scene::nurbs::polyline_to_nurbs(cx, cx.model.polyline_arena.get(i.0))
839 }
840 CurveImpl::CompositeCurve(i) => {
842 crate::scene::nurbs::composite_to_nurbs(cx, cx.model.composite_curve_arena.get(i.0))
843 }
844 CurveImpl::SurfaceCurve(i) => crate::scene::nurbs::surface_curve_3d_to_nurbs(
846 cx,
847 &cx.model.surface_curve_arena.get(i.0).curve_3d,
848 ),
849 CurveImpl::SeamCurve(i) => crate::scene::nurbs::surface_curve_3d_to_nurbs(
850 cx,
851 &cx.model.seam_curve_arena.get(i.0).curve_3d,
852 ),
853 CurveImpl::BoundedSurfaceCurve(i) => crate::scene::nurbs::surface_curve_3d_to_nurbs(
854 cx,
855 &cx.model.bounded_surface_curve_arena.get(i.0).curve_3d,
856 ),
857 CurveImpl::IntersectionCurve(i) => crate::scene::nurbs::surface_curve_3d_to_nurbs(
858 cx,
859 &cx.model.intersection_curve_arena.get(i.0).curve_3d,
860 ),
861 _ => None,
862 }
863 }
864
865 pub fn kind(&self) -> CurveKind<'m> {
866 let model = self.cx.model;
867 match self.which {
868 CurveImpl::Line(i) => CurveKind::Line(model.line_arena.get(i.0)),
869 CurveImpl::Circle(i) => CurveKind::Circle(model.circle_arena.get(i.0)),
870 CurveImpl::Ellipse(i) => CurveKind::Ellipse(model.ellipse_arena.get(i.0)),
871 CurveImpl::BSplineCurve(i) => CurveKind::BSpline(model.b_spline_curve_arena.get(i.0)),
872 CurveImpl::BSplineCurveWithKnots(i) => {
873 CurveKind::BSplineWithKnots(model.b_spline_curve_with_knots_arena.get(i.0))
874 }
875 CurveImpl::TrimmedCurve(i) => CurveKind::Trimmed(model.trimmed_curve_arena.get(i.0)),
876 CurveImpl::BezierCurve(i) => CurveKind::Bezier(model.bezier_curve_arena.get(i.0)),
877 CurveImpl::BoundedCurve(_) => CurveKind::Other("BOUNDED_CURVE"),
878 CurveImpl::BoundedPcurve(_) => CurveKind::Other("BOUNDED_PCURVE"),
879 CurveImpl::BoundedSurfaceCurve(i) => {
880 CurveKind::BoundedSurfaceCurve(model.bounded_surface_curve_arena.get(i.0))
881 }
882 CurveImpl::CompositeCurve(i) => {
883 CurveKind::Composite(model.composite_curve_arena.get(i.0))
884 }
885 CurveImpl::Conic(_) => CurveKind::Other("CONIC"),
886 CurveImpl::Curve(_) => CurveKind::Other("CURVE"),
887 CurveImpl::Hyperbola(_) => CurveKind::Other("HYPERBOLA"),
888 CurveImpl::IntersectionCurve(i) => {
889 CurveKind::IntersectionCurve(model.intersection_curve_arena.get(i.0))
890 }
891 CurveImpl::Pcurve(_) => CurveKind::Other("PCURVE"),
892 CurveImpl::Polyline(i) => CurveKind::Polyline(model.polyline_arena.get(i.0)),
893 CurveImpl::QuasiUniformCurve(i) => {
894 CurveKind::QuasiUniform(model.quasi_uniform_curve_arena.get(i.0))
895 }
896 CurveImpl::RationalBSplineCurve(_) => CurveKind::Other("RATIONAL_B_SPLINE_CURVE"),
897 CurveImpl::SeamCurve(i) => CurveKind::SeamCurve(model.seam_curve_arena.get(i.0)),
898 CurveImpl::SurfaceCurve(i) => {
899 CurveKind::SurfaceCurve(model.surface_curve_arena.get(i.0))
900 }
901 CurveImpl::UniformCurve(i) => CurveKind::Uniform(model.uniform_curve_arena.get(i.0)),
902 CurveImpl::Complex(_) => CurveKind::Other("COMPLEX"),
903 }
904 }
905}
906
907#[derive(Clone, Copy)]
913pub struct Vertex<'m> {
914 cx: Ctx<'m>,
915 id: m::VertexPointId,
916}
917
918impl<'m> Vertex<'m> {
919 fn from_ref(cx: Ctx<'m>, r: &m::VertexRef) -> Option<Self> {
920 match r {
921 m::VertexRef::VertexPoint(i) => Some(Vertex { cx, id: *i }),
922 m::VertexRef::Vertex(_) | m::VertexRef::Complex(_) => None,
923 }
924 }
925
926 pub fn key(&self) -> m::EntityKey {
928 m::EntityKey::VertexPoint(self.id)
929 }
930
931 pub fn point(&self) -> Option<Point<'m>> {
933 let r = &self
934 .cx
935 .model
936 .vertex_point_arena
937 .get(self.id.0)
938 .vertex_geometry;
939 match r {
940 m::PointRef::CartesianPoint(i) => Some(Point {
941 cx: self.cx,
942 id: *i,
943 }),
944 m::PointRef::ApllPoint(_)
945 | m::PointRef::ApllPointWithSurface(_)
946 | m::PointRef::Point(_)
947 | m::PointRef::Complex(_) => None,
948 }
949 }
950
951 pub fn edges(&self) -> impl Iterator<Item = Edge<'m>> + 'm {
955 let cx = self.cx;
956 let rg = cx.ref_graph();
957 let mut out: Vec<Edge<'m>> = Vec::new();
958 for &r in rg.referrers(m::EntityKey::VertexPoint(self.id)) {
959 if let m::EntityKey::EdgeCurve(eid) = r {
960 if !out.iter().any(|e| e.id == eid) {
961 out.push(Edge { cx, id: eid });
962 }
963 }
964 }
965 out.into_iter()
966 }
967}
968
969#[derive(Clone, Copy)]
971pub struct Point<'m> {
972 cx: Ctx<'m>,
973 id: m::CartesianPointId,
974}
975
976impl<'m> Point<'m> {
977 pub(crate) fn from_id(cx: Ctx<'m>, id: m::CartesianPointId) -> Self {
980 Point { cx, id }
981 }
982
983 pub fn key(&self) -> m::EntityKey {
985 m::EntityKey::CartesianPoint(self.id)
986 }
987
988 pub fn xyz(&self) -> [f64; 3] {
992 let c = self.coords();
993 [
994 c.first().copied().unwrap_or(0.0),
995 c.get(1).copied().unwrap_or(0.0),
996 c.get(2).copied().unwrap_or(0.0),
997 ]
998 }
999
1000 pub fn coords(&self) -> &'m [f64] {
1001 &self
1002 .cx
1003 .model
1004 .cartesian_point_arena
1005 .get(self.id.0)
1006 .coordinates
1007 }
1008}
1009
1010fn closed_shell_to_solid(rg: &RefGraph, cs: m::ClosedShellId) -> Option<m::ManifoldSolidBrepId> {
1017 for &r in rg.referrers(m::EntityKey::ClosedShell(cs)) {
1018 match r {
1019 m::EntityKey::ManifoldSolidBrep(msb) => return Some(msb),
1020 m::EntityKey::OrientedClosedShell(ocs) => {
1021 for &r2 in rg.referrers(m::EntityKey::OrientedClosedShell(ocs)) {
1022 if let m::EntityKey::ManifoldSolidBrep(msb) = r2 {
1023 return Some(msb);
1024 }
1025 }
1026 }
1027 _ => {}
1028 }
1029 }
1030 None
1031}
1032
1033fn resolve_closed_shell<'m>(
1036 model: &'m StepModel,
1037 r: &m::ClosedShellRef,
1038) -> Option<&'m m::ClosedShell> {
1039 match r {
1040 m::ClosedShellRef::ClosedShell(i) => Some(model.closed_shell_arena.get(i.0)),
1041 m::ClosedShellRef::OrientedClosedShell(i) => {
1042 let oc = model.oriented_closed_shell_arena.get(i.0);
1043 resolve_closed_shell(model, &oc.closed_shell_element)
1044 }
1045 m::ClosedShellRef::Complex(_) => None,
1046 }
1047}
1048
1049fn resolve_edge_loop<'m>(model: &'m StepModel, r: &m::LoopRef) -> Option<&'m m::EdgeLoop> {
1051 match r {
1052 m::LoopRef::EdgeLoop(i) => Some(model.edge_loop_arena.get(i.0)),
1053 m::LoopRef::Loop(_)
1054 | m::LoopRef::PolyLoop(_)
1055 | m::LoopRef::VertexLoop(_)
1056 | m::LoopRef::Complex(_) => None,
1057 }
1058}
1059
1060fn resolve_oriented_edge<'m>(
1062 model: &'m StepModel,
1063 r: &m::OrientedEdgeRef,
1064) -> Option<&'m m::OrientedEdge> {
1065 match r {
1066 m::OrientedEdgeRef::OrientedEdge(i) => Some(model.oriented_edge_arena.get(i.0)),
1067 m::OrientedEdgeRef::Complex(_) => None,
1068 }
1069}