Simbody
3.4 (development)
|
00001 #ifndef SimTK_SIMMATH_MULTIBODY_GRAPH_MAKER_H_ 00002 #define SimTK_SIMMATH_MULTIBODY_GRAPH_MAKER_H_ 00003 00004 /* -------------------------------------------------------------------------- * 00005 * Simbody(tm): Multibody Graph Maker * 00006 * -------------------------------------------------------------------------- * 00007 * This is part of the SimTK biosimulation toolkit originating from * 00008 * Simbios, the NIH National Center for Physics-Based Simulation of * 00009 * Biological Structures at Stanford, funded under the NIH Roadmap for * 00010 * Medical Research, grant U54 GM072970. See https://simtk.org/home/simbody. * 00011 * * 00012 * Portions copyright (c) 2013 Stanford University and the Authors. * 00013 * Authors: Michael Sherman * 00014 * Contributors: Kevin He * 00015 * * 00016 * Licensed under the Apache License, Version 2.0 (the "License"); you may * 00017 * not use this file except in compliance with the License. You may obtain a * 00018 * copy of the License at http://www.apache.org/licenses/LICENSE-2.0. * 00019 * * 00020 * Unless required by applicable law or agreed to in writing, software * 00021 * distributed under the License is distributed on an "AS IS" BASIS, * 00022 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 00023 * See the License for the specific language governing permissions and * 00024 * limitations under the License. * 00025 * -------------------------------------------------------------------------- */ 00026 00032 #include "SimTKcommon.h" 00033 #include "simmath/internal/common.h" 00034 00035 #include <utility> 00036 #include <string> 00037 #include <vector> 00038 #include <map> 00039 #include <iosfwd> 00040 00041 namespace SimTK { 00042 00043 //============================================================================== 00044 // MULTIBODY GRAPH MAKER 00045 //============================================================================== 00146 class SimTK_SIMMATH_EXPORT MultibodyGraphMaker { 00147 public: 00148 // Local classes. 00149 class Body; 00150 class Joint; 00151 class JointType; 00152 class Mobilizer; 00153 class LoopConstraint; 00154 00157 MultibodyGraphMaker(); 00158 00159 00164 int addJointType(const std::string& name, 00165 int numMobilities, 00166 bool haveGoodLoopJointAvailable = false, 00167 void* userRef = 0); 00168 00169 00191 void addBody(const std::string& name, 00192 double mass, 00193 bool mustBeBaseBody, 00194 void* userRef = 0); 00195 00204 bool deleteBody(const std::string& name); 00205 00238 void addJoint(const std::string& name, 00239 const std::string& type, 00240 const std::string& parentBodyName, 00241 const std::string& childBodyName, 00242 bool mustBeLoopJoint, 00243 void* userRef = 0); 00244 00253 bool deleteJoint(const std::string& name); 00254 00257 void generateGraph(); 00258 void clearGraph(); 00259 00261 void dumpGraph(std::ostream& out) const; 00262 00269 int getNumMobilizers() const {return (int)mobilizers.size();} 00272 const Mobilizer& getMobilizer(int mobilizerNum) const 00273 { return mobilizers[mobilizerNum]; } 00274 00282 int getNumLoopConstraints() const {return (int)constraints.size();} 00285 const LoopConstraint& getLoopConstraint(int loopConstraintNum) const 00286 { return constraints[loopConstraintNum]; } 00287 00290 int getNumBodies() const {return (int)bodies.size();} 00294 const Body& getBody(int bodyNum) const {return bodies[bodyNum];} 00298 int getBodyNum(const std::string& bodyName) const { 00299 std::map<std::string,int>::const_iterator p = 00300 bodyName2Num.find(bodyName); 00301 return p==bodyName2Num.end() ? -1 : p->second; 00302 } 00303 00308 int getNumJoints() const {return (int)joints.size();} 00311 const Joint& getJoint(int jointNum) const {return joints[jointNum];} 00315 int getJointNum(const std::string& jointName) const { 00316 std::map<std::string,int>::const_iterator p = 00317 jointName2Num.find(jointName); 00318 return p==jointName2Num.end() ? -1 : p->second; 00319 } 00320 00322 int getNumJointTypes() const {return (int)jointTypes.size();} 00324 const JointType& getJointType(int jointTypeNum) const 00325 { return jointTypes[jointTypeNum]; } 00327 int getJointTypeNum(const std::string& jointTypeName) const { 00328 std::map<std::string,int>::const_iterator p = 00329 jointTypeName2Num.find(jointTypeName); 00330 return p==jointTypeName2Num.end() ? -1 : p->second; 00331 } 00332 00336 void setWeldJointTypeName(const std::string& name) 00337 { weldTypeName=name; initialize(); } 00340 const std::string& getWeldJointTypeName() const {return weldTypeName;} 00341 00345 void setFreeJointTypeName(const std::string& name) 00346 { freeTypeName=name; initialize(); } 00349 const std::string& getFreeJointTypeName() const {return freeTypeName;} 00350 00353 const std::string& getGroundBodyName() const; 00354 private: 00355 // Get writable access to bodies and joints. 00356 Body& updBody(int bodyNum) {return bodies[bodyNum];} 00357 Joint& updJoint(int jointNum) {return joints[jointNum];} 00358 Joint& updJoint(const std::string& name) {return joints[jointName2Num[name]];} 00359 00360 void initialize(); 00361 int splitBody(int bodyNum); 00362 int chooseNewBaseBody() const; 00363 void connectBodyToGround(int bodyNum); 00364 int addMobilizerForJoint(int jointNum); 00365 int findHeaviestUnassignedForwardJoint(int inboardBody) const; 00366 int findHeaviestUnassignedReverseJoint(int inboardBody) const; 00367 void growTree(); 00368 void breakLoops(); 00369 bool bodiesAreConnected(int b1, int b2) const; 00370 00371 // Clear everything except for default names. 00372 void clear() { 00373 bodies.clear(); joints.clear(); jointTypes.clear(); 00374 bodyName2Num.clear(); jointName2Num.clear(); jointTypeName2Num.clear(); 00375 mobilizers.clear(); constraints.clear(); 00376 } 00377 00378 std::string weldTypeName, freeTypeName; 00379 std::vector<Body> bodies; // ground + input bodies + slaves 00380 std::vector<Joint> joints; // input joints + added joints 00381 std::vector<JointType> jointTypes; 00382 std::map<std::string,int> bodyName2Num; 00383 std::map<std::string,int> jointName2Num; 00384 std::map<std::string,int> jointTypeName2Num; 00385 00386 // Calculated by generateGraph() 00387 std::vector<Mobilizer> mobilizers; // mobilized bodies 00388 std::vector<LoopConstraint> constraints; 00389 }; 00390 00391 //------------------------------------------------------------------------------ 00392 // MULTIBODY GRAPH MAKER :: BODY 00393 //------------------------------------------------------------------------------ 00395 class MultibodyGraphMaker::Body { 00396 public: 00397 explicit Body(const std::string& name, 00398 double mass, 00399 bool mustBeBaseBody, 00400 void* userRef) 00401 : name(name), mass(mass), mustBeBaseBody(mustBeBaseBody), 00402 userRef(userRef), level(-1), mobilizer(-1), master(-1) {} 00403 00404 void forgetGraph(MultibodyGraphMaker& graph); 00405 int getNumFragments() const {return 1 + getNumSlaves();} 00406 int getNumSlaves() const {return (int)slaves.size();} 00407 int getNumJoints() const 00408 { return int(jointsAsChild.size() + jointsAsParent.size()); } 00409 bool isSlave() const {return master >= 0;} 00410 bool isMaster() const {return getNumSlaves()>0;} 00411 bool isInTree() const {return level>=0;} 00412 00413 // Inputs 00414 std::string name; 00415 double mass; 00416 bool mustBeBaseBody; 00417 void* userRef; 00418 00419 // How this body appears in joints (input and added). 00420 std::vector<int> jointsAsChild; // where this body is the child 00421 std::vector<int> jointsAsParent; // where this body is the parent 00422 00423 // Disposition of this body in the spanning tree. 00424 00425 int level; // Ground=0, connected to Ground=1, contact to that=2, etc. 00426 int mobilizer; // the unique mobilizer where this is the outboard body 00427 00428 int master; // >=0 if this is a slave 00429 std::vector<int> slaves; // slave links, if this is a master 00430 }; 00431 00432 //------------------------------------------------------------------------------ 00433 // MULTIBODY GRAPH MAKER :: JOINT 00434 //------------------------------------------------------------------------------ 00436 class MultibodyGraphMaker::Joint { 00437 public: 00438 Joint(const std::string& name, int jointTypeNum, 00439 int parentBodyNum, int childBodyNum, 00440 bool mustBeLoopJoint, void* userRef) 00441 : name(name), jointTypeNum(jointTypeNum), 00442 parentBodyNum(parentBodyNum), childBodyNum(childBodyNum), 00443 mustBeLoopJoint(mustBeLoopJoint), userRef(userRef), 00444 isAddedBaseJoint(false), mobilizer(-1), loopConstraint(-1) {} 00445 00448 bool forgetGraph(MultibodyGraphMaker& graph); 00449 00450 // Only one of these will be true -- we don't consider it a LoopConstraint 00451 // if we split a body and weld it back. 00452 bool hasMobilizer() const {return mobilizer>=0;} 00453 bool hasLoopConstraint() const {return loopConstraint>=0;} 00454 00455 // Inputs 00456 std::string name; 00457 bool mustBeLoopJoint; 00458 void* userRef; 00459 00460 // Mapping of strings to indices for fast lookup. 00461 int parentBodyNum, childBodyNum; 00462 int jointTypeNum; 00463 00464 bool isAddedBaseJoint; // true if this wasn't one of the input joints 00465 00466 // Disposition of this joint in the multibody graph. 00467 int mobilizer; // if this joint is part of the spanning tree, else -1 00468 int loopConstraint; // if this joint used a loop constraint, else -1 00469 }; 00470 00471 //------------------------------------------------------------------------------ 00472 // MULTIBODY GRAPH MAKER :: JOINT TYPE 00473 //------------------------------------------------------------------------------ 00475 class MultibodyGraphMaker::JointType { 00476 public: 00477 JointType(const std::string& name, int numMobilities, 00478 bool haveGoodLoopJointAvailable, void* userRef) 00479 : name(name), numMobilities(numMobilities), 00480 haveGoodLoopJointAvailable(haveGoodLoopJointAvailable), 00481 userRef(userRef) {} 00482 std::string name; 00483 int numMobilities; 00484 bool haveGoodLoopJointAvailable; 00485 void* userRef; 00486 }; 00487 00488 //------------------------------------------------------------------------------ 00489 // MULTIBODY GRAPH MAKER :: MOBILIZER 00490 //------------------------------------------------------------------------------ 00494 class MultibodyGraphMaker::Mobilizer { 00495 public: 00496 Mobilizer() 00497 : joint(-1), level(-1), inboardBody(-1), outboardBody(-1), 00498 isReversed(false), mgm(0) {} 00499 Mobilizer(int jointNum, int level, int inboardBodyNum, int outboardBodyNum, 00500 bool isReversed, MultibodyGraphMaker* graphMaker) 00501 : joint(jointNum), level(level), inboardBody(inboardBodyNum), 00502 outboardBody(outboardBodyNum), isReversed(isReversed), 00503 mgm(graphMaker) {} 00504 00511 bool isAddedBaseMobilizer() const 00512 { return mgm->getJoint(joint).isAddedBaseJoint; } 00516 void* getJointRef() const 00517 { return mgm->getJoint(joint).userRef; } 00522 void* getInboardBodyRef() const 00523 { return mgm->getBody(inboardBody).userRef; } 00529 void* getOutboardBodyRef() const 00530 { return mgm->getBody(outboardBody).userRef; } 00535 void* getOutboardMasterBodyRef() const 00536 { return mgm->getBody(getOutboardMasterBodyNum()).userRef; } 00538 const std::string& getJointTypeName() const 00539 { return mgm->getJointType(mgm->getJoint(joint).jointTypeNum).name; } 00542 void* getJointTypeRef() const 00543 { return mgm->getJointType(mgm->getJoint(joint).jointTypeNum).userRef; } 00546 bool isSlaveMobilizer() const 00547 { return mgm->getBody(outboardBody).isSlave(); } 00553 int getNumFragments() const 00554 { return mgm->getBody(getOutboardMasterBodyNum()).getNumFragments(); } 00559 bool isReversedFromJoint() const {return isReversed;} 00560 00561 private: 00562 friend class MultibodyGraphMaker; 00563 00564 int getOutboardMasterBodyNum() const 00565 { const Body& outb = mgm->getBody(outboardBody); 00566 return outb.isSlave() ? outb.master : outboardBody; } 00567 00568 int joint; 00569 int level; 00570 int inboardBody; 00571 int outboardBody; 00572 bool isReversed; 00573 00574 MultibodyGraphMaker* mgm; // just a reference to container 00575 }; 00576 00577 00578 //------------------------------------------------------------------------------ 00579 // MULTIBODY GRAPH MAKER :: LOOP CONSTRAINT 00580 //------------------------------------------------------------------------------ 00583 class MultibodyGraphMaker::LoopConstraint { 00584 public: 00585 LoopConstraint() : joint(-1), parentBody(-1), childBody(-1), mgm(0) {} 00586 LoopConstraint(const std::string& type, int jointNum, 00587 int parentBodyNum, int childBodyNum, 00588 MultibodyGraphMaker* graphMaker) 00589 : type(type), joint(jointNum), 00590 parentBody(parentBodyNum), childBody(childBodyNum), 00591 mgm(graphMaker) {} 00592 00595 void* getJointRef() const 00596 { return mgm->getJoint(joint).userRef; } 00599 const std::string& getJointTypeName() const 00600 { return type; } 00603 void* getParentBodyRef() const 00604 { return mgm->getBody(parentBody).userRef; } 00607 void* getChildBodyRef() const 00608 { return mgm->getBody(childBody).userRef; } 00609 00610 private: 00611 friend class MultibodyGraphMaker; 00612 00613 std::string type; // e.g., ball 00614 int joint; // always one of the input joints 00615 int parentBody; // parent from the joint 00616 int childBody; // child from the joint 00617 00618 MultibodyGraphMaker* mgm; // just a reference to container 00619 }; 00620 00621 00622 } // namespace SimTK 00623 00624 #endif // SimTK_SIMMATH_MULTIBODY_GRAPH_MAKER_H_ 00625