1#![allow(clippy::must_use_candidate)]
13
14use crate::generated::model as m;
15use crate::scene::geometry::Solid;
16use crate::scene::pmi;
17use crate::scene::{Ctx, Scene};
18
19impl Scene<'_> {
20 pub fn all_products(&self) -> impl Iterator<Item = Product<'_>> + '_ {
22 let cx = self.ctx();
23 (0..cx.model.product_arena.items.len()).map(move |i| Product {
24 cx,
25 id: m::ProductId(i),
26 })
27 }
28
29 pub fn all_product_definitions(&self) -> impl Iterator<Item = ProductDef<'_>> + '_ {
31 let cx = self.ctx();
32 (0..cx.model.product_definition_arena.items.len()).map(move |i| ProductDef {
33 cx,
34 id: m::ProductDefinitionId(i),
35 })
36 }
37
38 pub fn root_definitions(&self) -> impl Iterator<Item = ProductDef<'_>> + '_ {
42 let cx = self.ctx();
43 let rg = cx.ref_graph();
44 self.all_product_definitions().filter(move |def| {
45 !rg.referrers(def.key()).iter().any(|r| {
46 let m::EntityKey::NextAssemblyUsageOccurrence(nid) = r else {
47 return false;
48 };
49 let nauo = cx.model.next_assembly_usage_occurrence_arena.get(nid.0);
50 matches!(
51 &nauo.related_product_definition,
52 m::ProductDefinitionOrReferenceRef::ProductDefinition(d) if m::EntityKey::ProductDefinition(*d) == def.key()
53 )
54 })
55 })
56 }
57}
58
59#[derive(Clone, Copy)]
65pub struct Product<'m> {
66 cx: Ctx<'m>,
67 id: m::ProductId,
68}
69
70impl<'m> Product<'m> {
71 fn raw(&self) -> &'m m::Product {
72 self.cx.model.product_arena.get(self.id.0)
73 }
74
75 pub fn key(&self) -> m::EntityKey {
78 m::EntityKey::Product(self.id)
79 }
80
81 pub fn id(&self) -> &'m str {
82 &self.raw().id
83 }
84
85 pub fn name(&self) -> &'m str {
86 &self.raw().name
87 }
88
89 pub fn description(&self) -> Option<&'m str> {
90 self.raw().description.as_deref()
91 }
92
93 pub fn definitions(&self) -> impl Iterator<Item = ProductDef<'m>> + 'm {
101 let cx = self.cx;
102 let rg = cx.ref_graph();
103 let mut out: Vec<ProductDef<'m>> = Vec::new();
104 for &fr in rg.referrers(m::EntityKey::Product(self.id)) {
105 if !matches!(
106 fr,
107 m::EntityKey::ProductDefinitionFormation(_)
108 | m::EntityKey::ProductDefinitionFormationWithSpecifiedSource(_)
109 ) {
110 continue;
111 }
112 for &pr in rg.referrers(fr) {
113 if let m::EntityKey::ProductDefinition(pdid) = pr {
114 out.push(ProductDef { cx, id: pdid });
115 }
116 }
117 }
118 out.into_iter()
119 }
120
121 fn metadata_targets(&self) -> Vec<m::EntityKey> {
128 let rg = self.cx.ref_graph();
129 let mut targets = vec![self.key()];
130 for &fr in rg.referrers(self.key()) {
131 if !matches!(
132 fr,
133 m::EntityKey::ProductDefinitionFormation(_)
134 | m::EntityKey::ProductDefinitionFormationWithSpecifiedSource(_)
135 ) {
136 continue;
137 }
138 targets.push(fr);
139 for &pr in rg.referrers(fr) {
140 if matches!(pr, m::EntityKey::ProductDefinition(_)) {
141 targets.push(pr);
142 }
143 }
144 }
145 targets
146 }
147
148 pub fn contributors(&self) -> Vec<Contributor<'m>> {
151 contributors_of(self.cx, &self.metadata_targets())
152 }
153
154 pub fn approvals(&self) -> Vec<Approval<'m>> {
157 approvals_of(self.cx, &self.metadata_targets())
158 }
159
160 pub fn documents(&self) -> Vec<Document<'m>> {
162 documents_of(self.cx, &self.metadata_targets())
163 }
164
165 pub fn security_classifications(&self) -> Vec<SecurityClassification<'m>> {
167 security_classifications_of(self.cx, &self.metadata_targets())
168 }
169
170 pub fn versions(&self) -> Vec<Version<'m>> {
174 let cx = self.cx;
175 let rg = cx.ref_graph();
176 let mut out: Vec<Version<'m>> = Vec::new();
177 for r in rg.referrers(self.key()) {
178 let which = match r {
179 m::EntityKey::ProductDefinitionFormation(id) => FormImpl::Plain(*id),
180 m::EntityKey::ProductDefinitionFormationWithSpecifiedSource(id) => {
181 FormImpl::WithSource(*id)
182 }
183 _ => continue,
184 };
185 out.push(Version { cx, which });
186 }
187 out
188 }
189}
190
191#[derive(Clone, Copy)]
196pub struct Version<'m> {
197 cx: Ctx<'m>,
198 which: FormImpl,
199}
200
201#[derive(Clone, Copy)]
202enum FormImpl {
203 Plain(m::ProductDefinitionFormationId),
204 WithSource(m::ProductDefinitionFormationWithSpecifiedSourceId),
205}
206
207impl<'m> Version<'m> {
208 fn fields(&self) -> (&'m str, Option<&'m str>) {
211 let model = self.cx.model;
212 match self.which {
213 FormImpl::Plain(i) => {
214 let f = model.product_definition_formation_arena.get(i.0);
215 (&f.id, f.description.as_deref())
216 }
217 FormImpl::WithSource(i) => {
218 let f = model
219 .product_definition_formation_with_specified_source_arena
220 .get(i.0);
221 (&f.id, f.description.as_deref())
222 }
223 }
224 }
225
226 pub fn key(&self) -> m::EntityKey {
228 match self.which {
229 FormImpl::Plain(i) => m::EntityKey::ProductDefinitionFormation(i),
230 FormImpl::WithSource(i) => {
231 m::EntityKey::ProductDefinitionFormationWithSpecifiedSource(i)
232 }
233 }
234 }
235
236 pub fn id(&self) -> &'m str {
238 self.fields().0
239 }
240
241 pub fn description(&self) -> Option<&'m str> {
243 self.fields().1
244 }
245
246 pub fn definitions(&self) -> impl Iterator<Item = ProductDef<'m>> + 'm {
249 let cx = self.cx;
250 let rg = cx.ref_graph();
251 let mut out: Vec<ProductDef<'m>> = Vec::new();
252 for &r in rg.referrers(self.key()) {
253 if let m::EntityKey::ProductDefinition(pdid) = r {
254 out.push(ProductDef { cx, id: pdid });
255 }
256 }
257 out.into_iter()
258 }
259}
260
261#[derive(Clone, Copy)]
268pub struct ProductDef<'m> {
269 cx: Ctx<'m>,
270 id: m::ProductDefinitionId,
271}
272
273impl<'m> ProductDef<'m> {
274 fn raw(&self) -> &'m m::ProductDefinition {
275 self.cx.model.product_definition_arena.get(self.id.0)
276 }
277
278 pub fn key(&self) -> m::EntityKey {
281 m::EntityKey::ProductDefinition(self.id)
282 }
283
284 pub fn id(&self) -> &'m str {
285 &self.raw().id
286 }
287
288 pub fn description(&self) -> Option<&'m str> {
289 self.raw().description.as_deref()
290 }
291
292 pub fn product(&self) -> Option<Product<'m>> {
294 let model = self.cx.model;
295 let of_product: &m::ProductRef = match &self.raw().formation {
296 m::ProductDefinitionFormationRef::ProductDefinitionFormation(i) => {
297 &model.product_definition_formation_arena.get(i.0).of_product
298 }
299 m::ProductDefinitionFormationRef::ProductDefinitionFormationWithSpecifiedSource(i) => {
300 &model
301 .product_definition_formation_with_specified_source_arena
302 .get(i.0)
303 .of_product
304 }
305 m::ProductDefinitionFormationRef::Complex(_) => return None,
306 };
307 match of_product {
308 m::ProductRef::Product(pid) => Some(Product {
309 cx: self.cx,
310 id: *pid,
311 }),
312 m::ProductRef::Complex(_) => None,
313 }
314 }
315
316 pub fn occurrences(&self) -> impl Iterator<Item = Occurrence<'m>> + 'm {
320 let cx = self.cx;
321 let rg = cx.ref_graph();
322 let me = self.id;
323 let mut out: Vec<Occurrence<'m>> = Vec::new();
324 for r in rg.referrers(m::EntityKey::ProductDefinition(me)) {
325 if let m::EntityKey::NextAssemblyUsageOccurrence(nid) = r {
326 let nauo = cx.model.next_assembly_usage_occurrence_arena.get(nid.0);
327 if pdor_is(&nauo.relating_product_definition, me) {
328 out.push(Occurrence { cx, id: *nid });
329 }
330 }
331 }
332 out.into_iter()
333 }
334
335 pub fn children(&self) -> impl Iterator<Item = ProductDef<'m>> + 'm {
338 self.occurrences().filter_map(|o| o.definition())
339 }
340
341 pub fn parents(&self) -> impl Iterator<Item = ProductDef<'m>> + 'm {
344 let cx = self.cx;
345 let rg = cx.ref_graph();
346 let me = self.id;
347 let mut out: Vec<ProductDef<'m>> = Vec::new();
348 for r in rg.referrers(m::EntityKey::ProductDefinition(me)) {
349 if let m::EntityKey::NextAssemblyUsageOccurrence(nid) = r {
350 let nauo = cx.model.next_assembly_usage_occurrence_arena.get(nid.0);
351 if pdor_is(&nauo.related_product_definition, me) {
352 if let Some(d) = pdor_to_def(cx, &nauo.relating_product_definition) {
353 out.push(d);
354 }
355 }
356 }
357 }
358 out.into_iter()
359 }
360
361 pub fn solids(&self) -> impl Iterator<Item = Solid<'m>> + 'm {
366 let cx = self.cx;
367 let rg = cx.ref_graph();
368 let me = self.id;
369 let mut out: Vec<Solid<'m>> = Vec::new();
370 for r in rg.referrers(m::EntityKey::ProductDefinition(me)) {
371 let m::EntityKey::ProductDefinitionShape(pds_id) = r else {
372 continue;
373 };
374 let pds = cx.model.product_definition_shape_arena.get(pds_id.0);
375 if !matches!(&pds.definition, m::CharacterizedDefinitionRef::ProductDefinition(pd) if *pd == me)
376 {
377 continue;
378 }
379 for s in rg.referrers(m::EntityKey::ProductDefinitionShape(*pds_id)) {
380 let m::EntityKey::ShapeDefinitionRepresentation(sdr_id) = s else {
381 continue;
382 };
383 let sdr = cx.model.shape_definition_representation_arena.get(sdr_id.0);
384 if matches!(&sdr.definition, m::RepresentedDefinitionRef::ProductDefinitionShape(p) if *p == *pds_id)
385 {
386 collect_solids_from_repr(cx, &sdr.used_representation, &mut out);
387 }
388 }
389 }
390 out.into_iter()
391 }
392
393 pub fn features(&self) -> impl Iterator<Item = pmi::Feature<'m>> + 'm {
397 pmi::features_of(self.cx, self.id).into_iter()
398 }
399
400 pub fn dimensions(&self) -> impl Iterator<Item = pmi::Dimension<'m>> + 'm {
402 pmi::dimensions_of(self.cx, self.id).into_iter()
403 }
404
405 pub fn tolerances(&self) -> impl Iterator<Item = pmi::Tolerance<'m>> + 'm {
408 pmi::tolerances_of(self.cx, self.id).into_iter()
409 }
410
411 pub fn datums(&self) -> impl Iterator<Item = pmi::Datum<'m>> + 'm {
413 pmi::datums_of(self.cx, self.id).into_iter()
414 }
415
416 pub fn version(&self) -> Option<&'m str> {
418 let model = self.cx.model;
419 match &self.raw().formation {
420 m::ProductDefinitionFormationRef::ProductDefinitionFormation(i) => {
421 Some(&model.product_definition_formation_arena.get(i.0).id)
422 }
423 m::ProductDefinitionFormationRef::ProductDefinitionFormationWithSpecifiedSource(i) => {
424 Some(
425 &model
426 .product_definition_formation_with_specified_source_arena
427 .get(i.0)
428 .id,
429 )
430 }
431 m::ProductDefinitionFormationRef::Complex(_) => None,
432 }
433 }
434
435 fn metadata_targets(&self) -> Vec<m::EntityKey> {
443 let mut targets = Vec::new();
444 if let Some(p) = self.product() {
445 targets.push(p.key());
446 }
447 match &self.raw().formation {
448 m::ProductDefinitionFormationRef::ProductDefinitionFormation(i) => {
449 targets.push(m::EntityKey::ProductDefinitionFormation(*i));
450 }
451 m::ProductDefinitionFormationRef::ProductDefinitionFormationWithSpecifiedSource(i) => {
452 targets.push(m::EntityKey::ProductDefinitionFormationWithSpecifiedSource(
453 *i,
454 ));
455 }
456 m::ProductDefinitionFormationRef::Complex(_) => {}
457 }
458 targets.push(m::EntityKey::ProductDefinition(self.id));
459 targets
460 }
461
462 pub fn contributors(&self) -> Vec<Contributor<'m>> {
465 contributors_of(self.cx, &self.metadata_targets())
466 }
467
468 pub fn approvals(&self) -> Vec<Approval<'m>> {
471 approvals_of(self.cx, &self.metadata_targets())
472 }
473
474 pub fn documents(&self) -> Vec<Document<'m>> {
478 documents_of(self.cx, &self.metadata_targets())
479 }
480
481 pub fn security_classifications(&self) -> Vec<SecurityClassification<'m>> {
484 security_classifications_of(self.cx, &self.metadata_targets())
485 }
486}
487
488#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
507pub enum Scope {
508 Product,
510 Version,
512 Definition,
514}
515
516fn scope_of(k: m::EntityKey) -> Scope {
519 match k {
520 m::EntityKey::Product(_) => Scope::Product,
521 m::EntityKey::ProductDefinitionFormation(_)
522 | m::EntityKey::ProductDefinitionFormationWithSpecifiedSource(_) => Scope::Version,
523 _ => Scope::Definition,
524 }
525}
526
527#[derive(Clone, Copy)]
532pub enum Target<'m> {
533 Product(Product<'m>),
534 Version(Version<'m>),
535 Definition(ProductDef<'m>),
536}
537
538impl Target<'_> {
539 pub fn scope(&self) -> Scope {
541 match self {
542 Target::Product(_) => Scope::Product,
543 Target::Version(_) => Scope::Version,
544 Target::Definition(_) => Scope::Definition,
545 }
546 }
547}
548
549fn target_of(cx: Ctx<'_>, k: m::EntityKey) -> Option<Target<'_>> {
552 Some(match k {
553 m::EntityKey::Product(id) => Target::Product(Product { cx, id }),
554 m::EntityKey::ProductDefinitionFormation(id) => Target::Version(Version {
555 cx,
556 which: FormImpl::Plain(id),
557 }),
558 m::EntityKey::ProductDefinitionFormationWithSpecifiedSource(id) => {
559 Target::Version(Version {
560 cx,
561 which: FormImpl::WithSource(id),
562 })
563 }
564 m::EntityKey::ProductDefinition(id) => Target::Definition(ProductDef { cx, id }),
565 _ => return None,
566 })
567}
568
569fn targets_from_keys<'m>(cx: Ctx<'m>, keys: impl Iterator<Item = m::EntityKey>) -> Vec<Target<'m>> {
571 let mut out: Vec<Target<'m>> = Vec::new();
572 let mut seen: Vec<m::EntityKey> = Vec::new();
573 for k in keys {
574 if seen.contains(&k) {
575 continue;
576 }
577 seen.push(k);
578 if let Some(t) = target_of(cx, k) {
579 out.push(t);
580 }
581 }
582 out
583}
584
585fn contributors_of<'m>(cx: Ctx<'m>, targets: &[m::EntityKey]) -> Vec<Contributor<'m>> {
586 let rg = cx.ref_graph();
587 let mut out: Vec<Contributor<'m>> = Vec::new();
588 let mut seen: Vec<m::EntityKey> = Vec::new();
589 for &t in targets {
590 let scope = scope_of(t);
591 for r in rg.referrers(t) {
592 let which = match r {
593 m::EntityKey::CcDesignPersonAndOrganizationAssignment(id) => {
594 ContributorImpl::CcDesign(*id)
595 }
596 m::EntityKey::AppliedPersonAndOrganizationAssignment(id) => {
597 ContributorImpl::Applied(*id)
598 }
599 _ => continue,
600 };
601 if seen.contains(r) {
602 continue;
603 }
604 seen.push(*r);
605 out.push(Contributor { cx, which, scope });
606 }
607 }
608 out
609}
610
611fn approvals_of<'m>(cx: Ctx<'m>, targets: &[m::EntityKey]) -> Vec<Approval<'m>> {
612 let rg = cx.ref_graph();
613 let mut out: Vec<Approval<'m>> = Vec::new();
614 let mut seen: Vec<m::ApprovalId> = Vec::new();
615 for &t in targets {
616 let scope = scope_of(t);
617 for r in rg.referrers(t) {
618 let m::ApprovalRef::Approval(aid) = match r {
619 m::EntityKey::CcDesignApproval(id) => {
620 &cx.model
621 .cc_design_approval_arena
622 .get(id.0)
623 .assigned_approval
624 }
625 m::EntityKey::AppliedApprovalAssignment(id) => {
626 &cx.model
627 .applied_approval_assignment_arena
628 .get(id.0)
629 .assigned_approval
630 }
631 _ => continue,
632 };
633 if seen.contains(aid) {
634 continue;
635 }
636 seen.push(*aid);
637 out.push(Approval {
638 cx,
639 id: *aid,
640 scope,
641 });
642 }
643 }
644 out
645}
646
647fn documents_of<'m>(cx: Ctx<'m>, targets: &[m::EntityKey]) -> Vec<Document<'m>> {
650 let rg = cx.ref_graph();
651 let mut out: Vec<Document<'m>> = Vec::new();
652 let mut seen: Vec<m::EntityKey> = Vec::new();
653 for &t in targets {
654 let scope = scope_of(t);
655 for r in rg.referrers(t) {
656 let m::EntityKey::AppliedDocumentReference(id) = r else {
657 continue;
658 };
659 let which = match &cx
660 .model
661 .applied_document_reference_arena
662 .get(id.0)
663 .assigned_document
664 {
665 m::DocumentRef::Document(i) => DocImpl::Document(*i),
666 m::DocumentRef::DocumentFile(i) => DocImpl::DocumentFile(*i),
667 m::DocumentRef::Complex(_) => {
668 cx.warn(
669 "APPLIED_DOCUMENT_REFERENCE.assigned_document is a complex instance; \
670 document left unread"
671 .to_owned(),
672 );
673 continue;
674 }
675 };
676 let doc = Document { cx, which, scope };
677 let k = doc.key();
678 if seen.contains(&k) {
679 continue;
680 }
681 seen.push(k);
682 out.push(doc);
683 }
684 }
685 out
686}
687
688fn security_classifications_of<'m>(
689 cx: Ctx<'m>,
690 targets: &[m::EntityKey],
691) -> Vec<SecurityClassification<'m>> {
692 let rg = cx.ref_graph();
693 let mut out: Vec<SecurityClassification<'m>> = Vec::new();
694 let mut seen: Vec<m::SecurityClassificationId> = Vec::new();
695 for &t in targets {
696 let scope = scope_of(t);
697 for r in rg.referrers(t) {
698 let m::SecurityClassificationRef::SecurityClassification(sid) = match r {
699 m::EntityKey::CcDesignSecurityClassification(id) => {
700 &cx.model
701 .cc_design_security_classification_arena
702 .get(id.0)
703 .assigned_security_classification
704 }
705 m::EntityKey::AppliedSecurityClassificationAssignment(id) => {
706 &cx.model
707 .applied_security_classification_assignment_arena
708 .get(id.0)
709 .assigned_security_classification
710 }
711 _ => continue,
712 };
713 if seen.contains(sid) {
714 continue;
715 }
716 seen.push(*sid);
717 out.push(SecurityClassification {
718 cx,
719 id: *sid,
720 scope,
721 });
722 }
723 }
724 out
725}
726
727#[derive(Clone, Copy)]
732enum ContributorImpl {
733 CcDesign(m::CcDesignPersonAndOrganizationAssignmentId),
734 Applied(m::AppliedPersonAndOrganizationAssignmentId),
735}
736
737#[derive(Clone, Copy)]
740pub struct Contributor<'m> {
741 cx: Ctx<'m>,
742 which: ContributorImpl,
743 scope: Scope,
744}
745
746impl<'m> Contributor<'m> {
747 pub fn assigned_scope(&self) -> Scope {
749 self.scope
750 }
751
752 pub fn assigned_targets(&self) -> Vec<Target<'m>> {
755 let cx = self.cx;
756 let keys: Vec<m::EntityKey> = match self.which {
757 ContributorImpl::CcDesign(i) => cx
758 .model
759 .cc_design_person_and_organization_assignment_arena
760 .get(i.0)
761 .items
762 .iter()
763 .map(m::CcPersonOrganizationItemRef::entity_key)
764 .collect(),
765 ContributorImpl::Applied(i) => cx
766 .model
767 .applied_person_and_organization_assignment_arena
768 .get(i.0)
769 .items
770 .iter()
771 .map(m::PersonAndOrganizationItemRef::entity_key)
772 .collect(),
773 };
774 targets_from_keys(cx, keys.into_iter())
775 }
776
777 fn ids(&self) -> (m::PersonAndOrganizationId, m::PersonAndOrganizationRoleId) {
780 let model = self.cx.model;
781 let (pao, role) = match self.which {
782 ContributorImpl::CcDesign(i) => {
783 let a = model
784 .cc_design_person_and_organization_assignment_arena
785 .get(i.0);
786 (&a.assigned_person_and_organization, &a.role)
787 }
788 ContributorImpl::Applied(i) => {
789 let a = model
790 .applied_person_and_organization_assignment_arena
791 .get(i.0);
792 (&a.assigned_person_and_organization, &a.role)
793 }
794 };
795 let m::PersonAndOrganizationRef::PersonAndOrganization(pid) = pao;
796 let m::PersonAndOrganizationRoleRef::PersonAndOrganizationRole(rid) = role;
797 (*pid, *rid)
798 }
799
800 pub fn role(&self) -> &'m str {
802 let (_, rid) = self.ids();
803 &self
804 .cx
805 .model
806 .person_and_organization_role_arena
807 .get(rid.0)
808 .name
809 }
810
811 pub fn person(&self) -> Person<'m> {
813 let (pao, _) = self.ids();
814 let m::PersonRef::Person(pid) = &self
815 .cx
816 .model
817 .person_and_organization_arena
818 .get(pao.0)
819 .the_person;
820 Person {
821 cx: self.cx,
822 id: *pid,
823 }
824 }
825
826 pub fn organization(&self) -> &'m str {
828 let (pao, _) = self.ids();
829 let m::OrganizationRef::Organization(oid) = &self
830 .cx
831 .model
832 .person_and_organization_arena
833 .get(pao.0)
834 .the_organization;
835 &self.cx.model.organization_arena.get(oid.0).name
836 }
837}
838
839#[derive(Clone, Copy)]
841pub struct Person<'m> {
842 cx: Ctx<'m>,
843 id: m::PersonId,
844}
845
846impl<'m> Person<'m> {
847 fn raw(&self) -> &'m m::Person {
848 self.cx.model.person_arena.get(self.id.0)
849 }
850
851 pub fn key(&self) -> m::EntityKey {
853 m::EntityKey::Person(self.id)
854 }
855
856 pub fn id(&self) -> &'m str {
858 &self.raw().id
859 }
860
861 pub fn first_name(&self) -> Option<&'m str> {
863 self.raw().first_name.as_deref()
864 }
865
866 pub fn last_name(&self) -> Option<&'m str> {
868 self.raw().last_name.as_deref()
869 }
870}
871
872#[derive(Clone, Copy, Debug)]
879pub struct Placement {
880 pub origin: [f64; 3],
881 pub axis: [f64; 3],
882 pub ref_direction: [f64; 3],
883}
884
885#[derive(Clone, Copy, Debug)]
889pub struct Transform {
890 pub from: Placement,
891 pub to: Placement,
892}
893
894fn vdot(a: [f64; 3], b: [f64; 3]) -> f64 {
898 a[0] * b[0] + a[1] * b[1] + a[2] * b[2]
899}
900fn vsub(a: [f64; 3], b: [f64; 3]) -> [f64; 3] {
901 [a[0] - b[0], a[1] - b[1], a[2] - b[2]]
902}
903fn vscale(a: [f64; 3], s: f64) -> [f64; 3] {
904 [a[0] * s, a[1] * s, a[2] * s]
905}
906fn vcross(a: [f64; 3], b: [f64; 3]) -> [f64; 3] {
907 [
908 a[1] * b[2] - a[2] * b[1],
909 a[2] * b[0] - a[0] * b[2],
910 a[0] * b[1] - a[1] * b[0],
911 ]
912}
913fn vnorm(a: [f64; 3]) -> Option<[f64; 3]> {
914 let n = vdot(a, a).sqrt();
915 (n >= 1e-12).then(|| vscale(a, 1.0 / n))
916}
917
918impl Placement {
919 fn frame(&self) -> Option<([f64; 3], [f64; 3], [f64; 3])> {
924 let z = vnorm(self.axis)?;
925 let x = vnorm(vsub(
926 self.ref_direction,
927 vscale(z, vdot(self.ref_direction, z)),
928 ))?;
929 Some((x, vcross(z, x), z))
930 }
931}
932
933impl Transform {
934 #[allow(clippy::needless_range_loop)]
945 pub fn matrix(&self) -> Option<[[f64; 4]; 4]> {
946 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]);
949 let mut m = [[0.0_f64; 4]; 4];
950 for i in 0..3 {
952 for j in 0..3 {
953 m[i][j] = (0..3).map(|k| rt[k][i] * rf[k][j]).sum();
954 }
955 }
956 for i in 0..3 {
958 m[i][3] =
959 self.to.origin[i] - (0..3).map(|j| m[i][j] * self.from.origin[j]).sum::<f64>();
960 }
961 m[3][3] = 1.0;
962 Some(m)
963 }
964}
965
966#[derive(Clone, Copy)]
969pub struct Occurrence<'m> {
970 cx: Ctx<'m>,
971 id: m::NextAssemblyUsageOccurrenceId,
972}
973
974impl<'m> Occurrence<'m> {
975 fn raw(&self) -> &'m m::NextAssemblyUsageOccurrence {
976 self.cx
977 .model
978 .next_assembly_usage_occurrence_arena
979 .get(self.id.0)
980 }
981
982 pub fn key(&self) -> m::EntityKey {
984 m::EntityKey::NextAssemblyUsageOccurrence(self.id)
985 }
986
987 pub fn definition(&self) -> Option<ProductDef<'m>> {
989 pdor_to_def(self.cx, &self.raw().related_product_definition)
990 }
991
992 pub fn transform(&self) -> Option<Transform> {
999 let cx = self.cx;
1000 let rg = cx.ref_graph();
1001 let me = self.id;
1002 for r in rg.referrers(m::EntityKey::NextAssemblyUsageOccurrence(me)) {
1003 let m::EntityKey::ProductDefinitionShape(pds_id) = r else {
1004 continue;
1005 };
1006 let pds = cx.model.product_definition_shape_arena.get(pds_id.0);
1007 if !matches!(&pds.definition, m::CharacterizedDefinitionRef::NextAssemblyUsageOccurrence(n) if *n == me)
1008 {
1009 continue;
1010 }
1011 for c in rg.referrers(m::EntityKey::ProductDefinitionShape(*pds_id)) {
1012 let m::EntityKey::ContextDependentShapeRepresentation(cdsr_id) = c else {
1013 continue;
1014 };
1015 let cdsr = cx
1016 .model
1017 .context_dependent_shape_representation_arena
1018 .get(cdsr_id.0);
1019 if !matches!(&cdsr.represented_product_relation, m::ProductDefinitionShapeRef::ProductDefinitionShape(p) if *p == *pds_id)
1020 {
1021 continue;
1022 }
1023 if let Some(idt) = idt_of_cdsr(cx, &cdsr.representation_relation) {
1024 let from = resolve_placement(cx, &idt.transform_item_1)?;
1025 let to = resolve_placement(cx, &idt.transform_item_2)?;
1026 return Some(Transform { from, to });
1027 }
1028 }
1029 }
1030 None
1031 }
1032}
1033
1034impl Scene<'_> {
1040 pub fn all_mapped_instances(&self) -> impl Iterator<Item = MappedInstance<'_>> + '_ {
1045 let cx = self.ctx();
1046 (0..cx.model.mapped_item_arena.items.len()).map(move |i| MappedInstance {
1047 cx,
1048 id: m::MappedItemId(i),
1049 })
1050 }
1051}
1052
1053#[derive(Clone, Copy)]
1056pub struct MappedInstance<'m> {
1057 cx: Ctx<'m>,
1058 id: m::MappedItemId,
1059}
1060
1061impl<'m> MappedInstance<'m> {
1062 fn raw(&self) -> &'m m::MappedItem {
1063 self.cx.model.mapped_item_arena.get(self.id.0)
1064 }
1065
1066 pub fn name(&self) -> &'m str {
1067 &self.raw().name
1068 }
1069
1070 pub fn key(&self) -> m::EntityKey {
1072 m::EntityKey::MappedItem(self.id)
1073 }
1074
1075 fn map(&self) -> Option<&'m m::RepresentationMap> {
1076 let m::RepresentationMapRef::RepresentationMap(id) = &self.raw().mapping_source else {
1077 self.cx
1078 .warn("MAPPED_ITEM.mapping_source is not a REPRESENTATION_MAP".to_owned());
1079 return None;
1080 };
1081 Some(self.cx.model.representation_map_arena.get(id.0))
1082 }
1083
1084 pub fn transform(&self) -> Option<Transform> {
1090 let cx = self.cx;
1091 let map = self.map()?;
1092 let from = resolve_placement(cx, &map.mapping_origin)?;
1093 let to = resolve_placement(cx, &self.raw().mapping_target)?;
1094 Some(Transform { from, to })
1095 }
1096
1097 pub fn solids(&self) -> Vec<Solid<'m>> {
1100 let cx = self.cx;
1101 let Some(map) = self.map() else {
1102 return Vec::new();
1103 };
1104 rep_items(cx, &map.mapped_representation)
1105 .into_iter()
1106 .flatten()
1107 .filter_map(|it| match it {
1108 m::RepresentationItemRef::ManifoldSolidBrep(id) => Some(Solid::from_id(cx, *id)),
1109 _ => None,
1110 })
1111 .collect()
1112 }
1113
1114 pub fn mapped_children(&self) -> Vec<MappedInstance<'m>> {
1117 let cx = self.cx;
1118 let Some(map) = self.map() else {
1119 return Vec::new();
1120 };
1121 rep_items(cx, &map.mapped_representation)
1122 .into_iter()
1123 .flatten()
1124 .filter_map(|it| match it {
1125 m::RepresentationItemRef::MappedItem(id) => Some(MappedInstance { cx, id: *id }),
1126 _ => None,
1127 })
1128 .collect()
1129 }
1130}
1131
1132fn rep_items<'m>(cx: Ctx<'m>, r: &m::RepresentationRef) -> Option<&'m [m::RepresentationItemRef]> {
1135 match r {
1136 m::RepresentationRef::ShapeRepresentation(id) => {
1137 Some(&cx.model.shape_representation_arena.get(id.0).items)
1138 }
1139 m::RepresentationRef::AdvancedBrepShapeRepresentation(id) => Some(
1140 &cx.model
1141 .advanced_brep_shape_representation_arena
1142 .get(id.0)
1143 .items,
1144 ),
1145 m::RepresentationRef::GeometricallyBoundedWireframeShapeRepresentation(id) => Some(
1146 &cx.model
1147 .geometrically_bounded_wireframe_shape_representation_arena
1148 .get(id.0)
1149 .items,
1150 ),
1151 _ => None,
1152 }
1153}
1154
1155fn idt_of_cdsr<'m>(
1164 cx: Ctx<'m>,
1165 rr: &m::ShapeRepresentationRelationshipRef,
1166) -> Option<&'m m::ItemDefinedTransformation> {
1167 let m::ShapeRepresentationRelationshipRef::Complex(cuid) = rr else {
1168 return None;
1169 };
1170 let op = cx
1171 .model
1172 .complex_unit_arena
1173 .get(cuid.0)
1174 .parts
1175 .iter()
1176 .find_map(|p| match p {
1177 m::UnitPart::RepresentationRelationshipWithTransformation {
1178 transformation_operator,
1179 } => Some(transformation_operator),
1180 _ => None,
1181 })?;
1182 let m::TransformationRef::ItemDefinedTransformation(id) = op else {
1183 return None;
1184 };
1185 Some(cx.model.item_defined_transformation_arena.get(id.0))
1186}
1187
1188fn resolve_placement(cx: Ctx<'_>, item: &m::RepresentationItemRef) -> Option<Placement> {
1193 let m::RepresentationItemRef::Axis2Placement3d(id) = item else {
1194 cx.warn("transform item is not an AXIS2_PLACEMENT_3D".to_owned());
1195 return None;
1196 };
1197 let a = cx.model.axis2_placement3d_arena.get(id.0);
1198 Some(Placement {
1199 origin: point3(cx, &a.location),
1200 axis: a.axis.as_ref().map_or([0.0, 0.0, 1.0], |d| dir3(cx, d)),
1201 ref_direction: a
1202 .ref_direction
1203 .as_ref()
1204 .map_or([1.0, 0.0, 0.0], |d| dir3(cx, d)),
1205 })
1206}
1207
1208fn point3(cx: Ctx<'_>, r: &m::CartesianPointRef) -> [f64; 3] {
1210 if let m::CartesianPointRef::CartesianPoint(id) = r {
1211 let c = &cx.model.cartesian_point_arena.get(id.0).coordinates;
1212 [
1213 c.first().copied().unwrap_or(0.0),
1214 c.get(1).copied().unwrap_or(0.0),
1215 c.get(2).copied().unwrap_or(0.0),
1216 ]
1217 } else {
1218 [0.0; 3]
1219 }
1220}
1221
1222fn dir3(cx: Ctx<'_>, r: &m::DirectionRef) -> [f64; 3] {
1224 if let m::DirectionRef::Direction(id) = r {
1225 let c = &cx.model.direction_arena.get(id.0).direction_ratios;
1226 [
1227 c.first().copied().unwrap_or(0.0),
1228 c.get(1).copied().unwrap_or(0.0),
1229 c.get(2).copied().unwrap_or(0.0),
1230 ]
1231 } else {
1232 [0.0; 3]
1233 }
1234}
1235
1236fn pdor_is(r: &m::ProductDefinitionOrReferenceRef, id: m::ProductDefinitionId) -> bool {
1238 matches!(r, m::ProductDefinitionOrReferenceRef::ProductDefinition(i) if *i == id)
1239}
1240
1241fn pdor_to_def<'m>(cx: Ctx<'m>, r: &m::ProductDefinitionOrReferenceRef) -> Option<ProductDef<'m>> {
1244 match r {
1245 m::ProductDefinitionOrReferenceRef::ProductDefinition(i) => Some(ProductDef { cx, id: *i }),
1246 _ => None,
1247 }
1248}
1249
1250fn collect_solids_from_repr<'m>(cx: Ctx<'m>, r: &m::RepresentationRef, out: &mut Vec<Solid<'m>>) {
1252 let items: &[m::RepresentationItemRef] = match r {
1253 m::RepresentationRef::ShapeRepresentation(i) => {
1254 &cx.model.shape_representation_arena.get(i.0).items
1255 }
1256 m::RepresentationRef::AdvancedBrepShapeRepresentation(i) => {
1257 &cx.model
1258 .advanced_brep_shape_representation_arena
1259 .get(i.0)
1260 .items
1261 }
1262 _ => return,
1263 };
1264 for it in items {
1265 if let m::RepresentationItemRef::ManifoldSolidBrep(sid) = it {
1266 out.push(Solid::from_id(cx, *sid));
1267 }
1268 }
1269}
1270
1271#[derive(Clone, Copy)]
1278pub struct Approval<'m> {
1279 cx: Ctx<'m>,
1280 id: m::ApprovalId,
1281 scope: Scope,
1282}
1283
1284impl<'m> Approval<'m> {
1285 fn raw(&self) -> &'m m::Approval {
1286 self.cx.model.approval_arena.get(self.id.0)
1287 }
1288
1289 pub fn key(&self) -> m::EntityKey {
1291 m::EntityKey::Approval(self.id)
1292 }
1293
1294 pub fn assigned_scope(&self) -> Scope {
1297 self.scope
1298 }
1299
1300 pub fn assigned_targets(&self) -> Vec<Target<'m>> {
1303 let cx = self.cx;
1304 let mut keys: Vec<m::EntityKey> = Vec::new();
1305 for r in cx.ref_graph().referrers(self.key()) {
1306 match r {
1307 m::EntityKey::CcDesignApproval(i) => keys.extend(
1308 cx.model
1309 .cc_design_approval_arena
1310 .get(i.0)
1311 .items
1312 .iter()
1313 .map(m::ApprovedItemRef::entity_key),
1314 ),
1315 m::EntityKey::AppliedApprovalAssignment(i) => keys.extend(
1316 cx.model
1317 .applied_approval_assignment_arena
1318 .get(i.0)
1319 .items
1320 .iter()
1321 .map(m::ApprovalItemRef::entity_key),
1322 ),
1323 _ => {}
1324 }
1325 }
1326 targets_from_keys(cx, keys.into_iter())
1327 }
1328
1329 pub fn status(&self) -> &'m str {
1331 let m::ApprovalStatusRef::ApprovalStatus(sid) = &self.raw().status;
1332 &self.cx.model.approval_status_arena.get(sid.0).name
1333 }
1334
1335 pub fn level(&self) -> &'m str {
1337 &self.raw().level
1338 }
1339
1340 pub fn approvers(&self) -> Vec<Approver<'m>> {
1343 let cx = self.cx;
1344 let mut out: Vec<Approver<'m>> = Vec::new();
1345 for r in cx.ref_graph().referrers(self.key()) {
1346 if let m::EntityKey::ApprovalPersonOrganization(id) = r {
1347 out.push(Approver { cx, id: *id });
1348 }
1349 }
1350 out
1351 }
1352
1353 pub fn date(&self) -> Option<ApprovalDate> {
1361 let cx = self.cx;
1362 for r in cx.ref_graph().referrers(self.key()) {
1363 if let m::EntityKey::ApprovalDateTime(id) = r {
1364 let dt = &cx.model.approval_date_time_arena.get(id.0).date_time;
1365 return resolve_datetime(cx, dt);
1366 }
1367 }
1368 None
1369 }
1370}
1371
1372#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
1377pub struct ApprovalDate {
1378 pub year: Option<i64>,
1379 pub month: Option<i64>,
1380 pub day: Option<i64>,
1381 pub hour: Option<i64>,
1382 pub minute: Option<i64>,
1383}
1384
1385fn resolve_datetime(cx: Ctx<'_>, r: &m::DateTimeSelectRef) -> Option<ApprovalDate> {
1390 let mut d = ApprovalDate::default();
1391 match r {
1392 m::DateTimeSelectRef::CalendarDate(i) => set_calendar(cx, &mut d, *i),
1393 m::DateTimeSelectRef::Date(i) => {
1394 d.year = Some(cx.model.date_arena.get(i.0).year_component);
1395 }
1396 m::DateTimeSelectRef::DateAndTime(i) => {
1397 let dt = cx.model.date_and_time_arena.get(i.0);
1398 set_date(cx, &mut d, &dt.date_component);
1399 let m::LocalTimeRef::LocalTime(lt) = &dt.time_component;
1400 set_time(cx, &mut d, *lt);
1401 }
1402 m::DateTimeSelectRef::LocalTime(i) => set_time(cx, &mut d, *i),
1403 m::DateTimeSelectRef::Complex(_) => {
1404 cx.warn(
1405 "APPROVAL_DATE_TIME.date_time is a complex instance; date left unread".to_owned(),
1406 );
1407 return None;
1408 }
1409 }
1410 Some(d)
1411}
1412
1413fn set_date(cx: Ctx<'_>, d: &mut ApprovalDate, r: &m::DateRef) {
1415 match r {
1416 m::DateRef::CalendarDate(i) => set_calendar(cx, d, *i),
1417 m::DateRef::Date(i) => d.year = Some(cx.model.date_arena.get(i.0).year_component),
1418 m::DateRef::Complex(_) => {}
1419 }
1420}
1421
1422fn set_calendar(cx: Ctx<'_>, d: &mut ApprovalDate, i: m::CalendarDateId) {
1423 let c = cx.model.calendar_date_arena.get(i.0);
1424 d.year = Some(c.year_component);
1425 d.month = Some(c.month_component);
1426 d.day = Some(c.day_component);
1427}
1428
1429fn set_time(cx: Ctx<'_>, d: &mut ApprovalDate, i: m::LocalTimeId) {
1430 let t = cx.model.local_time_arena.get(i.0);
1431 d.hour = Some(t.hour_component);
1432 d.minute = t.minute_component;
1433}
1434
1435#[derive(Clone, Copy)]
1437pub struct Approver<'m> {
1438 cx: Ctx<'m>,
1439 id: m::ApprovalPersonOrganizationId,
1440}
1441
1442impl<'m> Approver<'m> {
1443 fn raw(&self) -> &'m m::ApprovalPersonOrganization {
1444 self.cx
1445 .model
1446 .approval_person_organization_arena
1447 .get(self.id.0)
1448 }
1449
1450 pub fn role(&self) -> &'m str {
1452 let m::ApprovalRoleRef::ApprovalRole(rid) = &self.raw().role;
1453 &self.cx.model.approval_role_arena.get(rid.0).role
1454 }
1455
1456 pub fn person(&self) -> Option<Person<'m>> {
1459 let pid = match &self.raw().person_organization {
1460 m::PersonOrganizationSelectRef::Person(i) => *i,
1461 m::PersonOrganizationSelectRef::PersonAndOrganization(i) => {
1462 let m::PersonRef::Person(p) = &self
1463 .cx
1464 .model
1465 .person_and_organization_arena
1466 .get(i.0)
1467 .the_person;
1468 *p
1469 }
1470 m::PersonOrganizationSelectRef::Organization(_) => return None,
1471 };
1472 Some(Person {
1473 cx: self.cx,
1474 id: pid,
1475 })
1476 }
1477
1478 pub fn organization(&self) -> Option<&'m str> {
1481 let oid = match &self.raw().person_organization {
1482 m::PersonOrganizationSelectRef::Organization(i) => *i,
1483 m::PersonOrganizationSelectRef::PersonAndOrganization(i) => {
1484 let m::OrganizationRef::Organization(o) = &self
1485 .cx
1486 .model
1487 .person_and_organization_arena
1488 .get(i.0)
1489 .the_organization;
1490 *o
1491 }
1492 m::PersonOrganizationSelectRef::Person(_) => return None,
1493 };
1494 Some(&self.cx.model.organization_arena.get(oid.0).name)
1495 }
1496}
1497
1498#[derive(Clone, Copy)]
1499enum DocImpl {
1500 Document(m::DocumentId),
1501 DocumentFile(m::DocumentFileId),
1502}
1503
1504#[derive(Clone, Copy)]
1510pub struct Document<'m> {
1511 cx: Ctx<'m>,
1512 which: DocImpl,
1513 scope: Scope,
1514}
1515
1516impl<'m> Document<'m> {
1517 pub fn assigned_scope(&self) -> Scope {
1519 self.scope
1520 }
1521
1522 pub fn assigned_targets(&self) -> Vec<Target<'m>> {
1525 let cx = self.cx;
1526 let mut keys: Vec<m::EntityKey> = Vec::new();
1527 for r in cx.ref_graph().referrers(self.key()) {
1528 if let m::EntityKey::AppliedDocumentReference(i) = r {
1529 keys.extend(
1530 cx.model
1531 .applied_document_reference_arena
1532 .get(i.0)
1533 .items
1534 .iter()
1535 .map(m::DocumentReferenceItemRef::entity_key),
1536 );
1537 }
1538 }
1539 targets_from_keys(cx, keys.into_iter())
1540 }
1541
1542 fn fields(&self) -> (&'m str, &'m str, Option<&'m str>, &'m m::DocumentTypeRef) {
1545 let model = self.cx.model;
1546 match self.which {
1547 DocImpl::Document(i) => {
1548 let d = model.document_arena.get(i.0);
1549 (&d.id, &d.name, d.description.as_deref(), &d.kind)
1550 }
1551 DocImpl::DocumentFile(i) => {
1552 let d = model.document_file_arena.get(i.0);
1553 (&d.id, &d.name, d.description.as_deref(), &d.kind)
1554 }
1555 }
1556 }
1557
1558 pub fn key(&self) -> m::EntityKey {
1560 match self.which {
1561 DocImpl::Document(i) => m::EntityKey::Document(i),
1562 DocImpl::DocumentFile(i) => m::EntityKey::DocumentFile(i),
1563 }
1564 }
1565
1566 pub fn id(&self) -> &'m str {
1568 self.fields().0
1569 }
1570
1571 pub fn name(&self) -> &'m str {
1573 self.fields().1
1574 }
1575
1576 pub fn description(&self) -> Option<&'m str> {
1578 self.fields().2
1579 }
1580
1581 pub fn kind(&self) -> &'m str {
1584 let m::DocumentTypeRef::DocumentType(tid) = self.fields().3;
1585 &self
1586 .cx
1587 .model
1588 .document_type_arena
1589 .get(tid.0)
1590 .product_data_type
1591 }
1592}
1593
1594#[derive(Clone, Copy)]
1597pub struct SecurityClassification<'m> {
1598 cx: Ctx<'m>,
1599 id: m::SecurityClassificationId,
1600 scope: Scope,
1601}
1602
1603impl<'m> SecurityClassification<'m> {
1604 fn raw(&self) -> &'m m::SecurityClassification {
1605 self.cx.model.security_classification_arena.get(self.id.0)
1606 }
1607
1608 pub fn key(&self) -> m::EntityKey {
1610 m::EntityKey::SecurityClassification(self.id)
1611 }
1612
1613 pub fn assigned_scope(&self) -> Scope {
1615 self.scope
1616 }
1617
1618 pub fn assigned_targets(&self) -> Vec<Target<'m>> {
1621 let cx = self.cx;
1622 let mut keys: Vec<m::EntityKey> = Vec::new();
1623 for r in cx.ref_graph().referrers(self.key()) {
1624 match r {
1625 m::EntityKey::CcDesignSecurityClassification(i) => keys.extend(
1626 cx.model
1627 .cc_design_security_classification_arena
1628 .get(i.0)
1629 .items
1630 .iter()
1631 .map(m::CcClassifiedItemRef::entity_key),
1632 ),
1633 m::EntityKey::AppliedSecurityClassificationAssignment(i) => keys.extend(
1634 cx.model
1635 .applied_security_classification_assignment_arena
1636 .get(i.0)
1637 .items
1638 .iter()
1639 .map(m::SecurityClassificationItemRef::entity_key),
1640 ),
1641 _ => {}
1642 }
1643 }
1644 targets_from_keys(cx, keys.into_iter())
1645 }
1646
1647 pub fn name(&self) -> &'m str {
1649 &self.raw().name
1650 }
1651
1652 pub fn purpose(&self) -> &'m str {
1654 &self.raw().purpose
1655 }
1656
1657 pub fn level(&self) -> &'m str {
1660 let m::SecurityClassificationLevelRef::SecurityClassificationLevel(lid) =
1661 &self.raw().security_level;
1662 &self
1663 .cx
1664 .model
1665 .security_classification_level_arena
1666 .get(lid.0)
1667 .name
1668 }
1669}