#![allow(clippy::must_use_candidate)]
use crate::generated::model as m;
use crate::scene::geometry::{Curve, Edge, Face, Point, Solid};
use crate::scene::{Ctx, Scene};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DimensionKind {
Size,
Location,
AngularSize,
AngularLocation,
}
#[derive(Clone, Copy)]
enum DimImpl {
Size(m::DimensionalSizeId),
Location(m::DimensionalLocationId),
AngularSize(m::AngularSizeId),
AngularLocation(m::AngularLocationId),
}
#[derive(Clone, Copy)]
pub struct Dimension<'m> {
cx: Ctx<'m>,
which: DimImpl,
}
impl Scene<'_> {
pub fn dimensions(&self) -> impl Iterator<Item = Dimension<'_>> + '_ {
all_dimensions(self.ctx()).into_iter()
}
}
fn all_dimensions(cx: Ctx<'_>) -> Vec<Dimension<'_>> {
let mut out = Vec::new();
for i in 0..cx.model.dimensional_size_arena.items.len() {
out.push(Dimension {
cx,
which: DimImpl::Size(m::DimensionalSizeId(i)),
});
}
for i in 0..cx.model.dimensional_location_arena.items.len() {
out.push(Dimension {
cx,
which: DimImpl::Location(m::DimensionalLocationId(i)),
});
}
for i in 0..cx.model.angular_size_arena.items.len() {
out.push(Dimension {
cx,
which: DimImpl::AngularSize(m::AngularSizeId(i)),
});
}
for i in 0..cx.model.angular_location_arena.items.len() {
out.push(Dimension {
cx,
which: DimImpl::AngularLocation(m::AngularLocationId(i)),
});
}
out
}
impl<'m> Dimension<'m> {
pub fn kind(&self) -> DimensionKind {
match self.which {
DimImpl::Size(_) => DimensionKind::Size,
DimImpl::Location(_) => DimensionKind::Location,
DimImpl::AngularSize(_) => DimensionKind::AngularSize,
DimImpl::AngularLocation(_) => DimensionKind::AngularLocation,
}
}
pub fn name(&self) -> &'m str {
match self.which {
DimImpl::Size(i) => &self.cx.model.dimensional_size_arena.get(i.0).name,
DimImpl::Location(i) => &self.cx.model.dimensional_location_arena.get(i.0).name,
DimImpl::AngularSize(i) => &self.cx.model.angular_size_arena.get(i.0).name,
DimImpl::AngularLocation(i) => &self.cx.model.angular_location_arena.get(i.0).name,
}
}
pub fn key(&self) -> m::EntityKey {
match self.which {
DimImpl::Size(i) => m::EntityKey::DimensionalSize(i),
DimImpl::Location(i) => m::EntityKey::DimensionalLocation(i),
DimImpl::AngularSize(i) => m::EntityKey::AngularSize(i),
DimImpl::AngularLocation(i) => m::EntityKey::AngularLocation(i),
}
}
pub fn value(&self) -> Option<f64> {
let cx = self.cx;
let rg = cx.ref_graph();
for r in rg.referrers(self.key()) {
let m::EntityKey::DimensionalCharacteristicRepresentation(dcr_id) = r else {
continue;
};
let dcr = cx
.model
.dimensional_characteristic_representation_arena
.get(dcr_id.0);
let sdr_id = match &dcr.representation {
m::ShapeDimensionRepresentationRef::ShapeDimensionRepresentation(id) => id,
m::ShapeDimensionRepresentationRef::Complex(_) => {
cx.warn("dimension value representation is a complex instance".to_owned());
continue;
}
};
let sdr = cx.model.shape_dimension_representation_arena.get(sdr_id.0);
for item in &sdr.items {
if let m::RepresentationItemRef::MeasureRepresentationItem(mid) = item {
return Some(
cx.model
.measure_representation_item_arena
.get(mid.0)
.value_component
.value
.as_f64(),
);
}
}
}
None
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ToleranceKind {
Position,
Flatness,
Straightness,
Roundness,
Cylindricity,
LineProfile,
SurfaceProfile,
Angularity,
Parallelism,
Perpendicularity,
Concentricity,
Coaxiality,
Symmetry,
CircularRunout,
TotalRunout,
Other,
}
#[derive(Clone, Copy)]
pub struct Tolerance<'m> {
cx: Ctx<'m>,
which: TolImpl,
}
macro_rules! leaf_tolerances {
($( $ent:ident, $id:ident, $arena:ident, $kind:ident );+ $(;)?) => {
#[derive(Clone, Copy)]
enum TolImpl {
$( $ent(m::$id), )+
Complex(m::ComplexUnitId),
}
fn push_dedicated_tolerances<'m>(cx: Ctx<'m>, out: &mut Vec<Tolerance<'m>>) {
$(
for i in 0..cx.model.$arena.items.len() {
out.push(Tolerance { cx, which: TolImpl::$ent(m::$id(i)) });
}
)+
}
impl<'m> Tolerance<'m> {
pub fn kind(&self) -> ToleranceKind {
match self.which {
$( TolImpl::$ent(_) => ToleranceKind::$kind, )+
TolImpl::Complex(cuid) => self.complex_kind(cuid),
}
}
pub fn key(&self) -> m::EntityKey {
match self.which {
$( TolImpl::$ent(i) => m::EntityKey::$ent(i), )+
TolImpl::Complex(cuid) => m::EntityKey::ComplexUnit(cuid),
}
}
fn dedicated_fields(&self) -> Option<(&'m str, Option<&'m m::LengthMeasureWithUnitRef>)> {
match self.which {
$( TolImpl::$ent(i) => {
let e = self.cx.model.$arena.get(i.0);
Some((&e.name, e.magnitude.as_ref()))
} )+
TolImpl::Complex(_) => None,
}
}
fn dedicated_target(&self) -> Option<&'m m::GeometricToleranceTargetRef> {
match self.which {
$( TolImpl::$ent(i) => {
Some(&self.cx.model.$arena.get(i.0).toleranced_shape_aspect)
} )+
TolImpl::Complex(_) => None,
}
}
}
};
}
leaf_tolerances! {
PositionTolerance, PositionToleranceId, position_tolerance_arena, Position;
FlatnessTolerance, FlatnessToleranceId, flatness_tolerance_arena, Flatness;
StraightnessTolerance, StraightnessToleranceId, straightness_tolerance_arena, Straightness;
RoundnessTolerance, RoundnessToleranceId, roundness_tolerance_arena, Roundness;
CylindricityTolerance, CylindricityToleranceId, cylindricity_tolerance_arena, Cylindricity;
LineProfileTolerance, LineProfileToleranceId, line_profile_tolerance_arena, LineProfile;
SurfaceProfileTolerance, SurfaceProfileToleranceId, surface_profile_tolerance_arena, SurfaceProfile;
AngularityTolerance, AngularityToleranceId, angularity_tolerance_arena, Angularity;
ParallelismTolerance, ParallelismToleranceId, parallelism_tolerance_arena, Parallelism;
PerpendicularityTolerance,PerpendicularityToleranceId,perpendicularity_tolerance_arena, Perpendicularity;
ConcentricityTolerance, ConcentricityToleranceId, concentricity_tolerance_arena, Concentricity;
CoaxialityTolerance, CoaxialityToleranceId, coaxiality_tolerance_arena, Coaxiality;
SymmetryTolerance, SymmetryToleranceId, symmetry_tolerance_arena, Symmetry;
CircularRunoutTolerance, CircularRunoutToleranceId, circular_runout_tolerance_arena, CircularRunout;
TotalRunoutTolerance, TotalRunoutToleranceId, total_runout_tolerance_arena, TotalRunout;
}
impl Scene<'_> {
pub fn tolerances(&self) -> impl Iterator<Item = Tolerance<'_>> + '_ {
all_tolerances(self.ctx()).into_iter()
}
}
fn all_tolerances(cx: Ctx<'_>) -> Vec<Tolerance<'_>> {
let mut out: Vec<Tolerance<'_>> = Vec::new();
push_dedicated_tolerances(cx, &mut out);
for i in 0..cx.model.complex_unit_arena.items.len() {
let cu = cx.model.complex_unit_arena.get(i);
if cu
.parts
.iter()
.any(|p| matches!(p, m::UnitPart::GeometricTolerance { .. }))
{
out.push(Tolerance {
cx,
which: TolImpl::Complex(m::ComplexUnitId(i)),
});
}
}
out
}
impl<'m> Tolerance<'m> {
pub fn name(&self) -> &'m str {
self.dedicated_fields()
.or_else(|| self.complex_geometric_tolerance())
.map_or("", |(name, _)| name)
}
pub fn magnitude(&self) -> Option<f64> {
let (_, mag) = self
.dedicated_fields()
.or_else(|| self.complex_geometric_tolerance())?;
mag.and_then(|r| length_measure_f64(self.cx, r))
}
fn complex_geometric_tolerance(
&self,
) -> Option<(&'m str, Option<&'m m::LengthMeasureWithUnitRef>)> {
let TolImpl::Complex(cuid) = self.which else {
return None;
};
let cu = self.cx.model.complex_unit_arena.get(cuid.0);
cu.parts.iter().find_map(|p| match p {
m::UnitPart::GeometricTolerance {
name, magnitude, ..
} => Some((name.as_str(), magnitude.as_ref())),
_ => None,
})
}
fn complex_kind(&self, cuid: m::ComplexUnitId) -> ToleranceKind {
let cu = self.cx.model.complex_unit_arena.get(cuid.0);
for p in &cu.parts {
let kind = match p {
m::UnitPart::PositionTolerance => ToleranceKind::Position,
m::UnitPart::FlatnessTolerance => ToleranceKind::Flatness,
m::UnitPart::StraightnessTolerance => ToleranceKind::Straightness,
m::UnitPart::RoundnessTolerance => ToleranceKind::Roundness,
m::UnitPart::CylindricityTolerance => ToleranceKind::Cylindricity,
m::UnitPart::LineProfileTolerance => ToleranceKind::LineProfile,
m::UnitPart::SurfaceProfileTolerance => ToleranceKind::SurfaceProfile,
m::UnitPart::ParallelismTolerance => ToleranceKind::Parallelism,
m::UnitPart::PerpendicularityTolerance => ToleranceKind::Perpendicularity,
m::UnitPart::CircularRunoutTolerance => ToleranceKind::CircularRunout,
_ => continue,
};
return kind;
}
self.cx
.warn("geometric tolerance has no recognized characteristic subtype".to_owned());
ToleranceKind::Other
}
}
fn length_measure_f64(cx: Ctx<'_>, r: &m::LengthMeasureWithUnitRef) -> Option<f64> {
match r {
m::LengthMeasureWithUnitRef::LengthMeasureWithUnit(id) => Some(
cx.model
.length_measure_with_unit_arena
.get(id.0)
.value_component
.value
.as_f64(),
),
m::LengthMeasureWithUnitRef::Complex(_) => {
cx.warn("tolerance magnitude is a complex measure instance".to_owned());
None
}
}
}
#[derive(Clone, Copy)]
pub struct Datum<'m> {
cx: Ctx<'m>,
which: DatumImpl,
}
#[derive(Clone, Copy)]
enum DatumImpl {
Datum(m::DatumId),
CommonDatum(m::CommonDatumId),
}
impl Scene<'_> {
pub fn datums(&self) -> impl Iterator<Item = Datum<'_>> + '_ {
all_datums(self.ctx()).into_iter()
}
}
fn all_datums(cx: Ctx<'_>) -> Vec<Datum<'_>> {
let mut out: Vec<Datum<'_>> = Vec::new();
for i in 0..cx.model.datum_arena.items.len() {
out.push(Datum {
cx,
which: DatumImpl::Datum(m::DatumId(i)),
});
}
for i in 0..cx.model.common_datum_arena.items.len() {
out.push(Datum {
cx,
which: DatumImpl::CommonDatum(m::CommonDatumId(i)),
});
}
out
}
impl<'m> Datum<'m> {
pub fn letter(&self) -> &'m str {
match self.which {
DatumImpl::Datum(i) => &self.cx.model.datum_arena.get(i.0).identification,
DatumImpl::CommonDatum(i) => &self.cx.model.common_datum_arena.get(i.0).identification,
}
}
pub fn name(&self) -> &'m str {
match self.which {
DatumImpl::Datum(i) => &self.cx.model.datum_arena.get(i.0).name,
DatumImpl::CommonDatum(i) => &self.cx.model.common_datum_arena.get(i.0).name,
}
}
pub fn key(&self) -> m::EntityKey {
match self.which {
DatumImpl::Datum(i) => m::EntityKey::Datum(i),
DatumImpl::CommonDatum(i) => m::EntityKey::CommonDatum(i),
}
}
pub fn datum_feature(&self) -> Option<Feature<'m>> {
let cx = self.cx;
let rg = cx.ref_graph();
for r in rg.referrers(self.key()) {
let m::EntityKey::ShapeAspectRelationship(sid) = r else {
continue;
};
let sar = cx.model.shape_aspect_relationship_arena.get(sid.0);
for aspect in [&sar.relating_shape_aspect, &sar.related_shape_aspect] {
if let m::ShapeAspectRef::DatumFeature(fid) = aspect {
return Some(Feature {
cx,
which: FeatureImpl::DatumFeature(*fid),
});
}
}
}
None
}
}
impl<'m> Tolerance<'m> {
pub fn datums(&self) -> Vec<Datum<'m>> {
let mut keyed: Vec<(i64, Datum<'m>)> = Vec::new();
for r in self.datum_system() {
self.collect_system_ref(r, &mut keyed);
}
keyed.sort_by_key(|(k, _)| *k);
keyed.into_iter().map(|(_, d)| d).collect()
}
fn datum_system(&self) -> &'m [m::DatumSystemOrReferenceRef] {
let model = self.cx.model;
match self.which {
TolImpl::AngularityTolerance(i) => {
&model.angularity_tolerance_arena.get(i.0).datum_system
}
TolImpl::CircularRunoutTolerance(i) => {
&model.circular_runout_tolerance_arena.get(i.0).datum_system
}
TolImpl::CoaxialityTolerance(i) => {
&model.coaxiality_tolerance_arena.get(i.0).datum_system
}
TolImpl::ConcentricityTolerance(i) => {
&model.concentricity_tolerance_arena.get(i.0).datum_system
}
TolImpl::ParallelismTolerance(i) => {
&model.parallelism_tolerance_arena.get(i.0).datum_system
}
TolImpl::PerpendicularityTolerance(i) => {
&model.perpendicularity_tolerance_arena.get(i.0).datum_system
}
TolImpl::SymmetryTolerance(i) => &model.symmetry_tolerance_arena.get(i.0).datum_system,
TolImpl::TotalRunoutTolerance(i) => {
&model.total_runout_tolerance_arena.get(i.0).datum_system
}
TolImpl::Complex(cuid) => model
.complex_unit_arena
.get(cuid.0)
.parts
.iter()
.find_map(|p| match p {
m::UnitPart::GeometricToleranceWithDatumReference { datum_system } => {
Some(datum_system.as_slice())
}
_ => None,
})
.unwrap_or(&[]),
_ => &[],
}
}
fn collect_system_ref(
&self,
r: &m::DatumSystemOrReferenceRef,
out: &mut Vec<(i64, Datum<'m>)>,
) {
match r {
m::DatumSystemOrReferenceRef::DatumReference(id) => {
let dr = self.cx.model.datum_reference_arena.get(id.0);
self.collect_datum_ref(dr.precedence, &dr.referenced_datum, out);
}
m::DatumSystemOrReferenceRef::DatumSystem(id) => {
let ds = self.cx.model.datum_system_arena.get(id.0);
for (idx, c) in ds.constituents.iter().enumerate() {
let m::DatumReferenceCompartmentRef::DatumReferenceCompartment(cid) = c;
let comp = self.cx.model.datum_reference_compartment_arena.get(cid.0);
let key = i64::try_from(idx).unwrap_or(i64::MAX);
self.collect_base(key, &comp.base, out, 0);
}
}
m::DatumSystemOrReferenceRef::Complex(_) => {
self.cx
.warn("tolerance datum reference is a complex instance".to_owned());
}
}
}
fn collect_datum_ref(&self, key: i64, r: &m::DatumRef, out: &mut Vec<(i64, Datum<'m>)>) {
match r {
m::DatumRef::Datum(id) => out.push((key, self.datum(DatumImpl::Datum(*id)))),
m::DatumRef::CommonDatum(id) => {
out.push((key, self.datum(DatumImpl::CommonDatum(*id))));
}
m::DatumRef::Complex(_) => {
self.cx
.warn("tolerance references a complex datum instance".to_owned());
}
}
}
fn collect_base(
&self,
key: i64,
r: &m::DatumOrCommonDatumRef,
out: &mut Vec<(i64, Datum<'m>)>,
depth: u32,
) {
if depth > 8 {
self.cx
.warn("datum reference nesting is too deep to resolve".to_owned());
return;
}
match r {
m::DatumOrCommonDatumRef::Datum(id) => {
out.push((key, self.datum(DatumImpl::Datum(*id))));
}
m::DatumOrCommonDatumRef::CommonDatum(id) => {
out.push((key, self.datum(DatumImpl::CommonDatum(*id))));
}
m::DatumOrCommonDatumRef::DatumReferenceElement(id) => {
let e = self.cx.model.datum_reference_element_arena.get(id.0);
self.collect_base(key, &e.base, out, depth + 1);
}
m::DatumOrCommonDatumRef::CommonDatumList(refs) => {
for er in refs {
let m::DatumReferenceElementRef::DatumReferenceElement(eid) = er;
let e = self.cx.model.datum_reference_element_arena.get(eid.0);
self.collect_base(key, &e.base, out, depth + 1);
}
}
m::DatumOrCommonDatumRef::Complex(_) => {
self.cx
.warn("tolerance references a complex datum instance".to_owned());
}
}
}
fn datum(&self, which: DatumImpl) -> Datum<'m> {
Datum { cx: self.cx, which }
}
}
#[derive(Clone, Copy)]
pub struct Feature<'m> {
cx: Ctx<'m>,
which: FeatureImpl,
}
macro_rules! feature_family {
(
regions: { $( $rent:ident, $rid:ident, $rarena:ident );+ $(;)? }
aspects: { $( $aent:ident, $aid:ident, $aarena:ident );+ $(;)? }
) => {
#[derive(Clone, Copy)]
enum FeatureImpl {
$( $rent(m::$rid), )+
$( $aent(m::$aid), )+
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum FeatureKind {
$( $rent, )+
$( $aent, )+
}
impl<'m> Feature<'m> {
pub fn kind(&self) -> FeatureKind {
match self.which {
$( FeatureImpl::$rent(_) => FeatureKind::$rent, )+
$( FeatureImpl::$aent(_) => FeatureKind::$aent, )+
}
}
pub fn name(&self) -> &'m str {
match self.which {
$( FeatureImpl::$rent(i) => &self.cx.model.$rarena.get(i.0).name, )+
$( FeatureImpl::$aent(i) => &self.cx.model.$aarena.get(i.0).name, )+
}
}
pub fn description(&self) -> Option<&'m str> {
match self.which {
$( FeatureImpl::$rent(i) => {
self.cx.model.$rarena.get(i.0).description.as_deref()
} )+
$( FeatureImpl::$aent(i) => {
self.cx.model.$aarena.get(i.0).description.as_deref()
} )+
}
}
pub fn key(&self) -> m::EntityKey {
match self.which {
$( FeatureImpl::$rent(i) => m::EntityKey::$rent(i), )+
$( FeatureImpl::$aent(i) => m::EntityKey::$aent(i), )+
}
}
fn of_shape(&self) -> &'m m::ProductDefinitionShapeRef {
match self.which {
$( FeatureImpl::$rent(i) => &self.cx.model.$rarena.get(i.0).of_shape, )+
$( FeatureImpl::$aent(i) => &self.cx.model.$aarena.get(i.0).of_shape, )+
}
}
}
fn feature_impl_from_shape_aspect_ref(r: &m::ShapeAspectRef) -> Option<FeatureImpl> {
match r {
$( m::ShapeAspectRef::$rent(i) => Some(FeatureImpl::$rent(*i)), )+
$( m::ShapeAspectRef::$aent(i) => Some(FeatureImpl::$aent(*i)), )+
m::ShapeAspectRef::Complex(_) => None,
}
}
fn feature_impl_from_tolerance_target(
r: &m::GeometricToleranceTargetRef,
) -> Option<FeatureImpl> {
match r {
$( m::GeometricToleranceTargetRef::$rent(i) => Some(FeatureImpl::$rent(*i)), )+
$( m::GeometricToleranceTargetRef::$aent(i) => Some(FeatureImpl::$aent(*i)), )+
_ => None,
}
}
fn push_all_features<'m>(cx: Ctx<'m>, out: &mut Vec<Feature<'m>>) {
$(
for i in 0..cx.model.$rarena.items.len() {
out.push(Feature { cx, which: FeatureImpl::$rent(m::$rid(i)) });
}
)+
}
};
}
feature_family! {
regions: {
ShapeAspect, ShapeAspectId, shape_aspect_arena;
DatumFeature, DatumFeatureId, datum_feature_arena;
AllAroundShapeAspect, AllAroundShapeAspectId, all_around_shape_aspect_arena;
CentreOfSymmetry, CentreOfSymmetryId, centre_of_symmetry_arena;
CompositeShapeAspect, CompositeShapeAspectId, composite_shape_aspect_arena;
CompositeGroupShapeAspect, CompositeGroupShapeAspectId, composite_group_shape_aspect_arena;
ContinuousShapeAspect, ContinuousShapeAspectId, continuous_shape_aspect_arena;
DerivedShapeAspect, DerivedShapeAspectId, derived_shape_aspect_arena;
}
aspects: {
Datum, DatumId, datum_arena;
CommonDatum, CommonDatumId, common_datum_arena;
DatumTarget, DatumTargetId, datum_target_arena;
DatumReferenceCompartment, DatumReferenceCompartmentId, datum_reference_compartment_arena;
DatumReferenceElement, DatumReferenceElementId, datum_reference_element_arena;
DatumSystem, DatumSystemId, datum_system_arena;
DefaultModelGeometricView, DefaultModelGeometricViewId, default_model_geometric_view_arena;
GeneralDatumReference, GeneralDatumReferenceId, general_datum_reference_arena;
PlacedDatumTargetFeature, PlacedDatumTargetFeatureId, placed_datum_target_feature_arena;
ToleranceZone, ToleranceZoneId, tolerance_zone_arena;
ToleranceZoneWithDatum, ToleranceZoneWithDatumId, tolerance_zone_with_datum_arena;
DimensionalSizeWithDatumFeature, DimensionalSizeWithDatumFeatureId, dimensional_size_with_datum_feature_arena;
}
}
impl Scene<'_> {
pub fn features(&self) -> impl Iterator<Item = Feature<'_>> + '_ {
let cx = self.ctx();
let mut out: Vec<Feature<'_>> = Vec::new();
push_all_features(cx, &mut out);
out.into_iter()
}
}
impl<'m> Dimension<'m> {
pub fn features(&self) -> Vec<Feature<'m>> {
let model = self.cx.model;
let refs: Vec<&m::ShapeAspectRef> = match self.which {
DimImpl::Size(i) => vec![&model.dimensional_size_arena.get(i.0).applies_to],
DimImpl::AngularSize(i) => vec![&model.angular_size_arena.get(i.0).applies_to],
DimImpl::Location(i) => {
let e = model.dimensional_location_arena.get(i.0);
vec![&e.relating_shape_aspect, &e.related_shape_aspect]
}
DimImpl::AngularLocation(i) => {
let e = model.angular_location_arena.get(i.0);
vec![&e.relating_shape_aspect, &e.related_shape_aspect]
}
};
refs.into_iter()
.filter_map(|r| self.feature_from_sa_ref(r))
.collect()
}
fn feature_from_sa_ref(&self, r: &m::ShapeAspectRef) -> Option<Feature<'m>> {
if matches!(r, m::ShapeAspectRef::Complex(_)) {
self.cx
.warn("dimension feature is a complex instance".to_owned());
return None;
}
feature_impl_from_shape_aspect_ref(r).map(|which| Feature { cx: self.cx, which })
}
}
impl<'m> Tolerance<'m> {
pub fn feature(&self) -> Option<Feature<'m>> {
let target = self.tolerance_target()?;
if matches!(target, m::GeometricToleranceTargetRef::Complex(_)) {
self.cx
.warn("tolerance target is a complex instance".to_owned());
return None;
}
feature_impl_from_tolerance_target(target).map(|which| Feature { cx: self.cx, which })
}
fn tolerance_target(&self) -> Option<&'m m::GeometricToleranceTargetRef> {
if let Some(t) = self.dedicated_target() {
return Some(t);
}
let TolImpl::Complex(cuid) = self.which else {
return None;
};
self.cx
.model
.complex_unit_arena
.get(cuid.0)
.parts
.iter()
.find_map(|p| match p {
m::UnitPart::GeometricTolerance {
toleranced_shape_aspect,
..
} => Some(toleranced_shape_aspect),
_ => None,
})
}
}
pub enum FeatureGeometry<'m> {
Face(Face<'m>),
Edge(Edge<'m>),
Point(Point<'m>),
Solid(Solid<'m>),
Curve(Curve<'m>),
Other(m::EntityKey),
}
impl<'m> Feature<'m> {
pub fn geometry(&self) -> Vec<FeatureGeometry<'m>> {
let cx = self.cx;
let rg = cx.ref_graph();
let mut out = Vec::new();
for r in rg.referrers(self.key()) {
let m::EntityKey::GeometricItemSpecificUsage(gid) = r else {
continue;
};
let item = &cx
.model
.geometric_item_specific_usage_arena
.get(gid.0)
.identified_item;
out.push(match item {
m::GeometricModelItemRef::AdvancedFace(id) => {
FeatureGeometry::Face(Face::from_advanced_face(cx, *id))
}
m::GeometricModelItemRef::EdgeCurve(id) => {
FeatureGeometry::Edge(Edge::from_id(cx, *id))
}
m::GeometricModelItemRef::CartesianPoint(id) => {
FeatureGeometry::Point(Point::from_id(cx, *id))
}
m::GeometricModelItemRef::ManifoldSolidBrep(id) => {
FeatureGeometry::Solid(Solid::from_id(cx, *id))
}
other => match Curve::from_model_item(cx, other) {
Some(c) => FeatureGeometry::Curve(c),
None => FeatureGeometry::Other(other.entity_key()),
},
});
}
out
}
}
fn product_def_of_pds(cx: Ctx<'_>, id: m::ProductDefinitionShapeId) -> Option<m::EntityKey> {
match cx.model.product_definition_shape_arena.get(id.0).definition {
m::CharacterizedDefinitionRef::ProductDefinition(pd) => {
Some(m::EntityKey::ProductDefinition(pd))
}
m::CharacterizedDefinitionRef::ProductDefinitionWithAssociatedDocuments(w) => {
Some(m::EntityKey::ProductDefinitionWithAssociatedDocuments(w))
}
_ => None,
}
}
fn product_def_of_shape(cx: Ctx<'_>, r: &m::ProductDefinitionShapeRef) -> Option<m::EntityKey> {
match r {
m::ProductDefinitionShapeRef::ProductDefinitionShape(id) => product_def_of_pds(cx, *id),
m::ProductDefinitionShapeRef::Complex(_) => None,
}
}
impl Feature<'_> {
fn part_def_id(&self) -> Option<m::EntityKey> {
product_def_of_shape(self.cx, self.of_shape())
}
}
impl Datum<'_> {
fn part_def_id(&self) -> Option<m::EntityKey> {
let of_shape = match self.which {
DatumImpl::Datum(i) => &self.cx.model.datum_arena.get(i.0).of_shape,
DatumImpl::CommonDatum(i) => &self.cx.model.common_datum_arena.get(i.0).of_shape,
};
product_def_of_shape(self.cx, of_shape)
}
}
impl Tolerance<'_> {
fn part_def_id(&self) -> Option<m::EntityKey> {
let target = self.tolerance_target()?;
if let m::GeometricToleranceTargetRef::ProductDefinitionShape(id) = target {
return product_def_of_pds(self.cx, *id);
}
let which = feature_impl_from_tolerance_target(target)?;
Feature { cx: self.cx, which }.part_def_id()
}
}
pub(crate) fn features_of(cx: Ctx<'_>, part: m::EntityKey) -> Vec<Feature<'_>> {
let mut all = Vec::new();
push_all_features(cx, &mut all);
all.retain(|f| f.part_def_id() == Some(part));
all
}
pub(crate) fn datums_of(cx: Ctx<'_>, part: m::EntityKey) -> Vec<Datum<'_>> {
let mut all = all_datums(cx);
all.retain(|d| d.part_def_id() == Some(part));
all
}
pub(crate) fn dimensions_of(cx: Ctx<'_>, part: m::EntityKey) -> Vec<Dimension<'_>> {
let mut all = all_dimensions(cx);
all.retain(|d| d.features().iter().any(|f| f.part_def_id() == Some(part)));
all
}
pub(crate) fn tolerances_of(cx: Ctx<'_>, part: m::EntityKey) -> Vec<Tolerance<'_>> {
let mut all = all_tolerances(cx);
all.retain(|t| t.part_def_id() == Some(part));
all
}