@@ -122,7 +122,7 @@ void LinkJointGraph::InvalidateForest() {
122122 DRAKE_DEMAND (ssize (data_.joint_name_to_index ) == data_.num_user_joints );
123123 DRAKE_DEMAND (data_.ephemeral_link_name_to_index .empty ());
124124 DRAKE_DEMAND (data_.ephemeral_joint_name_to_index .empty ());
125- DRAKE_DEMAND (data_.link_composites .empty ());
125+ DRAKE_DEMAND (data_.welded_links_assemblies .empty ());
126126 DRAKE_DEMAND (data_.num_user_links == ssize (data_.links ));
127127 DRAKE_DEMAND (data_.num_user_joints == ssize (data_.joints ));
128128 return ;
@@ -143,7 +143,7 @@ void LinkJointGraph::InvalidateForest() {
143143 data_.ephemeral_link_name_to_index .clear ();
144144 data_.links .erase (data_.links .begin () + data_.num_user_links ,
145145 data_.links .end ());
146- DRAKE_DEMAND (ssize ( links () ) == data_.num_user_links );
146+ DRAKE_DEMAND (num_links ( ) == data_.num_user_links );
147147 }
148148
149149 if (ssize (data_.joints ) > num_user_joints ()) {
@@ -161,7 +161,7 @@ void LinkJointGraph::InvalidateForest() {
161161 // Remove all as-modeled information from the user's graph.
162162 for (auto & link : data_.links ) link.ClearModel (data_.max_user_joint_index );
163163 for (auto & joint : data_.joints ) joint.ClearModel ();
164- data_.link_composites .clear ();
164+ data_.welded_links_assemblies .clear ();
165165}
166166
167167const LinkJointGraph::Link& LinkJointGraph::world_link () const {
@@ -175,7 +175,7 @@ LinkIndex LinkJointGraph::AddLink(const std::string& link_name,
175175 DRAKE_DEMAND (model_instance.is_valid ());
176176
177177 // Reject use of world model instance for any Link other than World.
178- if (ssize ( links () ) > 0 && model_instance == world_model_instance ()) {
178+ if (num_links ( ) > 0 && model_instance == world_model_instance ()) {
179179 throw std::logic_error (fmt::format (
180180 " {}(): Model instance index {} is reserved for the World link. "
181181 " World is always predefined and is named '{}'." ,
@@ -203,15 +203,15 @@ LinkIndex LinkJointGraph::AddLink(const std::string& link_name,
203203 InvalidateForest ();
204204
205205 const LinkIndex link_index (num_link_indexes ());
206- const LinkOrdinal link_ordinal (ssize ( links () ));
206+ const LinkOrdinal link_ordinal (num_links ( ));
207207 data_.link_index_to_ordinal .push_back (link_ordinal);
208208
209209 // provide fast name lookup
210210 data_.link_name_to_index .insert ({link_name, link_index});
211211
212212 data_.links .emplace_back (
213213 Link (link_index, link_ordinal, link_name, model_instance, flags));
214- data_.num_user_links = ssize ( links () );
214+ data_.num_user_links = num_links ( );
215215 data_.max_user_link_index = link_index;
216216
217217 Link& new_link = data_.links .back ();
@@ -485,14 +485,15 @@ bool LinkJointGraph::IsJointTypeRegistered(
485485 return it != data_.joint_type_name_to_index .end ();
486486}
487487
488- void LinkJointGraph::CreateWorldLinkComposite () {
488+ void LinkJointGraph::CreateWorldWeldedLinksAssembly () {
489489 DRAKE_DEMAND (!links ().empty ()); // Better be at least World!
490- DRAKE_DEMAND (data_.link_composites .empty ());
490+ DRAKE_DEMAND (data_.welded_links_assemblies .empty ());
491491 Link& world_link = data_.links [LinkOrdinal (0 )];
492- DRAKE_DEMAND (!world_link.link_composite_index_ .has_value ());
493- data_.link_composites .emplace_back (LinkComposite{
494- .links = std::vector{world_link.index ()}, .is_massless = false });
495- world_link.link_composite_index_ = LinkCompositeIndex (0 );
492+ DRAKE_DEMAND (!world_link.welded_links_assembly_index_ .has_value ());
493+ WeldedLinksAssembly& assembly = data_.welded_links_assemblies .emplace_back ();
494+ assembly.links_ .push_back (world_link.index ());
495+ assembly.is_massless_ = false ;
496+ world_link.welded_links_assembly_index_ = WeldedLinksAssemblyIndex (0 );
496497}
497498
498499LoopConstraintIndex LinkJointGraph::AddLoopClosingWeldConstraint (
@@ -602,42 +603,57 @@ JointIndex LinkJointGraph::AddEphemeralJointToWorld(
602603 return new_joint_index;
603604}
604605
605- LinkCompositeIndex LinkJointGraph::AddToLinkComposite (
606- LinkOrdinal maybe_composite_link_ordinal, LinkOrdinal new_link_ordinal) {
607- DRAKE_ASSERT (maybe_composite_link_ordinal.is_valid () &&
606+ WeldedLinksAssemblyIndex LinkJointGraph::AddToWeldedLinksAssembly (
607+ LinkOrdinal maybe_assembly_link_ordinal, LinkOrdinal new_link_ordinal,
608+ JointOrdinal weld_joint_ordinal) {
609+ DRAKE_ASSERT (maybe_assembly_link_ordinal.is_valid () &&
608610 new_link_ordinal.is_valid ());
609- Link& maybe_composite_link = mutable_link (maybe_composite_link_ordinal );
611+ Link& maybe_assembly_link = mutable_link (maybe_assembly_link_ordinal );
610612 Link& new_link = mutable_link (new_link_ordinal);
611613 DRAKE_DEMAND (!new_link.is_world ());
612614
613- std::optional<LinkCompositeIndex> existing_composite_index =
614- maybe_composite_link.link_composite_index_ ;
615- if (!existing_composite_index.has_value ()) {
616- // We're starting a new LinkComposite. This must be the "active link"
617- // for this Composite because we saw it first while building the Forest.
618- existing_composite_index = maybe_composite_link.link_composite_index_ =
619- LinkCompositeIndex (ssize (data_.link_composites ));
620- data_.link_composites .emplace_back (LinkComposite{
621- .links = std::vector<LinkIndex>{maybe_composite_link.index ()},
622- .is_massless = maybe_composite_link.is_massless ()});
615+ std::optional<WeldedLinksAssemblyIndex> existing_assembly_index =
616+ maybe_assembly_link.welded_links_assembly_index_ ;
617+ if (!existing_assembly_index.has_value ()) {
618+ // We're starting a new WeldedLinksAssembly. This must be the "active link"
619+ // for this Assembly because we saw it first while building the Forest.
620+ existing_assembly_index = maybe_assembly_link.welded_links_assembly_index_ =
621+ WeldedLinksAssemblyIndex (ssize (data_.welded_links_assemblies ));
622+ WeldedLinksAssembly& assembly =
623+ data_.welded_links_assemblies .emplace_back ();
624+ assembly.links_ .push_back (maybe_assembly_link.index ());
625+ assembly.is_massless_ = maybe_assembly_link.is_massless ();
623626 }
624627
625- LinkComposite& existing_composite =
626- data_.link_composites [*existing_composite_index];
627- existing_composite.links .push_back (new_link.index ());
628- // For the composite to be massless, _all_ its links must be massless.
629- if (!new_link.is_massless ()) existing_composite.is_massless = false ;
630- new_link.link_composite_index_ = existing_composite_index;
628+ WeldedLinksAssembly& existing_assembly =
629+ data_.welded_links_assemblies [*existing_assembly_index];
630+ existing_assembly.links_ .push_back (new_link.index ());
631+ existing_assembly.joints_ .push_back (joints (weld_joint_ordinal).index ());
632+ // For the assembly to be massless, _all_ its links must be massless.
633+ if (!new_link.is_massless ()) {
634+ existing_assembly.is_massless_ = false ;
635+ }
636+ new_link.welded_links_assembly_index_ = existing_assembly_index;
631637
632- return *existing_composite_index ;
638+ return *existing_assembly_index ;
633639}
634640
635- void LinkJointGraph::AddUnmodeledJointToComposite (
641+ void LinkJointGraph::NoteUnmodeledJointInWeldedLinksAssembly (
636642 JointOrdinal unmodeled_joint_ordinal,
637- LinkCompositeIndex link_composite_index ) {
643+ WeldedLinksAssemblyIndex welded_links_assembly_index ) {
638644 Joint& joint = mutable_joint (unmodeled_joint_ordinal);
639- DRAKE_DEMAND (joint.traits_index () == weld_joint_traits_index ());
640- joint.how_modeled_ = link_composite_index;
645+ DRAKE_DEMAND (joint.is_weld ());
646+ joint.how_modeled_ = welded_links_assembly_index;
647+ }
648+
649+ void LinkJointGraph::AddUnmodeledJointToWeldedLinksAssembly (
650+ JointOrdinal unmodeled_joint_ordinal,
651+ WeldedLinksAssemblyIndex welded_links_assembly_index) {
652+ WeldedLinksAssembly& assembly =
653+ data_.welded_links_assemblies [welded_links_assembly_index];
654+ assembly.joints_ .push_back (joints (unmodeled_joint_ordinal).index ());
655+ NoteUnmodeledJointInWeldedLinksAssembly (unmodeled_joint_ordinal,
656+ welded_links_assembly_index);
641657}
642658
643659LinkOrdinal LinkJointGraph::AddShadowLink (LinkOrdinal primary_link_ordinal,
@@ -649,14 +665,14 @@ LinkOrdinal LinkJointGraph::AddShadowLink(LinkOrdinal primary_link_ordinal,
649665 const int shadow_num = primary_link.num_shadows () + 1 ;
650666 /* Name should be <primary_name>$<shadow_num> (unique within primary's model
651667 instance). In the unlikely event that a user has names like this, we'll keep
652- prepending "_" to the body name until this one is unique. Nothing much depends
668+ prepending "_" to the link name until this one is unique. Nothing much depends
653669 on the details of this name. */
654670 std::string shadow_link_name =
655671 fmt::format (" {}${}" , primary_link.name (), shadow_num);
656672 while (HasLinkNamed (shadow_link_name, primary_link.model_instance ()))
657673 shadow_link_name = " _" + shadow_link_name;
658674 const LinkIndex shadow_link_index (num_link_indexes ());
659- const LinkOrdinal shadow_link_ordinal (ssize ( links () ));
675+ const LinkOrdinal shadow_link_ordinal (num_links ( ));
660676 DRAKE_DEMAND (shadow_link_ordinal >= num_user_links ()); // A sanity check.
661677 data_.link_index_to_ordinal .push_back (shadow_link_ordinal);
662678 data_.ephemeral_link_name_to_index .insert (
@@ -667,13 +683,18 @@ LinkOrdinal LinkJointGraph::AddShadowLink(LinkOrdinal primary_link_ordinal,
667683 /* Caution: primary_link reference is invalid now -- don't use it! */
668684 Link& shadow_link = data_.links .back ();
669685 shadow_link.primary_link_ = primary_link_index;
670- const Joint& shadow_joint = joints (shadow_joint_ordinal);
686+ Joint& shadow_joint = mutable_joint (shadow_joint_ordinal);
671687 if (shadow_is_parent) {
672688 shadow_link.add_joint_as_parent (shadow_joint.index ());
689+ shadow_joint.set_effective_parent_link (shadow_link_index);
673690 } else {
674691 shadow_link.add_joint_as_child (shadow_joint.index ());
692+ shadow_joint.set_effective_child_link (shadow_link_index);
675693 }
676- mutable_link (primary_link_ordinal).shadow_links_ .push_back (shadow_link_index);
694+
695+ Link& mutable_primary_link = mutable_link (primary_link_ordinal);
696+ mutable_primary_link.shadow_links_ .push_back (shadow_link_index);
697+ mutable_primary_link.NoteRetargetedJoint (shadow_joint.index ());
677698
678699 return shadow_link_ordinal;
679700}
@@ -720,7 +741,7 @@ std::vector<LinkIndex> LinkJointGraph::FindPathFromWorld(
720741 std::vector<LinkIndex> path (mobod->level () + 1 );
721742 while (mobod->inboard ().is_valid ()) {
722743 const Link& link = links (mobod->link_ordinal ());
723- path[mobod->level ()] = link.index (); // Active Link if composite .
744+ path[mobod->level ()] = link.index (); // Active Link if optimized assembly .
724745 mobod = &forest ().mobods (mobod->inboard ());
725746 }
726747 DRAKE_DEMAND (mobod->is_world ());
@@ -745,25 +766,25 @@ std::vector<LinkIndex> LinkJointGraph::FindSubtreeLinks(
745766 return forest ().FindSubtreeLinks (root_mobod_index);
746767}
747768
748- // Our link_composites collection doesn't include lone Links that aren't welded
749- // to anything. The return from this function must include every Link, with
750- // the World link in the first set (even if nothing is welded to it).
769+ // Our welded_links_assemblies collection doesn't include lone Links that aren't
770+ // welded to anything. The return from this function must include every Link,
771+ // with the World link in the first set (even if nothing is welded to it).
751772std::vector<std::set<LinkIndex>> LinkJointGraph::GetSubgraphsOfWeldedLinks ()
752773 const {
753774 ThrowIfForestNotBuiltYet (__func__);
754775
755776 std::vector<std::set<LinkIndex>> subgraphs;
756777
757- // First, collect all the precomputed Link Composites . World is always
778+ // First, collect all the precomputed WeldedLinksAssemblies . World is always
758779 // the first one, even if nothing is welded to it.
759- for (const LinkComposite& composite : link_composites ()) {
780+ for (const WeldedLinksAssembly& assembly : welded_links_assemblies ()) {
760781 subgraphs.emplace_back (
761- std::set<LinkIndex>(composite. links .cbegin (), composite. links .cend ()));
782+ std::set<LinkIndex>(assembly. links_ .cbegin (), assembly. links_ .cend ()));
762783 }
763784
764- // Finally, make one-Link subgraphs for Links that aren't in any composite .
785+ // Finally, make one-Link subgraphs for Links that aren't in any assembly .
765786 for (const Link& link : links ()) {
766- if (link.composite ().has_value ()) continue ;
787+ if (link.welded_links_assembly ().has_value ()) continue ;
767788 subgraphs.emplace_back (std::set<LinkIndex>{link.index ()});
768789 }
769790
@@ -806,22 +827,23 @@ std::vector<std::set<LinkIndex>> LinkJointGraph::CalcSubgraphsOfWeldedLinks()
806827 return subgraphs;
807828}
808829
809- // If the Link isn't part of a LinkComposite just return the Link. Otherwise,
810- // return all the Links in its LinkComposite .
830+ // If the Link isn't part of a WeldedLinksAssembly just return the Link.
831+ // Otherwise, return all the Links in its WeldedLinksAssembly .
811832std::set<LinkIndex> LinkJointGraph::GetLinksWeldedTo (
812833 LinkIndex link_index) const {
813834 ThrowIfForestNotBuiltYet (__func__);
814835 DRAKE_DEMAND (link_index.is_valid ());
815836 DRAKE_THROW_UNLESS (has_link (link_index));
816837 const Link& link = link_by_index (link_index);
817- const std::optional<LinkCompositeIndex> composite_index = link.composite ();
818- if (!composite_index.has_value ()) return std::set<LinkIndex>{link_index};
838+ const std::optional<WeldedLinksAssemblyIndex> assembly_index =
839+ link.welded_links_assembly ();
840+ if (!assembly_index.has_value ()) return std::set<LinkIndex>{link_index};
819841 const std::vector<LinkIndex>& welded_links =
820- link_composites (*composite_index ).links ;
842+ welded_links_assemblies (*assembly_index ).links () ;
821843 return std::set<LinkIndex>(welded_links.cbegin (), welded_links.cend ());
822844}
823845
824- // Without a Forest we don't have LinkComposites available so recursively
846+ // Without a Forest we don't have WeldedLinksAssemblies available so recursively
825847// chase Weld joints instead.
826848std::set<LinkIndex> LinkJointGraph::CalcLinksWeldedTo (
827849 LinkIndex link_index) const {
@@ -930,7 +952,8 @@ void LinkJointGraph::Link::ClearModel(JointIndex max_user_joint_index) {
930952 mobod_ = {};
931953 joint_ = {};
932954 shadow_links_.clear ();
933- link_composite_index_ = {};
955+ joints_moved_to_shadow_links_.clear ();
956+ welded_links_assembly_index_ = {};
934957}
935958
936959LinkJointGraph::Joint::Joint (JointIndex index, JointOrdinal ordinal,
@@ -953,6 +976,8 @@ LinkJointGraph::Joint::Joint(JointIndex index, JointOrdinal ordinal,
953976 child_link_index_.is_valid ());
954977 DRAKE_DEMAND (parent_link_index_ != child_link_index_);
955978 DRAKE_DEMAND (ordinal_ <= static_cast <int >(index_));
979+ effective_parent_link_index_ = parent_link_index_;
980+ effective_child_link_index_ = child_link_index_;
956981}
957982
958983} // namespace internal
0 commit comments