#![allow(clippy::must_use_candidate)]
use std::collections::HashSet;
use crate::generated::model as m;
use crate::scene::geometry::Solid;
use crate::scene::pmi;
use crate::scene::{Ctx, Scene};
impl Scene<'_> {
pub fn all_products(&self) -> impl Iterator<Item = Product<'_>> + '_ {
let cx = self.ctx();
(0..cx.model.product_arena.items.len()).map(move |i| Product {
cx,
id: m::ProductId(i),
})
}
pub fn all_product_definitions(&self) -> impl Iterator<Item = ProductDef<'_>> + '_ {
let cx = self.ctx();
let plain = (0..cx.model.product_definition_arena.items.len()).map(move |i| ProductDef {
cx,
which: PdImpl::Plain(m::ProductDefinitionId(i)),
});
let with_docs = (0..cx
.model
.product_definition_with_associated_documents_arena
.items
.len())
.map(move |i| ProductDef {
cx,
which: PdImpl::WithDocs(m::ProductDefinitionWithAssociatedDocumentsId(i)),
});
plain.chain(with_docs)
}
pub fn root_definitions(&self) -> impl Iterator<Item = ProductDef<'_>> + '_ {
let cx = self.ctx();
let rg = cx.ref_graph();
self.all_product_definitions().filter(move |def| {
!rg.referrers(def.key()).iter().any(|r| {
let m::EntityKey::NextAssemblyUsageOccurrence(nid) = r else {
return false;
};
let nauo = cx.model.next_assembly_usage_occurrence_arena.get(nid.0);
matches!(
&nauo.related_product_definition,
m::ProductDefinitionOrReferenceRef::ProductDefinition(d) if m::EntityKey::ProductDefinition(*d) == def.key()
)
})
})
}
}
#[derive(Clone, Copy)]
pub struct Product<'m> {
cx: Ctx<'m>,
id: m::ProductId,
}
impl<'m> Product<'m> {
fn raw(&self) -> &'m m::Product {
self.cx.model.product_arena.get(self.id.0)
}
pub fn key(&self) -> m::EntityKey {
m::EntityKey::Product(self.id)
}
pub fn id(&self) -> &'m str {
&self.raw().id
}
pub fn name(&self) -> &'m str {
&self.raw().name
}
pub fn description(&self) -> Option<&'m str> {
self.raw().description.as_deref()
}
pub fn definitions(&self) -> impl Iterator<Item = ProductDef<'m>> + 'm {
let cx = self.cx;
let rg = cx.ref_graph();
let mut out: Vec<ProductDef<'m>> = Vec::new();
for &fr in rg.referrers(m::EntityKey::Product(self.id)) {
if !matches!(
fr,
m::EntityKey::ProductDefinitionFormation(_)
| m::EntityKey::ProductDefinitionFormationWithSpecifiedSource(_)
) {
continue;
}
for &pr in rg.referrers(fr) {
if let Some(d) = ProductDef::from_key(cx, pr) {
out.push(d);
}
}
}
out.into_iter()
}
fn metadata_targets(&self) -> Vec<m::EntityKey> {
let rg = self.cx.ref_graph();
let mut targets = vec![self.key()];
for &fr in rg.referrers(self.key()) {
if !matches!(
fr,
m::EntityKey::ProductDefinitionFormation(_)
| m::EntityKey::ProductDefinitionFormationWithSpecifiedSource(_)
) {
continue;
}
targets.push(fr);
for &pr in rg.referrers(fr) {
if matches!(pr, m::EntityKey::ProductDefinition(_)) {
targets.push(pr);
}
}
}
targets
}
pub fn contributors(&self) -> Vec<Contributor<'m>> {
contributors_of(self.cx, &self.metadata_targets())
}
pub fn approvals(&self) -> Vec<Approval<'m>> {
approvals_of(self.cx, &self.metadata_targets())
}
pub fn documents(&self) -> Vec<Document<'m>> {
documents_of(self.cx, &self.metadata_targets())
}
pub fn security_classifications(&self) -> Vec<SecurityClassification<'m>> {
security_classifications_of(self.cx, &self.metadata_targets())
}
pub fn versions(&self) -> Vec<Version<'m>> {
let cx = self.cx;
let rg = cx.ref_graph();
let mut out: Vec<Version<'m>> = Vec::new();
for r in rg.referrers(self.key()) {
let which = match r {
m::EntityKey::ProductDefinitionFormation(id) => FormImpl::Plain(*id),
m::EntityKey::ProductDefinitionFormationWithSpecifiedSource(id) => {
FormImpl::WithSource(*id)
}
_ => continue,
};
out.push(Version { cx, which });
}
out
}
}
#[derive(Clone, Copy)]
pub struct Version<'m> {
cx: Ctx<'m>,
which: FormImpl,
}
#[derive(Clone, Copy)]
enum FormImpl {
Plain(m::ProductDefinitionFormationId),
WithSource(m::ProductDefinitionFormationWithSpecifiedSourceId),
}
impl<'m> Version<'m> {
fn fields(&self) -> (&'m str, Option<&'m str>) {
let model = self.cx.model;
match self.which {
FormImpl::Plain(i) => {
let f = model.product_definition_formation_arena.get(i.0);
(&f.id, f.description.as_deref())
}
FormImpl::WithSource(i) => {
let f = model
.product_definition_formation_with_specified_source_arena
.get(i.0);
(&f.id, f.description.as_deref())
}
}
}
pub fn key(&self) -> m::EntityKey {
match self.which {
FormImpl::Plain(i) => m::EntityKey::ProductDefinitionFormation(i),
FormImpl::WithSource(i) => {
m::EntityKey::ProductDefinitionFormationWithSpecifiedSource(i)
}
}
}
pub fn id(&self) -> &'m str {
self.fields().0
}
pub fn description(&self) -> Option<&'m str> {
self.fields().1
}
pub fn definitions(&self) -> impl Iterator<Item = ProductDef<'m>> + 'm {
let cx = self.cx;
let rg = cx.ref_graph();
let mut out: Vec<ProductDef<'m>> = Vec::new();
for &r in rg.referrers(self.key()) {
if let Some(d) = ProductDef::from_key(cx, r) {
out.push(d);
}
}
out.into_iter()
}
}
#[derive(Clone, Copy)]
pub struct ProductDef<'m> {
cx: Ctx<'m>,
which: PdImpl,
}
#[derive(Clone, Copy)]
enum PdImpl {
Plain(m::ProductDefinitionId),
WithDocs(m::ProductDefinitionWithAssociatedDocumentsId),
}
struct PdCore<'m> {
id: &'m str,
description: Option<&'m str>,
formation: &'m m::ProductDefinitionFormationRef,
}
impl<'m> ProductDef<'m> {
fn from_key(cx: Ctx<'m>, key: m::EntityKey) -> Option<Self> {
match key {
m::EntityKey::ProductDefinition(i) => Some(Self {
cx,
which: PdImpl::Plain(i),
}),
m::EntityKey::ProductDefinitionWithAssociatedDocuments(i) => Some(Self {
cx,
which: PdImpl::WithDocs(i),
}),
_ => None,
}
}
fn core(&self) -> PdCore<'m> {
match self.which {
PdImpl::Plain(i) => {
let r = self.cx.model.product_definition_arena.get(i.0);
PdCore {
id: &r.id,
description: r.description.as_deref(),
formation: &r.formation,
}
}
PdImpl::WithDocs(i) => {
let r = self
.cx
.model
.product_definition_with_associated_documents_arena
.get(i.0);
PdCore {
id: &r.id,
description: r.description.as_deref(),
formation: &r.formation,
}
}
}
}
pub fn key(&self) -> m::EntityKey {
match self.which {
PdImpl::Plain(i) => m::EntityKey::ProductDefinition(i),
PdImpl::WithDocs(i) => m::EntityKey::ProductDefinitionWithAssociatedDocuments(i),
}
}
pub fn id(&self) -> &'m str {
self.core().id
}
pub fn description(&self) -> Option<&'m str> {
self.core().description
}
pub fn product(&self) -> Option<Product<'m>> {
let model = self.cx.model;
let of_product: &m::ProductRef = match self.core().formation {
m::ProductDefinitionFormationRef::ProductDefinitionFormation(i) => {
&model.product_definition_formation_arena.get(i.0).of_product
}
m::ProductDefinitionFormationRef::ProductDefinitionFormationWithSpecifiedSource(i) => {
&model
.product_definition_formation_with_specified_source_arena
.get(i.0)
.of_product
}
m::ProductDefinitionFormationRef::Complex(_) => return None,
};
match of_product {
m::ProductRef::Product(pid) => Some(Product {
cx: self.cx,
id: *pid,
}),
m::ProductRef::Complex(_) => None,
}
}
pub fn occurrences(&self) -> impl Iterator<Item = Occurrence<'m>> + 'm {
let cx = self.cx;
let rg = cx.ref_graph();
let me = self.key();
let mut out: Vec<Occurrence<'m>> = Vec::new();
for r in rg.referrers(me) {
if let m::EntityKey::NextAssemblyUsageOccurrence(nid) = r {
let nauo = cx.model.next_assembly_usage_occurrence_arena.get(nid.0);
if pdor_is(&nauo.relating_product_definition, me) {
out.push(Occurrence { cx, id: *nid });
}
}
}
out.into_iter()
}
pub fn children(&self) -> impl Iterator<Item = ProductDef<'m>> + 'm {
self.occurrences().filter_map(|o| o.definition())
}
pub fn parents(&self) -> impl Iterator<Item = ProductDef<'m>> + 'm {
let cx = self.cx;
let rg = cx.ref_graph();
let me = self.key();
let mut out: Vec<ProductDef<'m>> = Vec::new();
for r in rg.referrers(me) {
if let m::EntityKey::NextAssemblyUsageOccurrence(nid) = r {
let nauo = cx.model.next_assembly_usage_occurrence_arena.get(nid.0);
if pdor_is(&nauo.related_product_definition, me) {
if let Some(d) = pdor_to_def(cx, &nauo.relating_product_definition) {
out.push(d);
}
}
}
}
out.into_iter()
}
pub fn solids(&self) -> impl Iterator<Item = Solid<'m>> + 'm {
let cx = self.cx;
let rg = cx.ref_graph();
let me = self.key();
let mut out: Vec<Solid<'m>> = Vec::new();
let mut visited: HashSet<m::EntityKey> = HashSet::new();
for r in rg.referrers(me) {
let m::EntityKey::ProductDefinitionShape(pds_id) = r else {
continue;
};
let pds = cx.model.product_definition_shape_arena.get(pds_id.0);
if !cdef_is(&pds.definition, me) {
continue;
}
for s in rg.referrers(m::EntityKey::ProductDefinitionShape(*pds_id)) {
let m::EntityKey::ShapeDefinitionRepresentation(sdr_id) = s else {
continue;
};
let sdr = cx.model.shape_definition_representation_arena.get(sdr_id.0);
if matches!(&sdr.definition, m::RepresentedDefinitionRef::ProductDefinitionShape(p) if *p == *pds_id)
{
collect_solids_from_repr(cx, &sdr.used_representation, &mut out, &mut visited);
}
}
}
let mut seen: HashSet<m::EntityKey> = HashSet::new();
out.retain(|s| seen.insert(s.key()));
out.into_iter()
}
pub fn features(&self) -> impl Iterator<Item = pmi::Feature<'m>> + 'm {
pmi::features_of(self.cx, self.key()).into_iter()
}
pub fn dimensions(&self) -> impl Iterator<Item = pmi::Dimension<'m>> + 'm {
pmi::dimensions_of(self.cx, self.key()).into_iter()
}
pub fn tolerances(&self) -> impl Iterator<Item = pmi::Tolerance<'m>> + 'm {
pmi::tolerances_of(self.cx, self.key()).into_iter()
}
pub fn datums(&self) -> impl Iterator<Item = pmi::Datum<'m>> + 'm {
pmi::datums_of(self.cx, self.key()).into_iter()
}
pub fn version(&self) -> Option<&'m str> {
let model = self.cx.model;
match self.core().formation {
m::ProductDefinitionFormationRef::ProductDefinitionFormation(i) => {
Some(&model.product_definition_formation_arena.get(i.0).id)
}
m::ProductDefinitionFormationRef::ProductDefinitionFormationWithSpecifiedSource(i) => {
Some(
&model
.product_definition_formation_with_specified_source_arena
.get(i.0)
.id,
)
}
m::ProductDefinitionFormationRef::Complex(_) => None,
}
}
fn metadata_targets(&self) -> Vec<m::EntityKey> {
let mut targets = Vec::new();
if let Some(p) = self.product() {
targets.push(p.key());
}
match self.core().formation {
m::ProductDefinitionFormationRef::ProductDefinitionFormation(i) => {
targets.push(m::EntityKey::ProductDefinitionFormation(*i));
}
m::ProductDefinitionFormationRef::ProductDefinitionFormationWithSpecifiedSource(i) => {
targets.push(m::EntityKey::ProductDefinitionFormationWithSpecifiedSource(
*i,
));
}
m::ProductDefinitionFormationRef::Complex(_) => {}
}
targets.push(self.key());
targets
}
pub fn contributors(&self) -> Vec<Contributor<'m>> {
contributors_of(self.cx, &self.metadata_targets())
}
pub fn approvals(&self) -> Vec<Approval<'m>> {
approvals_of(self.cx, &self.metadata_targets())
}
pub fn documents(&self) -> Vec<Document<'m>> {
let mut out = documents_of(self.cx, &self.metadata_targets());
if let PdImpl::WithDocs(i) = self.which {
let raw = self
.cx
.model
.product_definition_with_associated_documents_arena
.get(i.0);
let scope = scope_of(self.key());
for dref in &raw.documentation_ids {
let which = match dref {
m::DocumentRef::Document(i) => DocImpl::Document(*i),
m::DocumentRef::DocumentFile(i) => DocImpl::DocumentFile(*i),
m::DocumentRef::Complex(_) => continue,
};
let doc = Document {
cx: self.cx,
which,
scope,
};
if !out.iter().any(|d| d.key() == doc.key()) {
out.push(doc);
}
}
}
out
}
pub fn security_classifications(&self) -> Vec<SecurityClassification<'m>> {
security_classifications_of(self.cx, &self.metadata_targets())
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum Scope {
Product,
Version,
Definition,
}
fn scope_of(k: m::EntityKey) -> Scope {
match k {
m::EntityKey::Product(_) => Scope::Product,
m::EntityKey::ProductDefinitionFormation(_)
| m::EntityKey::ProductDefinitionFormationWithSpecifiedSource(_) => Scope::Version,
_ => Scope::Definition,
}
}
#[derive(Clone, Copy)]
pub enum Target<'m> {
Product(Product<'m>),
Version(Version<'m>),
Definition(ProductDef<'m>),
}
impl Target<'_> {
pub fn scope(&self) -> Scope {
match self {
Target::Product(_) => Scope::Product,
Target::Version(_) => Scope::Version,
Target::Definition(_) => Scope::Definition,
}
}
}
fn target_of(cx: Ctx<'_>, k: m::EntityKey) -> Option<Target<'_>> {
Some(match k {
m::EntityKey::Product(id) => Target::Product(Product { cx, id }),
m::EntityKey::ProductDefinitionFormation(id) => Target::Version(Version {
cx,
which: FormImpl::Plain(id),
}),
m::EntityKey::ProductDefinitionFormationWithSpecifiedSource(id) => {
Target::Version(Version {
cx,
which: FormImpl::WithSource(id),
})
}
other => return ProductDef::from_key(cx, other).map(Target::Definition),
})
}
fn targets_from_keys<'m>(cx: Ctx<'m>, keys: impl Iterator<Item = m::EntityKey>) -> Vec<Target<'m>> {
let mut out: Vec<Target<'m>> = Vec::new();
let mut seen: Vec<m::EntityKey> = Vec::new();
for k in keys {
if seen.contains(&k) {
continue;
}
seen.push(k);
if let Some(t) = target_of(cx, k) {
out.push(t);
}
}
out
}
fn contributors_of<'m>(cx: Ctx<'m>, targets: &[m::EntityKey]) -> Vec<Contributor<'m>> {
let rg = cx.ref_graph();
let mut out: Vec<Contributor<'m>> = Vec::new();
let mut seen: Vec<m::EntityKey> = Vec::new();
for &t in targets {
let scope = scope_of(t);
for r in rg.referrers(t) {
let which = match r {
m::EntityKey::CcDesignPersonAndOrganizationAssignment(id) => {
ContributorImpl::CcDesign(*id)
}
m::EntityKey::AppliedPersonAndOrganizationAssignment(id) => {
ContributorImpl::Applied(*id)
}
_ => continue,
};
if seen.contains(r) {
continue;
}
seen.push(*r);
out.push(Contributor { cx, which, scope });
}
}
out
}
fn approvals_of<'m>(cx: Ctx<'m>, targets: &[m::EntityKey]) -> Vec<Approval<'m>> {
let rg = cx.ref_graph();
let mut out: Vec<Approval<'m>> = Vec::new();
let mut seen: Vec<m::ApprovalId> = Vec::new();
for &t in targets {
let scope = scope_of(t);
for r in rg.referrers(t) {
let m::ApprovalRef::Approval(aid) = match r {
m::EntityKey::CcDesignApproval(id) => {
&cx.model
.cc_design_approval_arena
.get(id.0)
.assigned_approval
}
m::EntityKey::AppliedApprovalAssignment(id) => {
&cx.model
.applied_approval_assignment_arena
.get(id.0)
.assigned_approval
}
_ => continue,
};
if seen.contains(aid) {
continue;
}
seen.push(*aid);
out.push(Approval {
cx,
id: *aid,
scope,
});
}
}
out
}
fn documents_of<'m>(cx: Ctx<'m>, targets: &[m::EntityKey]) -> Vec<Document<'m>> {
let rg = cx.ref_graph();
let mut out: Vec<Document<'m>> = Vec::new();
let mut seen: Vec<m::EntityKey> = Vec::new();
for &t in targets {
let scope = scope_of(t);
for r in rg.referrers(t) {
let m::EntityKey::AppliedDocumentReference(id) = r else {
continue;
};
let which = match &cx
.model
.applied_document_reference_arena
.get(id.0)
.assigned_document
{
m::DocumentRef::Document(i) => DocImpl::Document(*i),
m::DocumentRef::DocumentFile(i) => DocImpl::DocumentFile(*i),
m::DocumentRef::Complex(_) => {
cx.warn(
"APPLIED_DOCUMENT_REFERENCE.assigned_document is a complex instance; \
document left unread"
.to_owned(),
);
continue;
}
};
let doc = Document { cx, which, scope };
let k = doc.key();
if seen.contains(&k) {
continue;
}
seen.push(k);
out.push(doc);
}
}
out
}
fn security_classifications_of<'m>(
cx: Ctx<'m>,
targets: &[m::EntityKey],
) -> Vec<SecurityClassification<'m>> {
let rg = cx.ref_graph();
let mut out: Vec<SecurityClassification<'m>> = Vec::new();
let mut seen: Vec<m::SecurityClassificationId> = Vec::new();
for &t in targets {
let scope = scope_of(t);
for r in rg.referrers(t) {
let m::SecurityClassificationRef::SecurityClassification(sid) = match r {
m::EntityKey::CcDesignSecurityClassification(id) => {
&cx.model
.cc_design_security_classification_arena
.get(id.0)
.assigned_security_classification
}
m::EntityKey::AppliedSecurityClassificationAssignment(id) => {
&cx.model
.applied_security_classification_assignment_arena
.get(id.0)
.assigned_security_classification
}
_ => continue,
};
if seen.contains(sid) {
continue;
}
seen.push(*sid);
out.push(SecurityClassification {
cx,
id: *sid,
scope,
});
}
}
out
}
#[derive(Clone, Copy)]
enum ContributorImpl {
CcDesign(m::CcDesignPersonAndOrganizationAssignmentId),
Applied(m::AppliedPersonAndOrganizationAssignmentId),
}
#[derive(Clone, Copy)]
pub struct Contributor<'m> {
cx: Ctx<'m>,
which: ContributorImpl,
scope: Scope,
}
impl<'m> Contributor<'m> {
pub fn assigned_scope(&self) -> Scope {
self.scope
}
pub fn assigned_targets(&self) -> Vec<Target<'m>> {
let cx = self.cx;
let keys: Vec<m::EntityKey> = match self.which {
ContributorImpl::CcDesign(i) => cx
.model
.cc_design_person_and_organization_assignment_arena
.get(i.0)
.items
.iter()
.map(m::CcPersonOrganizationItemRef::entity_key)
.collect(),
ContributorImpl::Applied(i) => cx
.model
.applied_person_and_organization_assignment_arena
.get(i.0)
.items
.iter()
.map(m::PersonAndOrganizationItemRef::entity_key)
.collect(),
};
targets_from_keys(cx, keys.into_iter())
}
fn ids(&self) -> (m::PersonAndOrganizationId, m::PersonAndOrganizationRoleId) {
let model = self.cx.model;
let (pao, role) = match self.which {
ContributorImpl::CcDesign(i) => {
let a = model
.cc_design_person_and_organization_assignment_arena
.get(i.0);
(&a.assigned_person_and_organization, &a.role)
}
ContributorImpl::Applied(i) => {
let a = model
.applied_person_and_organization_assignment_arena
.get(i.0);
(&a.assigned_person_and_organization, &a.role)
}
};
let m::PersonAndOrganizationRef::PersonAndOrganization(pid) = pao;
let m::PersonAndOrganizationRoleRef::PersonAndOrganizationRole(rid) = role;
(*pid, *rid)
}
pub fn role(&self) -> &'m str {
let (_, rid) = self.ids();
&self
.cx
.model
.person_and_organization_role_arena
.get(rid.0)
.name
}
pub fn person(&self) -> Person<'m> {
let (pao, _) = self.ids();
let m::PersonRef::Person(pid) = &self
.cx
.model
.person_and_organization_arena
.get(pao.0)
.the_person;
Person {
cx: self.cx,
id: *pid,
}
}
pub fn organization(&self) -> &'m str {
let (pao, _) = self.ids();
let m::OrganizationRef::Organization(oid) = &self
.cx
.model
.person_and_organization_arena
.get(pao.0)
.the_organization;
&self.cx.model.organization_arena.get(oid.0).name
}
}
#[derive(Clone, Copy)]
pub struct Person<'m> {
cx: Ctx<'m>,
id: m::PersonId,
}
impl<'m> Person<'m> {
fn raw(&self) -> &'m m::Person {
self.cx.model.person_arena.get(self.id.0)
}
pub fn key(&self) -> m::EntityKey {
m::EntityKey::Person(self.id)
}
pub fn id(&self) -> &'m str {
&self.raw().id
}
pub fn first_name(&self) -> Option<&'m str> {
self.raw().first_name.as_deref()
}
pub fn last_name(&self) -> Option<&'m str> {
self.raw().last_name.as_deref()
}
}
#[derive(Clone, Copy, Debug)]
pub struct Placement {
pub origin: [f64; 3],
pub axis: [f64; 3],
pub ref_direction: [f64; 3],
}
#[derive(Clone, Copy, Debug)]
pub struct Transform {
pub from: Placement,
pub to: Placement,
}
fn vdot(a: [f64; 3], b: [f64; 3]) -> f64 {
a[0] * b[0] + a[1] * b[1] + a[2] * b[2]
}
fn vsub(a: [f64; 3], b: [f64; 3]) -> [f64; 3] {
[a[0] - b[0], a[1] - b[1], a[2] - b[2]]
}
fn vscale(a: [f64; 3], s: f64) -> [f64; 3] {
[a[0] * s, a[1] * s, a[2] * s]
}
fn vcross(a: [f64; 3], b: [f64; 3]) -> [f64; 3] {
[
a[1] * b[2] - a[2] * b[1],
a[2] * b[0] - a[0] * b[2],
a[0] * b[1] - a[1] * b[0],
]
}
fn vnorm(a: [f64; 3]) -> Option<[f64; 3]> {
let n = vdot(a, a).sqrt();
(n >= 1e-12).then(|| vscale(a, 1.0 / n))
}
impl Placement {
fn frame(&self) -> Option<([f64; 3], [f64; 3], [f64; 3])> {
let z = vnorm(self.axis)?;
let x = vnorm(vsub(
self.ref_direction,
vscale(z, vdot(self.ref_direction, z)),
))?;
Some((x, vcross(z, x), z))
}
}
impl Transform {
#[allow(clippy::needless_range_loop)]
pub fn matrix(&self) -> Option<[[f64; 4]; 4]> {
let rf = self.from.frame()?; let rt = self.to.frame()?; let (rf, rt) = ([rf.0, rf.1, rf.2], [rt.0, rt.1, rt.2]);
let mut m = [[0.0_f64; 4]; 4];
for i in 0..3 {
for j in 0..3 {
m[i][j] = (0..3).map(|k| rt[k][i] * rf[k][j]).sum();
}
}
for i in 0..3 {
m[i][3] =
self.to.origin[i] - (0..3).map(|j| m[i][j] * self.from.origin[j]).sum::<f64>();
}
m[3][3] = 1.0;
Some(m)
}
}
#[derive(Clone, Copy)]
pub struct Occurrence<'m> {
cx: Ctx<'m>,
id: m::NextAssemblyUsageOccurrenceId,
}
impl<'m> Occurrence<'m> {
fn raw(&self) -> &'m m::NextAssemblyUsageOccurrence {
self.cx
.model
.next_assembly_usage_occurrence_arena
.get(self.id.0)
}
pub fn key(&self) -> m::EntityKey {
m::EntityKey::NextAssemblyUsageOccurrence(self.id)
}
pub fn definition(&self) -> Option<ProductDef<'m>> {
pdor_to_def(self.cx, &self.raw().related_product_definition)
}
pub fn transform(&self) -> Option<Transform> {
let cx = self.cx;
let rg = cx.ref_graph();
let me = self.id;
for r in rg.referrers(m::EntityKey::NextAssemblyUsageOccurrence(me)) {
let m::EntityKey::ProductDefinitionShape(pds_id) = r else {
continue;
};
let pds = cx.model.product_definition_shape_arena.get(pds_id.0);
if !matches!(&pds.definition, m::CharacterizedDefinitionRef::NextAssemblyUsageOccurrence(n) if *n == me)
{
continue;
}
for c in rg.referrers(m::EntityKey::ProductDefinitionShape(*pds_id)) {
let m::EntityKey::ContextDependentShapeRepresentation(cdsr_id) = c else {
continue;
};
let cdsr = cx
.model
.context_dependent_shape_representation_arena
.get(cdsr_id.0);
if !matches!(&cdsr.represented_product_relation, m::ProductDefinitionShapeRef::ProductDefinitionShape(p) if *p == *pds_id)
{
continue;
}
if let Some(idt) = idt_of_cdsr(cx, &cdsr.representation_relation) {
let from = resolve_placement(cx, &idt.transform_item_1)?;
let to = resolve_placement(cx, &idt.transform_item_2)?;
return Some(Transform { from, to });
}
}
}
None
}
}
impl Scene<'_> {
pub fn all_mapped_instances(&self) -> impl Iterator<Item = MappedInstance<'_>> + '_ {
let cx = self.ctx();
(0..cx.model.mapped_item_arena.items.len()).map(move |i| MappedInstance {
cx,
id: m::MappedItemId(i),
})
}
}
#[derive(Clone, Copy)]
pub struct MappedInstance<'m> {
cx: Ctx<'m>,
id: m::MappedItemId,
}
impl<'m> MappedInstance<'m> {
fn raw(&self) -> &'m m::MappedItem {
self.cx.model.mapped_item_arena.get(self.id.0)
}
pub fn name(&self) -> &'m str {
&self.raw().name
}
pub fn key(&self) -> m::EntityKey {
m::EntityKey::MappedItem(self.id)
}
fn map(&self) -> Option<&'m m::RepresentationMap> {
let m::RepresentationMapRef::RepresentationMap(id) = &self.raw().mapping_source else {
self.cx
.warn("MAPPED_ITEM.mapping_source is not a REPRESENTATION_MAP".to_owned());
return None;
};
Some(self.cx.model.representation_map_arena.get(id.0))
}
pub fn transform(&self) -> Option<Transform> {
let cx = self.cx;
let map = self.map()?;
let from = resolve_placement(cx, &map.mapping_origin)?;
let to = resolve_placement(cx, &self.raw().mapping_target)?;
Some(Transform { from, to })
}
pub fn solids(&self) -> Vec<Solid<'m>> {
let cx = self.cx;
let Some(map) = self.map() else {
return Vec::new();
};
rep_items(cx, &map.mapped_representation)
.into_iter()
.flatten()
.filter_map(|it| match it {
m::RepresentationItemRef::ManifoldSolidBrep(id) => Some(Solid::from_id(cx, *id)),
m::RepresentationItemRef::BrepWithVoids(id) => Some(Solid::from_void_id(cx, *id)),
_ => None,
})
.collect()
}
pub fn mapped_children(&self) -> Vec<MappedInstance<'m>> {
let cx = self.cx;
let Some(map) = self.map() else {
return Vec::new();
};
rep_items(cx, &map.mapped_representation)
.into_iter()
.flatten()
.filter_map(|it| match it {
m::RepresentationItemRef::MappedItem(id) => Some(MappedInstance { cx, id: *id }),
_ => None,
})
.collect()
}
}
fn rep_items<'m>(cx: Ctx<'m>, r: &m::RepresentationRef) -> Option<&'m [m::RepresentationItemRef]> {
match r {
m::RepresentationRef::ShapeRepresentation(id) => {
Some(&cx.model.shape_representation_arena.get(id.0).items)
}
m::RepresentationRef::AdvancedBrepShapeRepresentation(id) => Some(
&cx.model
.advanced_brep_shape_representation_arena
.get(id.0)
.items,
),
m::RepresentationRef::GeometricallyBoundedWireframeShapeRepresentation(id) => Some(
&cx.model
.geometrically_bounded_wireframe_shape_representation_arena
.get(id.0)
.items,
),
_ => None,
}
}
fn idt_of_cdsr<'m>(
cx: Ctx<'m>,
rr: &m::ShapeRepresentationRelationshipRef,
) -> Option<&'m m::ItemDefinedTransformation> {
let m::ShapeRepresentationRelationshipRef::Complex(cuid) = rr else {
return None;
};
let op = cx
.model
.complex_unit_arena
.get(cuid.0)
.parts
.iter()
.find_map(|p| match p {
m::UnitPart::RepresentationRelationshipWithTransformation {
transformation_operator,
} => Some(transformation_operator),
_ => None,
})?;
let m::TransformationRef::ItemDefinedTransformation(id) = op else {
return None;
};
Some(cx.model.item_defined_transformation_arena.get(id.0))
}
fn resolve_placement(cx: Ctx<'_>, item: &m::RepresentationItemRef) -> Option<Placement> {
let m::RepresentationItemRef::Axis2Placement3d(id) = item else {
cx.warn("transform item is not an AXIS2_PLACEMENT_3D".to_owned());
return None;
};
let a = cx.model.axis2_placement3d_arena.get(id.0);
Some(Placement {
origin: point3(cx, &a.location),
axis: a.axis.as_ref().map_or([0.0, 0.0, 1.0], |d| dir3(cx, d)),
ref_direction: a
.ref_direction
.as_ref()
.map_or([1.0, 0.0, 0.0], |d| dir3(cx, d)),
})
}
fn point3(cx: Ctx<'_>, r: &m::CartesianPointRef) -> [f64; 3] {
if let m::CartesianPointRef::CartesianPoint(id) = r {
let c = &cx.model.cartesian_point_arena.get(id.0).coordinates;
[
c.first().copied().unwrap_or(0.0),
c.get(1).copied().unwrap_or(0.0),
c.get(2).copied().unwrap_or(0.0),
]
} else {
[0.0; 3]
}
}
fn dir3(cx: Ctx<'_>, r: &m::DirectionRef) -> [f64; 3] {
if let m::DirectionRef::Direction(id) = r {
let c = &cx.model.direction_arena.get(id.0).direction_ratios;
[
c.first().copied().unwrap_or(0.0),
c.get(1).copied().unwrap_or(0.0),
c.get(2).copied().unwrap_or(0.0),
]
} else {
[0.0; 3]
}
}
fn pdor_is(r: &m::ProductDefinitionOrReferenceRef, key: m::EntityKey) -> bool {
match r {
m::ProductDefinitionOrReferenceRef::ProductDefinition(i) => {
m::EntityKey::ProductDefinition(*i) == key
}
m::ProductDefinitionOrReferenceRef::ProductDefinitionWithAssociatedDocuments(i) => {
m::EntityKey::ProductDefinitionWithAssociatedDocuments(*i) == key
}
_ => false,
}
}
fn pdor_to_def<'m>(cx: Ctx<'m>, r: &m::ProductDefinitionOrReferenceRef) -> Option<ProductDef<'m>> {
match r {
m::ProductDefinitionOrReferenceRef::ProductDefinition(i) => {
ProductDef::from_key(cx, m::EntityKey::ProductDefinition(*i))
}
m::ProductDefinitionOrReferenceRef::ProductDefinitionWithAssociatedDocuments(i) => {
ProductDef::from_key(
cx,
m::EntityKey::ProductDefinitionWithAssociatedDocuments(*i),
)
}
_ => None,
}
}
fn cdef_is(cd: &m::CharacterizedDefinitionRef, key: m::EntityKey) -> bool {
match cd {
m::CharacterizedDefinitionRef::ProductDefinition(i) => {
m::EntityKey::ProductDefinition(*i) == key
}
m::CharacterizedDefinitionRef::ProductDefinitionWithAssociatedDocuments(i) => {
m::EntityKey::ProductDefinitionWithAssociatedDocuments(*i) == key
}
_ => false,
}
}
fn collect_solids_from_repr<'m>(
cx: Ctx<'m>,
r: &m::RepresentationRef,
out: &mut Vec<Solid<'m>>,
visited: &mut HashSet<m::EntityKey>,
) {
let (key, items): (m::EntityKey, &[m::RepresentationItemRef]) = match r {
m::RepresentationRef::ShapeRepresentation(i) => (
m::EntityKey::ShapeRepresentation(*i),
&cx.model.shape_representation_arena.get(i.0).items,
),
m::RepresentationRef::AdvancedBrepShapeRepresentation(i) => (
m::EntityKey::AdvancedBrepShapeRepresentation(*i),
&cx.model
.advanced_brep_shape_representation_arena
.get(i.0)
.items,
),
_ => return,
};
if !visited.insert(key) {
return;
}
for it in items {
match it {
m::RepresentationItemRef::ManifoldSolidBrep(sid) => out.push(Solid::from_id(cx, *sid)),
m::RepresentationItemRef::BrepWithVoids(sid) => {
out.push(Solid::from_void_id(cx, *sid));
}
_ => {}
}
}
let rg = cx.ref_graph();
for referrer in rg.referrers(key) {
let m::EntityKey::ShapeRepresentationRelationship(srr_id) = referrer else {
continue;
};
let srr = cx
.model
.shape_representation_relationship_arena
.get(srr_id.0);
let (k1, k2) = (srr.rep_1.entity_key(), srr.rep_2.entity_key());
let other = if k1 == key {
k2
} else if k2 == key {
k1
} else {
continue;
};
if let Ok(other_ref) = m::RepresentationRef::from_any(other) {
collect_solids_from_repr(cx, &other_ref, out, visited);
}
}
}
#[derive(Clone, Copy)]
pub struct Approval<'m> {
cx: Ctx<'m>,
id: m::ApprovalId,
scope: Scope,
}
impl<'m> Approval<'m> {
fn raw(&self) -> &'m m::Approval {
self.cx.model.approval_arena.get(self.id.0)
}
pub fn key(&self) -> m::EntityKey {
m::EntityKey::Approval(self.id)
}
pub fn assigned_scope(&self) -> Scope {
self.scope
}
pub fn assigned_targets(&self) -> Vec<Target<'m>> {
let cx = self.cx;
let mut keys: Vec<m::EntityKey> = Vec::new();
for r in cx.ref_graph().referrers(self.key()) {
match r {
m::EntityKey::CcDesignApproval(i) => keys.extend(
cx.model
.cc_design_approval_arena
.get(i.0)
.items
.iter()
.map(m::ApprovedItemRef::entity_key),
),
m::EntityKey::AppliedApprovalAssignment(i) => keys.extend(
cx.model
.applied_approval_assignment_arena
.get(i.0)
.items
.iter()
.map(m::ApprovalItemRef::entity_key),
),
_ => {}
}
}
targets_from_keys(cx, keys.into_iter())
}
pub fn status(&self) -> &'m str {
let m::ApprovalStatusRef::ApprovalStatus(sid) = &self.raw().status;
&self.cx.model.approval_status_arena.get(sid.0).name
}
pub fn level(&self) -> &'m str {
&self.raw().level
}
pub fn approvers(&self) -> Vec<Approver<'m>> {
let cx = self.cx;
let mut out: Vec<Approver<'m>> = Vec::new();
for r in cx.ref_graph().referrers(self.key()) {
if let m::EntityKey::ApprovalPersonOrganization(id) = r {
out.push(Approver { cx, id: *id });
}
}
out
}
pub fn date(&self) -> Option<ApprovalDate> {
let cx = self.cx;
for r in cx.ref_graph().referrers(self.key()) {
if let m::EntityKey::ApprovalDateTime(id) = r {
let dt = &cx.model.approval_date_time_arena.get(id.0).date_time;
return resolve_datetime(cx, dt);
}
}
None
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct ApprovalDate {
pub year: Option<i64>,
pub month: Option<i64>,
pub day: Option<i64>,
pub hour: Option<i64>,
pub minute: Option<i64>,
}
fn resolve_datetime(cx: Ctx<'_>, r: &m::DateTimeSelectRef) -> Option<ApprovalDate> {
let mut d = ApprovalDate::default();
match r {
m::DateTimeSelectRef::CalendarDate(i) => set_calendar(cx, &mut d, *i),
m::DateTimeSelectRef::Date(i) => {
d.year = Some(cx.model.date_arena.get(i.0).year_component);
}
m::DateTimeSelectRef::DateAndTime(i) => {
let dt = cx.model.date_and_time_arena.get(i.0);
set_date(cx, &mut d, &dt.date_component);
let m::LocalTimeRef::LocalTime(lt) = &dt.time_component;
set_time(cx, &mut d, *lt);
}
m::DateTimeSelectRef::LocalTime(i) => set_time(cx, &mut d, *i),
m::DateTimeSelectRef::Complex(_) => {
cx.warn(
"APPROVAL_DATE_TIME.date_time is a complex instance; date left unread".to_owned(),
);
return None;
}
}
Some(d)
}
fn set_date(cx: Ctx<'_>, d: &mut ApprovalDate, r: &m::DateRef) {
match r {
m::DateRef::CalendarDate(i) => set_calendar(cx, d, *i),
m::DateRef::Date(i) => d.year = Some(cx.model.date_arena.get(i.0).year_component),
m::DateRef::Complex(_) => {}
}
}
fn set_calendar(cx: Ctx<'_>, d: &mut ApprovalDate, i: m::CalendarDateId) {
let c = cx.model.calendar_date_arena.get(i.0);
d.year = Some(c.year_component);
d.month = Some(c.month_component);
d.day = Some(c.day_component);
}
fn set_time(cx: Ctx<'_>, d: &mut ApprovalDate, i: m::LocalTimeId) {
let t = cx.model.local_time_arena.get(i.0);
d.hour = Some(t.hour_component);
d.minute = t.minute_component;
}
#[derive(Clone, Copy)]
pub struct Approver<'m> {
cx: Ctx<'m>,
id: m::ApprovalPersonOrganizationId,
}
impl<'m> Approver<'m> {
fn raw(&self) -> &'m m::ApprovalPersonOrganization {
self.cx
.model
.approval_person_organization_arena
.get(self.id.0)
}
pub fn role(&self) -> &'m str {
let m::ApprovalRoleRef::ApprovalRole(rid) = &self.raw().role;
&self.cx.model.approval_role_arena.get(rid.0).role
}
pub fn person(&self) -> Option<Person<'m>> {
let pid = match &self.raw().person_organization {
m::PersonOrganizationSelectRef::Person(i) => *i,
m::PersonOrganizationSelectRef::PersonAndOrganization(i) => {
let m::PersonRef::Person(p) = &self
.cx
.model
.person_and_organization_arena
.get(i.0)
.the_person;
*p
}
m::PersonOrganizationSelectRef::Organization(_) => return None,
};
Some(Person {
cx: self.cx,
id: pid,
})
}
pub fn organization(&self) -> Option<&'m str> {
let oid = match &self.raw().person_organization {
m::PersonOrganizationSelectRef::Organization(i) => *i,
m::PersonOrganizationSelectRef::PersonAndOrganization(i) => {
let m::OrganizationRef::Organization(o) = &self
.cx
.model
.person_and_organization_arena
.get(i.0)
.the_organization;
*o
}
m::PersonOrganizationSelectRef::Person(_) => return None,
};
Some(&self.cx.model.organization_arena.get(oid.0).name)
}
}
#[derive(Clone, Copy)]
enum DocImpl {
Document(m::DocumentId),
DocumentFile(m::DocumentFileId),
}
#[derive(Clone, Copy)]
pub struct Document<'m> {
cx: Ctx<'m>,
which: DocImpl,
scope: Scope,
}
impl<'m> Document<'m> {
pub fn assigned_scope(&self) -> Scope {
self.scope
}
pub fn assigned_targets(&self) -> Vec<Target<'m>> {
let cx = self.cx;
let mut keys: Vec<m::EntityKey> = Vec::new();
for r in cx.ref_graph().referrers(self.key()) {
if let m::EntityKey::AppliedDocumentReference(i) = r {
keys.extend(
cx.model
.applied_document_reference_arena
.get(i.0)
.items
.iter()
.map(m::DocumentReferenceItemRef::entity_key),
);
}
}
targets_from_keys(cx, keys.into_iter())
}
fn fields(&self) -> (&'m str, &'m str, Option<&'m str>, &'m m::DocumentTypeRef) {
let model = self.cx.model;
match self.which {
DocImpl::Document(i) => {
let d = model.document_arena.get(i.0);
(&d.id, &d.name, d.description.as_deref(), &d.kind)
}
DocImpl::DocumentFile(i) => {
let d = model.document_file_arena.get(i.0);
(&d.id, &d.name, d.description.as_deref(), &d.kind)
}
}
}
pub fn key(&self) -> m::EntityKey {
match self.which {
DocImpl::Document(i) => m::EntityKey::Document(i),
DocImpl::DocumentFile(i) => m::EntityKey::DocumentFile(i),
}
}
pub fn id(&self) -> &'m str {
self.fields().0
}
pub fn name(&self) -> &'m str {
self.fields().1
}
pub fn description(&self) -> Option<&'m str> {
self.fields().2
}
pub fn kind(&self) -> &'m str {
let m::DocumentTypeRef::DocumentType(tid) = self.fields().3;
&self
.cx
.model
.document_type_arena
.get(tid.0)
.product_data_type
}
}
#[derive(Clone, Copy)]
pub struct SecurityClassification<'m> {
cx: Ctx<'m>,
id: m::SecurityClassificationId,
scope: Scope,
}
impl<'m> SecurityClassification<'m> {
fn raw(&self) -> &'m m::SecurityClassification {
self.cx.model.security_classification_arena.get(self.id.0)
}
pub fn key(&self) -> m::EntityKey {
m::EntityKey::SecurityClassification(self.id)
}
pub fn assigned_scope(&self) -> Scope {
self.scope
}
pub fn assigned_targets(&self) -> Vec<Target<'m>> {
let cx = self.cx;
let mut keys: Vec<m::EntityKey> = Vec::new();
for r in cx.ref_graph().referrers(self.key()) {
match r {
m::EntityKey::CcDesignSecurityClassification(i) => keys.extend(
cx.model
.cc_design_security_classification_arena
.get(i.0)
.items
.iter()
.map(m::CcClassifiedItemRef::entity_key),
),
m::EntityKey::AppliedSecurityClassificationAssignment(i) => keys.extend(
cx.model
.applied_security_classification_assignment_arena
.get(i.0)
.items
.iter()
.map(m::SecurityClassificationItemRef::entity_key),
),
_ => {}
}
}
targets_from_keys(cx, keys.into_iter())
}
pub fn name(&self) -> &'m str {
&self.raw().name
}
pub fn purpose(&self) -> &'m str {
&self.raw().purpose
}
pub fn level(&self) -> &'m str {
let m::SecurityClassificationLevelRef::SecurityClassificationLevel(lid) =
&self.raw().security_level;
&self
.cx
.model
.security_classification_level_arena
.get(lid.0)
.name
}
}