1#![allow(clippy::must_use_candidate)]
15
16use crate::generated::model as m;
17use crate::scene::geometry::{Curve, Edge, Face, Point, Solid};
18use crate::scene::{Ctx, Scene};
19
20#[derive(Clone, Copy, Debug, PartialEq, Eq)]
22pub enum DimensionKind {
23 Size,
25 Location,
27 AngularSize,
29 AngularLocation,
31}
32
33#[derive(Clone, Copy)]
34enum DimImpl {
35 Size(m::DimensionalSizeId),
36 Location(m::DimensionalLocationId),
37 AngularSize(m::AngularSizeId),
38 AngularLocation(m::AngularLocationId),
39}
40
41#[derive(Clone, Copy)]
44pub struct Dimension<'m> {
45 cx: Ctx<'m>,
46 which: DimImpl,
47}
48
49impl Scene<'_> {
50 pub fn dimensions(&self) -> impl Iterator<Item = Dimension<'_>> + '_ {
54 all_dimensions(self.ctx()).into_iter()
55 }
56}
57
58fn all_dimensions(cx: Ctx<'_>) -> Vec<Dimension<'_>> {
61 let mut out = Vec::new();
62 for i in 0..cx.model.dimensional_size_arena.items.len() {
63 out.push(Dimension {
64 cx,
65 which: DimImpl::Size(m::DimensionalSizeId(i)),
66 });
67 }
68 for i in 0..cx.model.dimensional_location_arena.items.len() {
69 out.push(Dimension {
70 cx,
71 which: DimImpl::Location(m::DimensionalLocationId(i)),
72 });
73 }
74 for i in 0..cx.model.angular_size_arena.items.len() {
75 out.push(Dimension {
76 cx,
77 which: DimImpl::AngularSize(m::AngularSizeId(i)),
78 });
79 }
80 for i in 0..cx.model.angular_location_arena.items.len() {
81 out.push(Dimension {
82 cx,
83 which: DimImpl::AngularLocation(m::AngularLocationId(i)),
84 });
85 }
86 out
87}
88
89impl<'m> Dimension<'m> {
90 pub fn kind(&self) -> DimensionKind {
92 match self.which {
93 DimImpl::Size(_) => DimensionKind::Size,
94 DimImpl::Location(_) => DimensionKind::Location,
95 DimImpl::AngularSize(_) => DimensionKind::AngularSize,
96 DimImpl::AngularLocation(_) => DimensionKind::AngularLocation,
97 }
98 }
99
100 pub fn name(&self) -> &'m str {
102 match self.which {
103 DimImpl::Size(i) => &self.cx.model.dimensional_size_arena.get(i.0).name,
104 DimImpl::Location(i) => &self.cx.model.dimensional_location_arena.get(i.0).name,
105 DimImpl::AngularSize(i) => &self.cx.model.angular_size_arena.get(i.0).name,
106 DimImpl::AngularLocation(i) => &self.cx.model.angular_location_arena.get(i.0).name,
107 }
108 }
109
110 pub fn key(&self) -> m::EntityKey {
112 match self.which {
113 DimImpl::Size(i) => m::EntityKey::DimensionalSize(i),
114 DimImpl::Location(i) => m::EntityKey::DimensionalLocation(i),
115 DimImpl::AngularSize(i) => m::EntityKey::AngularSize(i),
116 DimImpl::AngularLocation(i) => m::EntityKey::AngularLocation(i),
117 }
118 }
119
120 pub fn value(&self) -> Option<f64> {
131 let cx = self.cx;
132 let rg = cx.ref_graph();
133 for r in rg.referrers(self.key()) {
134 let m::EntityKey::DimensionalCharacteristicRepresentation(dcr_id) = r else {
135 continue;
136 };
137 let dcr = cx
138 .model
139 .dimensional_characteristic_representation_arena
140 .get(dcr_id.0);
141 let sdr_id = match &dcr.representation {
142 m::ShapeDimensionRepresentationRef::ShapeDimensionRepresentation(id) => id,
143 m::ShapeDimensionRepresentationRef::Complex(_) => {
144 cx.warn("dimension value representation is a complex instance".to_owned());
145 continue;
146 }
147 };
148 let sdr = cx.model.shape_dimension_representation_arena.get(sdr_id.0);
149 for item in &sdr.items {
150 if let m::RepresentationItemRef::MeasureRepresentationItem(mid) = item {
151 return Some(
152 cx.model
153 .measure_representation_item_arena
154 .get(mid.0)
155 .value_component
156 .value
157 .as_f64(),
158 );
159 }
160 }
161 }
162 None
163 }
164}
165
166#[derive(Clone, Copy, Debug, PartialEq, Eq)]
168pub enum ToleranceKind {
169 Position,
171 Flatness,
173 Straightness,
175 Roundness,
177 Cylindricity,
179 LineProfile,
181 SurfaceProfile,
183 Angularity,
185 Parallelism,
187 Perpendicularity,
189 Concentricity,
191 Coaxiality,
193 Symmetry,
195 CircularRunout,
197 TotalRunout,
199 Other,
202}
203
204#[derive(Clone, Copy)]
208pub struct Tolerance<'m> {
209 cx: Ctx<'m>,
210 which: TolImpl,
211}
212
213macro_rules! leaf_tolerances {
219 ($( $ent:ident, $id:ident, $arena:ident, $kind:ident );+ $(;)?) => {
220 #[derive(Clone, Copy)]
221 enum TolImpl {
222 $( $ent(m::$id), )+
223 Complex(m::ComplexUnitId),
224 }
225
226 fn push_dedicated_tolerances<'m>(cx: Ctx<'m>, out: &mut Vec<Tolerance<'m>>) {
227 $(
228 for i in 0..cx.model.$arena.items.len() {
229 out.push(Tolerance { cx, which: TolImpl::$ent(m::$id(i)) });
230 }
231 )+
232 }
233
234 impl<'m> Tolerance<'m> {
235 pub fn kind(&self) -> ToleranceKind {
237 match self.which {
238 $( TolImpl::$ent(_) => ToleranceKind::$kind, )+
239 TolImpl::Complex(cuid) => self.complex_kind(cuid),
240 }
241 }
242
243 pub fn key(&self) -> m::EntityKey {
245 match self.which {
246 $( TolImpl::$ent(i) => m::EntityKey::$ent(i), )+
247 TolImpl::Complex(cuid) => m::EntityKey::ComplexUnit(cuid),
248 }
249 }
250
251 fn dedicated_fields(&self) -> Option<(&'m str, Option<&'m m::LengthMeasureWithUnitRef>)> {
253 match self.which {
254 $( TolImpl::$ent(i) => {
255 let e = self.cx.model.$arena.get(i.0);
256 Some((&e.name, e.magnitude.as_ref()))
257 } )+
258 TolImpl::Complex(_) => None,
259 }
260 }
261
262 fn dedicated_target(&self) -> Option<&'m m::GeometricToleranceTargetRef> {
264 match self.which {
265 $( TolImpl::$ent(i) => {
266 Some(&self.cx.model.$arena.get(i.0).toleranced_shape_aspect)
267 } )+
268 TolImpl::Complex(_) => None,
269 }
270 }
271 }
272 };
273}
274
275leaf_tolerances! {
276 PositionTolerance, PositionToleranceId, position_tolerance_arena, Position;
277 FlatnessTolerance, FlatnessToleranceId, flatness_tolerance_arena, Flatness;
278 StraightnessTolerance, StraightnessToleranceId, straightness_tolerance_arena, Straightness;
279 RoundnessTolerance, RoundnessToleranceId, roundness_tolerance_arena, Roundness;
280 CylindricityTolerance, CylindricityToleranceId, cylindricity_tolerance_arena, Cylindricity;
281 LineProfileTolerance, LineProfileToleranceId, line_profile_tolerance_arena, LineProfile;
282 SurfaceProfileTolerance, SurfaceProfileToleranceId, surface_profile_tolerance_arena, SurfaceProfile;
283 AngularityTolerance, AngularityToleranceId, angularity_tolerance_arena, Angularity;
284 ParallelismTolerance, ParallelismToleranceId, parallelism_tolerance_arena, Parallelism;
285 PerpendicularityTolerance,PerpendicularityToleranceId,perpendicularity_tolerance_arena, Perpendicularity;
286 ConcentricityTolerance, ConcentricityToleranceId, concentricity_tolerance_arena, Concentricity;
287 CoaxialityTolerance, CoaxialityToleranceId, coaxiality_tolerance_arena, Coaxiality;
288 SymmetryTolerance, SymmetryToleranceId, symmetry_tolerance_arena, Symmetry;
289 CircularRunoutTolerance, CircularRunoutToleranceId, circular_runout_tolerance_arena, CircularRunout;
290 TotalRunoutTolerance, TotalRunoutToleranceId, total_runout_tolerance_arena, TotalRunout;
291}
292
293impl Scene<'_> {
294 pub fn tolerances(&self) -> impl Iterator<Item = Tolerance<'_>> + '_ {
298 all_tolerances(self.ctx()).into_iter()
299 }
300}
301
302fn all_tolerances(cx: Ctx<'_>) -> Vec<Tolerance<'_>> {
305 let mut out: Vec<Tolerance<'_>> = Vec::new();
306 push_dedicated_tolerances(cx, &mut out);
307 for i in 0..cx.model.complex_unit_arena.items.len() {
308 let cu = cx.model.complex_unit_arena.get(i);
309 if cu
310 .parts
311 .iter()
312 .any(|p| matches!(p, m::UnitPart::GeometricTolerance { .. }))
313 {
314 out.push(Tolerance {
315 cx,
316 which: TolImpl::Complex(m::ComplexUnitId(i)),
317 });
318 }
319 }
320 out
321}
322
323impl<'m> Tolerance<'m> {
324 pub fn name(&self) -> &'m str {
326 self.dedicated_fields()
327 .or_else(|| self.complex_geometric_tolerance())
328 .map_or("", |(name, _)| name)
329 }
330
331 pub fn magnitude(&self) -> Option<f64> {
339 let (_, mag) = self
340 .dedicated_fields()
341 .or_else(|| self.complex_geometric_tolerance())?;
342 mag.and_then(|r| length_measure_f64(self.cx, r))
343 }
344
345 fn complex_geometric_tolerance(
348 &self,
349 ) -> Option<(&'m str, Option<&'m m::LengthMeasureWithUnitRef>)> {
350 let TolImpl::Complex(cuid) = self.which else {
351 return None;
352 };
353 let cu = self.cx.model.complex_unit_arena.get(cuid.0);
354 cu.parts.iter().find_map(|p| match p {
355 m::UnitPart::GeometricTolerance {
356 name, magnitude, ..
357 } => Some((name.as_str(), magnitude.as_ref())),
358 _ => None,
359 })
360 }
361
362 fn complex_kind(&self, cuid: m::ComplexUnitId) -> ToleranceKind {
367 let cu = self.cx.model.complex_unit_arena.get(cuid.0);
368 for p in &cu.parts {
369 let kind = match p {
370 m::UnitPart::PositionTolerance => ToleranceKind::Position,
371 m::UnitPart::FlatnessTolerance => ToleranceKind::Flatness,
372 m::UnitPart::StraightnessTolerance => ToleranceKind::Straightness,
373 m::UnitPart::RoundnessTolerance => ToleranceKind::Roundness,
374 m::UnitPart::CylindricityTolerance => ToleranceKind::Cylindricity,
375 m::UnitPart::LineProfileTolerance => ToleranceKind::LineProfile,
376 m::UnitPart::SurfaceProfileTolerance => ToleranceKind::SurfaceProfile,
377 m::UnitPart::ParallelismTolerance => ToleranceKind::Parallelism,
378 m::UnitPart::PerpendicularityTolerance => ToleranceKind::Perpendicularity,
379 m::UnitPart::CircularRunoutTolerance => ToleranceKind::CircularRunout,
380 _ => continue,
381 };
382 return kind;
383 }
384 self.cx
385 .warn("geometric tolerance has no recognized characteristic subtype".to_owned());
386 ToleranceKind::Other
387 }
388}
389
390fn length_measure_f64(cx: Ctx<'_>, r: &m::LengthMeasureWithUnitRef) -> Option<f64> {
393 match r {
394 m::LengthMeasureWithUnitRef::LengthMeasureWithUnit(id) => Some(
395 cx.model
396 .length_measure_with_unit_arena
397 .get(id.0)
398 .value_component
399 .value
400 .as_f64(),
401 ),
402 m::LengthMeasureWithUnitRef::Complex(_) => {
403 cx.warn("tolerance magnitude is a complex measure instance".to_owned());
404 None
405 }
406 }
407}
408
409#[derive(Clone, Copy)]
412pub struct Datum<'m> {
413 cx: Ctx<'m>,
414 which: DatumImpl,
415}
416
417#[derive(Clone, Copy)]
418enum DatumImpl {
419 Datum(m::DatumId),
420 CommonDatum(m::CommonDatumId),
421}
422
423impl Scene<'_> {
424 pub fn datums(&self) -> impl Iterator<Item = Datum<'_>> + '_ {
428 all_datums(self.ctx()).into_iter()
429 }
430}
431
432fn all_datums(cx: Ctx<'_>) -> Vec<Datum<'_>> {
435 let mut out: Vec<Datum<'_>> = Vec::new();
436 for i in 0..cx.model.datum_arena.items.len() {
437 out.push(Datum {
438 cx,
439 which: DatumImpl::Datum(m::DatumId(i)),
440 });
441 }
442 for i in 0..cx.model.common_datum_arena.items.len() {
443 out.push(Datum {
444 cx,
445 which: DatumImpl::CommonDatum(m::CommonDatumId(i)),
446 });
447 }
448 out
449}
450
451impl<'m> Datum<'m> {
452 pub fn letter(&self) -> &'m str {
455 match self.which {
456 DatumImpl::Datum(i) => &self.cx.model.datum_arena.get(i.0).identification,
457 DatumImpl::CommonDatum(i) => &self.cx.model.common_datum_arena.get(i.0).identification,
458 }
459 }
460
461 pub fn name(&self) -> &'m str {
463 match self.which {
464 DatumImpl::Datum(i) => &self.cx.model.datum_arena.get(i.0).name,
465 DatumImpl::CommonDatum(i) => &self.cx.model.common_datum_arena.get(i.0).name,
466 }
467 }
468
469 pub fn key(&self) -> m::EntityKey {
471 match self.which {
472 DatumImpl::Datum(i) => m::EntityKey::Datum(i),
473 DatumImpl::CommonDatum(i) => m::EntityKey::CommonDatum(i),
474 }
475 }
476}
477
478impl<'m> Tolerance<'m> {
479 pub fn datums(&self) -> Vec<Datum<'m>> {
487 let mut keyed: Vec<(i64, Datum<'m>)> = Vec::new();
492 for r in self.datum_system() {
493 self.collect_system_ref(r, &mut keyed);
494 }
495 keyed.sort_by_key(|(k, _)| *k);
496 keyed.into_iter().map(|(_, d)| d).collect()
497 }
498
499 fn datum_system(&self) -> &'m [m::DatumSystemOrReferenceRef] {
503 let model = self.cx.model;
504 match self.which {
505 TolImpl::AngularityTolerance(i) => {
506 &model.angularity_tolerance_arena.get(i.0).datum_system
507 }
508 TolImpl::CircularRunoutTolerance(i) => {
509 &model.circular_runout_tolerance_arena.get(i.0).datum_system
510 }
511 TolImpl::CoaxialityTolerance(i) => {
512 &model.coaxiality_tolerance_arena.get(i.0).datum_system
513 }
514 TolImpl::ConcentricityTolerance(i) => {
515 &model.concentricity_tolerance_arena.get(i.0).datum_system
516 }
517 TolImpl::ParallelismTolerance(i) => {
518 &model.parallelism_tolerance_arena.get(i.0).datum_system
519 }
520 TolImpl::PerpendicularityTolerance(i) => {
521 &model.perpendicularity_tolerance_arena.get(i.0).datum_system
522 }
523 TolImpl::SymmetryTolerance(i) => &model.symmetry_tolerance_arena.get(i.0).datum_system,
524 TolImpl::TotalRunoutTolerance(i) => {
525 &model.total_runout_tolerance_arena.get(i.0).datum_system
526 }
527 TolImpl::Complex(cuid) => model
528 .complex_unit_arena
529 .get(cuid.0)
530 .parts
531 .iter()
532 .find_map(|p| match p {
533 m::UnitPart::GeometricToleranceWithDatumReference { datum_system } => {
534 Some(datum_system.as_slice())
535 }
536 _ => None,
537 })
538 .unwrap_or(&[]),
539 _ => &[],
540 }
541 }
542
543 fn collect_system_ref(
547 &self,
548 r: &m::DatumSystemOrReferenceRef,
549 out: &mut Vec<(i64, Datum<'m>)>,
550 ) {
551 match r {
552 m::DatumSystemOrReferenceRef::DatumReference(id) => {
553 let dr = self.cx.model.datum_reference_arena.get(id.0);
554 self.collect_datum_ref(dr.precedence, &dr.referenced_datum, out);
555 }
556 m::DatumSystemOrReferenceRef::DatumSystem(id) => {
557 let ds = self.cx.model.datum_system_arena.get(id.0);
558 for (idx, c) in ds.constituents.iter().enumerate() {
559 let m::DatumReferenceCompartmentRef::DatumReferenceCompartment(cid) = c;
560 let comp = self.cx.model.datum_reference_compartment_arena.get(cid.0);
561 let key = i64::try_from(idx).unwrap_or(i64::MAX);
562 self.collect_base(key, &comp.base, out, 0);
563 }
564 }
565 m::DatumSystemOrReferenceRef::Complex(_) => {
566 self.cx
567 .warn("tolerance datum reference is a complex instance".to_owned());
568 }
569 }
570 }
571
572 fn collect_datum_ref(&self, key: i64, r: &m::DatumRef, out: &mut Vec<(i64, Datum<'m>)>) {
574 match r {
575 m::DatumRef::Datum(id) => out.push((key, self.datum(DatumImpl::Datum(*id)))),
576 m::DatumRef::CommonDatum(id) => {
577 out.push((key, self.datum(DatumImpl::CommonDatum(*id))));
578 }
579 m::DatumRef::Complex(_) => {
580 self.cx
581 .warn("tolerance references a complex datum instance".to_owned());
582 }
583 }
584 }
585
586 fn collect_base(
589 &self,
590 key: i64,
591 r: &m::DatumOrCommonDatumRef,
592 out: &mut Vec<(i64, Datum<'m>)>,
593 depth: u32,
594 ) {
595 if depth > 8 {
596 self.cx
597 .warn("datum reference nesting is too deep to resolve".to_owned());
598 return;
599 }
600 match r {
601 m::DatumOrCommonDatumRef::Datum(id) => {
602 out.push((key, self.datum(DatumImpl::Datum(*id))));
603 }
604 m::DatumOrCommonDatumRef::CommonDatum(id) => {
605 out.push((key, self.datum(DatumImpl::CommonDatum(*id))));
606 }
607 m::DatumOrCommonDatumRef::DatumReferenceElement(id) => {
608 let e = self.cx.model.datum_reference_element_arena.get(id.0);
609 self.collect_base(key, &e.base, out, depth + 1);
610 }
611 m::DatumOrCommonDatumRef::CommonDatumList(refs) => {
612 for er in refs {
613 let m::DatumReferenceElementRef::DatumReferenceElement(eid) = er;
614 let e = self.cx.model.datum_reference_element_arena.get(eid.0);
615 self.collect_base(key, &e.base, out, depth + 1);
616 }
617 }
618 m::DatumOrCommonDatumRef::Complex(_) => {
619 self.cx
620 .warn("tolerance references a complex datum instance".to_owned());
621 }
622 }
623 }
624
625 fn datum(&self, which: DatumImpl) -> Datum<'m> {
626 Datum { cx: self.cx, which }
627 }
628}
629
630#[derive(Clone, Copy)]
639pub struct Feature<'m> {
640 cx: Ctx<'m>,
641 which: FeatureImpl,
642}
643
644macro_rules! feature_family {
656 (
657 regions: { $( $rent:ident, $rid:ident, $rarena:ident );+ $(;)? }
658 aspects: { $( $aent:ident, $aid:ident, $aarena:ident );+ $(;)? }
659 ) => {
660 #[derive(Clone, Copy)]
661 enum FeatureImpl {
662 $( $rent(m::$rid), )+
663 $( $aent(m::$aid), )+
664 }
665
666 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
669 pub enum FeatureKind {
670 $( $rent, )+
671 $( $aent, )+
672 }
673
674 impl<'m> Feature<'m> {
675 pub fn kind(&self) -> FeatureKind {
677 match self.which {
678 $( FeatureImpl::$rent(_) => FeatureKind::$rent, )+
679 $( FeatureImpl::$aent(_) => FeatureKind::$aent, )+
680 }
681 }
682 pub fn name(&self) -> &'m str {
684 match self.which {
685 $( FeatureImpl::$rent(i) => &self.cx.model.$rarena.get(i.0).name, )+
686 $( FeatureImpl::$aent(i) => &self.cx.model.$aarena.get(i.0).name, )+
687 }
688 }
689
690 pub fn description(&self) -> Option<&'m str> {
692 match self.which {
693 $( FeatureImpl::$rent(i) => {
694 self.cx.model.$rarena.get(i.0).description.as_deref()
695 } )+
696 $( FeatureImpl::$aent(i) => {
697 self.cx.model.$aarena.get(i.0).description.as_deref()
698 } )+
699 }
700 }
701
702 pub fn key(&self) -> m::EntityKey {
704 match self.which {
705 $( FeatureImpl::$rent(i) => m::EntityKey::$rent(i), )+
706 $( FeatureImpl::$aent(i) => m::EntityKey::$aent(i), )+
707 }
708 }
709
710 fn of_shape(&self) -> &'m m::ProductDefinitionShapeRef {
712 match self.which {
713 $( FeatureImpl::$rent(i) => &self.cx.model.$rarena.get(i.0).of_shape, )+
714 $( FeatureImpl::$aent(i) => &self.cx.model.$aarena.get(i.0).of_shape, )+
715 }
716 }
717 }
718
719 fn feature_impl_from_shape_aspect_ref(r: &m::ShapeAspectRef) -> Option<FeatureImpl> {
722 match r {
723 $( m::ShapeAspectRef::$rent(i) => Some(FeatureImpl::$rent(*i)), )+
724 $( m::ShapeAspectRef::$aent(i) => Some(FeatureImpl::$aent(*i)), )+
725 m::ShapeAspectRef::Complex(_) => None,
726 }
727 }
728
729 fn feature_impl_from_tolerance_target(
733 r: &m::GeometricToleranceTargetRef,
734 ) -> Option<FeatureImpl> {
735 match r {
736 $( m::GeometricToleranceTargetRef::$rent(i) => Some(FeatureImpl::$rent(*i)), )+
737 $( m::GeometricToleranceTargetRef::$aent(i) => Some(FeatureImpl::$aent(*i)), )+
738 _ => None,
739 }
740 }
741
742 fn push_all_features<'m>(cx: Ctx<'m>, out: &mut Vec<Feature<'m>>) {
745 $(
746 for i in 0..cx.model.$rarena.items.len() {
747 out.push(Feature { cx, which: FeatureImpl::$rent(m::$rid(i)) });
748 }
749 )+
750 }
751 };
752}
753
754feature_family! {
755 regions: {
757 ShapeAspect, ShapeAspectId, shape_aspect_arena;
758 DatumFeature, DatumFeatureId, datum_feature_arena;
759 AllAroundShapeAspect, AllAroundShapeAspectId, all_around_shape_aspect_arena;
760 CentreOfSymmetry, CentreOfSymmetryId, centre_of_symmetry_arena;
761 CompositeShapeAspect, CompositeShapeAspectId, composite_shape_aspect_arena;
762 CompositeGroupShapeAspect, CompositeGroupShapeAspectId, composite_group_shape_aspect_arena;
763 ContinuousShapeAspect, ContinuousShapeAspectId, continuous_shape_aspect_arena;
764 DerivedShapeAspect, DerivedShapeAspectId, derived_shape_aspect_arena;
765 }
766 aspects: {
769 Datum, DatumId, datum_arena;
770 CommonDatum, CommonDatumId, common_datum_arena;
771 DatumTarget, DatumTargetId, datum_target_arena;
772 DatumReferenceCompartment, DatumReferenceCompartmentId, datum_reference_compartment_arena;
773 DatumReferenceElement, DatumReferenceElementId, datum_reference_element_arena;
774 DatumSystem, DatumSystemId, datum_system_arena;
775 DefaultModelGeometricView, DefaultModelGeometricViewId, default_model_geometric_view_arena;
776 GeneralDatumReference, GeneralDatumReferenceId, general_datum_reference_arena;
777 PlacedDatumTargetFeature, PlacedDatumTargetFeatureId, placed_datum_target_feature_arena;
778 ToleranceZone, ToleranceZoneId, tolerance_zone_arena;
779 ToleranceZoneWithDatum, ToleranceZoneWithDatumId, tolerance_zone_with_datum_arena;
780 DimensionalSizeWithDatumFeature, DimensionalSizeWithDatumFeatureId, dimensional_size_with_datum_feature_arena;
781 }
782}
783
784impl Scene<'_> {
785 pub fn features(&self) -> impl Iterator<Item = Feature<'_>> + '_ {
792 let cx = self.ctx();
793 let mut out: Vec<Feature<'_>> = Vec::new();
794 push_all_features(cx, &mut out);
795 out.into_iter()
796 }
797}
798
799impl<'m> Dimension<'m> {
800 pub fn features(&self) -> Vec<Feature<'m>> {
805 let model = self.cx.model;
806 let refs: Vec<&m::ShapeAspectRef> = match self.which {
807 DimImpl::Size(i) => vec![&model.dimensional_size_arena.get(i.0).applies_to],
808 DimImpl::AngularSize(i) => vec![&model.angular_size_arena.get(i.0).applies_to],
809 DimImpl::Location(i) => {
810 let e = model.dimensional_location_arena.get(i.0);
811 vec![&e.relating_shape_aspect, &e.related_shape_aspect]
812 }
813 DimImpl::AngularLocation(i) => {
814 let e = model.angular_location_arena.get(i.0);
815 vec![&e.relating_shape_aspect, &e.related_shape_aspect]
816 }
817 };
818 refs.into_iter()
819 .filter_map(|r| self.feature_from_sa_ref(r))
820 .collect()
821 }
822
823 fn feature_from_sa_ref(&self, r: &m::ShapeAspectRef) -> Option<Feature<'m>> {
824 if matches!(r, m::ShapeAspectRef::Complex(_)) {
825 self.cx
826 .warn("dimension feature is a complex instance".to_owned());
827 return None;
828 }
829 feature_impl_from_shape_aspect_ref(r).map(|which| Feature { cx: self.cx, which })
830 }
831}
832
833impl<'m> Tolerance<'m> {
834 pub fn feature(&self) -> Option<Feature<'m>> {
841 let target = self.tolerance_target()?;
842 if matches!(target, m::GeometricToleranceTargetRef::Complex(_)) {
843 self.cx
844 .warn("tolerance target is a complex instance".to_owned());
845 return None;
846 }
847 feature_impl_from_tolerance_target(target).map(|which| Feature { cx: self.cx, which })
848 }
849
850 fn tolerance_target(&self) -> Option<&'m m::GeometricToleranceTargetRef> {
853 if let Some(t) = self.dedicated_target() {
854 return Some(t);
855 }
856 let TolImpl::Complex(cuid) = self.which else {
857 return None;
858 };
859 self.cx
860 .model
861 .complex_unit_arena
862 .get(cuid.0)
863 .parts
864 .iter()
865 .find_map(|p| match p {
866 m::UnitPart::GeometricTolerance {
867 toleranced_shape_aspect,
868 ..
869 } => Some(toleranced_shape_aspect),
870 _ => None,
871 })
872 }
873}
874
875pub enum FeatureGeometry<'m> {
879 Face(Face<'m>),
881 Edge(Edge<'m>),
883 Point(Point<'m>),
885 Solid(Solid<'m>),
887 Curve(Curve<'m>),
890 Other(m::EntityKey),
892}
893
894impl<'m> Feature<'m> {
895 pub fn geometry(&self) -> Vec<FeatureGeometry<'m>> {
904 let cx = self.cx;
905 let rg = cx.ref_graph();
906 let mut out = Vec::new();
907 for r in rg.referrers(self.key()) {
908 let m::EntityKey::GeometricItemSpecificUsage(gid) = r else {
909 continue;
910 };
911 let item = &cx
912 .model
913 .geometric_item_specific_usage_arena
914 .get(gid.0)
915 .identified_item;
916 out.push(match item {
917 m::GeometricModelItemRef::AdvancedFace(id) => {
918 FeatureGeometry::Face(Face::from_advanced_face(cx, *id))
919 }
920 m::GeometricModelItemRef::EdgeCurve(id) => {
921 FeatureGeometry::Edge(Edge::from_id(cx, *id))
922 }
923 m::GeometricModelItemRef::CartesianPoint(id) => {
924 FeatureGeometry::Point(Point::from_id(cx, *id))
925 }
926 m::GeometricModelItemRef::ManifoldSolidBrep(id) => {
927 FeatureGeometry::Solid(Solid::from_id(cx, *id))
928 }
929 other => match Curve::from_model_item(cx, other) {
930 Some(c) => FeatureGeometry::Curve(c),
931 None => FeatureGeometry::Other(other.entity_key()),
932 },
933 });
934 }
935 out
936 }
937}
938
939fn product_def_of_pds(
947 cx: Ctx<'_>,
948 id: m::ProductDefinitionShapeId,
949) -> Option<m::ProductDefinitionId> {
950 match cx.model.product_definition_shape_arena.get(id.0).definition {
951 m::CharacterizedDefinitionRef::ProductDefinition(pd) => Some(pd),
952 _ => None,
953 }
954}
955
956fn product_def_of_shape(
959 cx: Ctx<'_>,
960 r: &m::ProductDefinitionShapeRef,
961) -> Option<m::ProductDefinitionId> {
962 match r {
963 m::ProductDefinitionShapeRef::ProductDefinitionShape(id) => product_def_of_pds(cx, *id),
964 m::ProductDefinitionShapeRef::Complex(_) => None,
965 }
966}
967
968impl Feature<'_> {
969 fn part_def_id(&self) -> Option<m::ProductDefinitionId> {
972 product_def_of_shape(self.cx, self.of_shape())
973 }
974}
975
976impl Datum<'_> {
977 fn part_def_id(&self) -> Option<m::ProductDefinitionId> {
979 let of_shape = match self.which {
980 DatumImpl::Datum(i) => &self.cx.model.datum_arena.get(i.0).of_shape,
981 DatumImpl::CommonDatum(i) => &self.cx.model.common_datum_arena.get(i.0).of_shape,
982 };
983 product_def_of_shape(self.cx, of_shape)
984 }
985}
986
987impl Tolerance<'_> {
988 fn part_def_id(&self) -> Option<m::ProductDefinitionId> {
992 let target = self.tolerance_target()?;
993 if let m::GeometricToleranceTargetRef::ProductDefinitionShape(id) = target {
994 return product_def_of_pds(self.cx, *id);
995 }
996 let which = feature_impl_from_tolerance_target(target)?;
997 Feature { cx: self.cx, which }.part_def_id()
998 }
999}
1000
1001pub(crate) fn features_of(cx: Ctx<'_>, part: m::ProductDefinitionId) -> Vec<Feature<'_>> {
1003 let mut all = Vec::new();
1004 push_all_features(cx, &mut all);
1005 all.retain(|f| f.part_def_id() == Some(part));
1006 all
1007}
1008
1009pub(crate) fn datums_of(cx: Ctx<'_>, part: m::ProductDefinitionId) -> Vec<Datum<'_>> {
1011 let mut all = all_datums(cx);
1012 all.retain(|d| d.part_def_id() == Some(part));
1013 all
1014}
1015
1016pub(crate) fn dimensions_of(cx: Ctx<'_>, part: m::ProductDefinitionId) -> Vec<Dimension<'_>> {
1018 let mut all = all_dimensions(cx);
1019 all.retain(|d| d.features().iter().any(|f| f.part_def_id() == Some(part)));
1020 all
1021}
1022
1023pub(crate) fn tolerances_of(cx: Ctx<'_>, part: m::ProductDefinitionId) -> Vec<Tolerance<'_>> {
1026 let mut all = all_tolerances(cx);
1027 all.retain(|t| t.part_def_id() == Some(part));
1028 all
1029}