00001
00002 #ifndef INCLUDED_KinematicJoint_h_
00003 #define INCLUDED_KinematicJoint_h_
00004
00005 #include "SensorInfo.h"
00006
00007 #include "Shared/plist.h"
00008 #include "Shared/plistSpecialty.h"
00009 #include "Shared/fmatSpatial.h"
00010 #include "Shared/BoundingBox.h"
00011
00012 #include "Planners/PlannerObstacles.h"
00013
00014 #include <set>
00015 #include <algorithm>
00016
00017 class KinematicJoint;
00018 class IKSolver;
00019
00020
00021
00022 class LinkComponent : virtual public plist::Dictionary {
00023 friend class KinematicJoint;
00024
00025 public:
00026
00027 LinkComponent()
00028 : plist::Dictionary(), mass(0), centerOfMass(), visible(true), material(),
00029 model("CollisionModel"), modelScale(1,1,1), modelRotation(), modelOffset(),
00030 collisionModel(), collisionModelScale(1,1,1), collisionModelRotation(), collisionModelOffset(),
00031 parent(NULL),
00032 bbDirty(false), boundingBox(),
00033 collisionModelListener(collisionModel,*this,&LinkComponent::dirtyBB,false),
00034 collisionModelScaleListener(collisionModelScale,*this,&LinkComponent::dirtyBB,false),
00035 collisionModelRotationListener(collisionModelRotation,*this,&LinkComponent::dirtyBB,false),
00036 collisionModelOffsetListener(collisionModelOffset,*this,&LinkComponent::dirtyBB,false)
00037 {
00038 init();
00039 }
00040
00041
00042 LinkComponent(const LinkComponent& c)
00043 : plist::Dictionary(), mass(c.mass), centerOfMass(c.centerOfMass), visible(c.visible), material(c.material),
00044 model(c.model), modelScale(c.modelScale), modelRotation(c.modelRotation), modelOffset(c.modelOffset),
00045 collisionModel(c.collisionModel), collisionModelScale(c.collisionModelScale), collisionModelRotation(c.collisionModelRotation), collisionModelOffset(c.collisionModelOffset),
00046 parent(NULL),
00047 bbDirty(c.bbDirty), boundingBox(c.boundingBox),
00048 collisionModelListener(collisionModel,*this,&LinkComponent::dirtyBB,false),
00049 collisionModelScaleListener(collisionModelScale,*this,&LinkComponent::dirtyBB,false),
00050 collisionModelRotationListener(collisionModelRotation,*this,&LinkComponent::dirtyBB,false),
00051 collisionModelOffsetListener(collisionModelOffset,*this,&LinkComponent::dirtyBB,false)
00052 {
00053 init();
00054 }
00055
00056
00057 LinkComponent& operator=(const LinkComponent& link) {
00058 if(&link==this)
00059 return *this;
00060 mass = link.mass;
00061 centerOfMass = link.centerOfMass;
00062 visible = link.visible;
00063 material = link.material;
00064 model = link.model;
00065 modelScale = link.modelScale;
00066 modelRotation = link.modelRotation;
00067 modelOffset = link.modelOffset;
00068 collisionModel = link.collisionModel;
00069 collisionModelScale = link.collisionModelScale;
00070 collisionModelRotation = link.collisionModelRotation;
00071 collisionModelOffset = link.collisionModelOffset;
00072
00073 bbDirty = link.bbDirty;
00074 boundingBox = link.boundingBox;
00075 return *this;
00076 }
00077
00078 virtual ~LinkComponent() {}
00079
00080 plist::Primitive<float> mass;
00081 plist::Point centerOfMass;
00082
00083 plist::Primitive<bool> visible;
00084
00085 plist::Primitive<std::string> material;
00086
00087 plist::Primitive<std::string> model;
00088 plist::Point modelScale;
00089 plist::Point modelRotation;
00090 plist::Point modelOffset;
00091
00092 plist::Primitive<std::string> collisionModel;
00093 plist::Point collisionModelScale;
00094 plist::Point collisionModelRotation;
00095 plist::Point collisionModelOffset;
00096
00097
00098
00099 PlannerObstacle2D* getObstacle(const fmat::Transform& worldT) const;
00100
00101
00102 void getObstacles(const fmat::Transform& worldT, HierarchicalObstacle& obs, bool recurse) const;
00103
00104
00105 virtual BoundingBox3D getOwnAABB() const { return getAABB(); }
00106
00107
00108 const BoundingBox3D& getAABB() const { if(bbDirty) updateBB(); return boundingBox; }
00109
00110
00111
00112 bool getOwnBB2D(const fmat::Transform& worldT, RectangularObstacle& ro) const;
00113
00114
00115
00116 bool getOwnBB3D(const fmat::Transform& worldT, BoxObstacle& bo) const;
00117
00118
00119
00120
00121 bool getBB2D(const fmat::Transform& worldT, RectangularObstacle& ro) const;
00122
00123
00124
00125
00126 bool getBB3D(const fmat::Transform& worldT, BoxObstacle& bo) const;
00127
00128
00129
00130
00131 fmat::Column<4> getMassVector() const { return fmat::pack(mass*centerOfMass[0],mass*centerOfMass[1],mass*centerOfMass[2],mass); }
00132
00133
00134 virtual void sumLinkCenterOfMass(fmat::Column<3>& cOfM, float& totalMass) const;
00135
00136
00137
00138 virtual fmat::Column<4> sumLinkCenterOfMass() const { return getMassVector(); }
00139
00140
00141 virtual bool hasMass() const { return mass>0; }
00142
00143
00144 void getModelTransform(fmat::Transform& tr) const;
00145
00146
00147 fmat::Transform getModelTransform() const {
00148 fmat::Transform tr; getModelTransform(tr); return tr;
00149 }
00150
00151
00152 void getCollisionModelTransform(fmat::Transform& tr) const;
00153
00154
00155 fmat::Transform getCollisionModelTransform() const {
00156 fmat::Transform tr; getCollisionModelTransform(tr); return tr;
00157 }
00158
00159
00160 KinematicJoint* getParent() const { return parent; }
00161
00162
00163 KinematicJoint* getNextMobileAncestor() const;
00164
00165 PLIST_CLONE_DEF(LinkComponent,new LinkComponent(*this));
00166
00167 protected:
00168 KinematicJoint* parent;
00169
00170 mutable bool bbDirty;
00171 mutable BoundingBox3D boundingBox;
00172
00173 virtual void dirtyBB();
00174 virtual void updateBB() const;
00175 void computeOwnAABB(BoundingBox3D& bb) const;
00176 static void computeBB2D(const fmat::Transform& fullT, RectangularObstacle& ro, const fmat::Column<3>& obD);
00177
00178 void init() {
00179 addEntry("Mass",mass,"Mass of the component, in kilograms. If 0, indicates static object, does not move but can still collide. (default 0)");
00180 addEntry("CenterOfMass",centerOfMass,"Position of average mass relative to parent frame.");
00181 addEntry("Visible",visible,"If true, indicates component should be rendered for simulated cameras, otherwise only appears in the Mirage user window. (default true)");
00182 addEntry("Material",material,"Name of an Ogre material, found in mirage/media/*.material files.");
00183 addEntry("Model",model,"An Ogre .mesh file, or \"CollisionModel\" to render the collision primitive. (default CollisionModel)");
00184 addEntry("ModelScale",modelScale,"Scales the graphics mesh loaded by Model.");
00185 addEntry("ModelRotation",modelRotation,"Rotates the graphics mesh loaded by Model, relative to parent frame. (supply axis component of quaternion, e.g. from axis/angle: axis * sin(angle/2) )");
00186 addEntry("ModelOffset",modelOffset,"Positions the graphics mesh loaded by Model, relative to parent frame.");
00187 addEntry("CollisionModel",collisionModel,"A Bullet primitive collision shape: { Cube | Cylinder | Sphere | Plane }");
00188 addEntry("CollisionModelScale",collisionModelScale,"Scales the CollisionModel, which by default is 1x1x1, so this sets the object dimensions.");
00189 addEntry("CollisionModelRotation",collisionModelRotation,"Rotates the CollisionModel relative to parent frame. (supply axis component of quaternion, e.g. from axis/angle: axis * sin(angle/2) )");
00190 addEntry("CollisionModelOffset",collisionModelOffset,"Positions the CollisionModel, relative to parent frame.");
00191 setLoadSavePolicy(FIXED,SYNC);
00192 }
00193
00194
00195 plist::PrimitiveCallbackMember<LinkComponent> collisionModelListener;
00196 plist::CollectionCallbackMember<LinkComponent> collisionModelScaleListener;
00197 plist::CollectionCallbackMember<LinkComponent> collisionModelRotationListener;
00198 plist::CollectionCallbackMember<LinkComponent> collisionModelOffsetListener;
00199 };
00200
00201
00202
00203 class KinematicJoint : public virtual plist::PrimitiveListener, public LinkComponent {
00204 friend class KinematicJointLoader;
00205 friend class KinematicJointSaver;
00206 public:
00207 class BranchListener : public plist::Listener {
00208 public:
00209 virtual void kinematicJointBranchAdded(KinematicJoint& parent, KinematicJoint& branch) {};
00210 virtual void kinematicJointBranchRemoved(KinematicJoint& parent, KinematicJoint& branch) {};
00211 virtual void kinematicJointReconfigured(KinematicJoint& joint) {};
00212 };
00213
00214
00215 KinematicJoint() : plist::Dictionary(), LinkComponent(),
00216 jointType(REVOLUTE, jointTypeNames), theta(0), d(0), alpha(0), r(0), qOffset(0), qmin(0), qmax(0),
00217 components(), frictionForce(0.5f), anistropicFrictionRatio(1,1,1), ikSolver(), sensorInfo(), controllerInfo(), outputOffset(),
00218 branches(), branchListeners(NULL), depth(0), q(0), To(), Tq(), ik(NULL), componentsListener(components,*this)
00219 {
00220 initEntries();
00221 }
00222
00223 KinematicJoint(const KinematicJoint& kj) : plist::Dictionary(), LinkComponent(kj),
00224 jointType(kj.jointType), theta(kj.theta), d(kj.d), alpha(kj.alpha), r(kj.r), qOffset(kj.qOffset), qmin(kj.qmin), qmax(kj.qmax),
00225 components(kj.components), frictionForce(kj.frictionForce), anistropicFrictionRatio(kj.anistropicFrictionRatio), ikSolver(kj.ikSolver), sensorInfo(kj.sensorInfo), controllerInfo(kj.controllerInfo), outputOffset(kj.outputOffset),
00226 branches(), branchListeners(NULL), depth(0), q(kj.q), To(kj.To), Tq(kj.Tq), ik(NULL), componentsListener(components,*this)
00227 {
00228 initEntries();
00229 copyBranches(kj);
00230 }
00231
00232 KinematicJoint& operator=(const KinematicJoint& kj) {
00233 shallowCopy(kj);
00234 copyBranches(kj);
00235 return *this;
00236 }
00237
00238 void shallowCopy(const KinematicJoint& kj) {
00239 if(&kj==this)
00240 return;
00241 LinkComponent::operator=(kj);
00242 jointType = kj.jointType;
00243 theta = kj.theta;
00244 d = kj.d;
00245 alpha = kj.alpha;
00246 r = kj.r;
00247 qOffset = kj.qOffset;
00248 qmin = kj.qmin;
00249 qmax = kj.qmax;
00250 components = kj.components;
00251 frictionForce=kj.frictionForce;
00252 anistropicFrictionRatio=kj.anistropicFrictionRatio;
00253 ikSolver = kj.ikSolver;
00254 sensorInfo = kj.sensorInfo;
00255 controllerInfo = kj.controllerInfo;
00256 outputOffset = kj.outputOffset;
00257 q = kj.q;
00258 To = kj.To;
00259 Tq = kj.Tq;
00260 fireReconfigured();
00261
00262
00263
00264
00265
00266 }
00267
00268 void copyBranches(const KinematicJoint& kj) {
00269 if(&kj==this)
00270 return;
00271
00272 std::set<KinematicJoint*> newBranches;
00273 for(std::set<KinematicJoint*>::const_iterator it=kj.branches.begin(); it!=kj.branches.end(); ++it)
00274 newBranches.insert(new KinematicJoint(**it));
00275 clearBranches();
00276 for(std::set<KinematicJoint*>::const_iterator it=newBranches.begin(); it!=newBranches.end(); ++it)
00277 addBranch(*it);
00278 }
00279
00280 virtual ~KinematicJoint();
00281
00282
00283 enum JointType_t {
00284 REVOLUTE,
00285 PRISMATIC
00286 };
00287
00288 static const char* jointTypeNames[3];
00289
00290 plist::NamedEnumeration<JointType_t> jointType;
00291
00292
00293 plist::Angle theta;
00294 plist::Primitive<fmat::fmatReal> d;
00295 plist::Angle alpha;
00296 plist::Primitive<fmat::fmatReal> r;
00297 plist::Angle qOffset;
00298
00299 plist::Angle qmin;
00300 plist::Angle qmax;
00301
00302
00303 plist::ArrayOf<LinkComponent> components;
00304 typedef plist::ArrayOf<LinkComponent>::const_iterator component_iterator;
00305
00306 plist::Primitive<float> frictionForce;
00307 plist::Point anistropicFrictionRatio;
00308
00309 plist::Primitive<std::string> ikSolver;
00310
00311 plist::ArrayOf<SensorInfo> sensorInfo;
00312
00313
00314
00315 struct ControllerInfo : virtual public plist::Dictionary {
00316 explicit ControllerInfo() : plist::Dictionary(), velocity(false), forceControl(false) { init(); }
00317 ControllerInfo(const ControllerInfo& ci) : plist::Dictionary(), velocity(ci.velocity), forceControl(ci.forceControl) { init(); }
00318 plist::Primitive<bool> velocity;
00319 plist::Primitive<bool> forceControl;
00320 protected:
00321
00322 void init() {
00323 addEntry("Velocity",velocity,"Adjusts interpretation of feedback and application of friction, false implies position control");
00324 addEntry("ForceControl",forceControl,"If true, simulation will use force control to move the joint rather than using position constraints. Grippers should set this to true for more realistic object interaction.");
00325 }
00326 };
00327 ControllerInfo controllerInfo;
00328
00329
00330 plist::OutputSelector outputOffset;
00331
00332
00333 void getObstacles(const fmat::Transform& worldT, class HierarchicalObstacle& obs, bool recurse) const;
00334
00335
00336
00337 virtual BoundingBox3D getOwnAABB() const { BoundingBox3D bb; computeOwnAABB(bb); return bb; }
00338
00339
00340 float getQ() const { return q; }
00341
00342
00343 void setQ(float x) { if(x!=q) { q=x; updateTq(); } }
00344
00345
00346 bool tryQ(float x);
00347
00348
00349 void freezeQ(float x) { qmin=qmax=x; setQ(x); }
00350
00351
00352 bool validQ(float x) const { return (x>=qmin && x<=qmax); }
00353
00354
00355
00356
00357 template<class M> void pushChildrenQIntoArray(M& values, int deoffset, unsigned int max) const {
00358 if(outputOffset!=plist::OutputSelector::UNUSED && static_cast<unsigned int>(outputOffset-deoffset)<max)
00359 values[outputOffset-deoffset]=q;
00360 for(std::set<KinematicJoint*>::const_iterator it=branches.begin(); it!=branches.end(); ++it)
00361 (*it)->pushChildrenQIntoArray(values, deoffset, max);
00362 }
00363
00364
00365
00366
00367 template<class M> void pushAncestorsQIntoArray(M& values, int deoffset, unsigned int max) const {
00368 if(outputOffset!=plist::OutputSelector::UNUSED && static_cast<unsigned int>(outputOffset-deoffset)<max)
00369 values[outputOffset-deoffset]=q;
00370 if(parent!=NULL)
00371 parent->pushAncestorsQIntoArray(values, deoffset, max);
00372 }
00373
00374
00375
00376
00377 template<class M> void pullChildrenQFromArray(M& values, int deoffset, unsigned int max) {
00378 if(outputOffset!=plist::OutputSelector::UNUSED && qmin!=qmax && static_cast<unsigned int>(outputOffset-deoffset)<max)
00379 setQ(values[outputOffset-deoffset]);
00380 for(std::set<KinematicJoint*>::const_iterator it=branches.begin(); it!=branches.end(); ++it)
00381 (*it)->pullChildrenQFromArray(values, deoffset, max);
00382 }
00383
00384
00385
00386
00387 template<class M> void pullAncestorsQFromArray(M& values, int deoffset, unsigned int max) {
00388 if(outputOffset!=plist::OutputSelector::UNUSED && qmin!=qmax && static_cast<unsigned int>(outputOffset-deoffset)<max)
00389 setQ(values[outputOffset-deoffset]);
00390 if(parent!=NULL)
00391 parent->pullAncestorsQFromArray(values, deoffset, max);
00392 }
00393
00394
00395 void zeroChildrenQ();
00396
00397
00398 void zeroAncestorQ();
00399
00400
00401
00402 fmat::Transform getFullT() const;
00403
00404
00405 fmat::Transform getFullInvT() const { return getFullT().rigidInverse(); }
00406
00407
00408 fmat::Transform getT(const KinematicJoint& j) const;
00409
00410
00411
00412 const fmat::Transform& getTo() const { return To; }
00413
00414
00415
00416 const fmat::Transform& getTq() const { return Tq; }
00417
00418
00419 void sumCenterOfMass(fmat::Column<3>& cOfM, float& totalMass) const;
00420
00421
00422
00423 fmat::Column<4> sumCenterOfMass() const;
00424
00425
00426
00427 virtual fmat::Column<4> sumLinkCenterOfMass() const;
00428
00429 using LinkComponent::sumLinkCenterOfMass;
00430
00431 virtual bool hasMass() const;
00432
00433
00434
00435
00436 fmat::Column<6> getJointJacobian(const fmat::Column<3>& p) const;
00437
00438
00439
00440
00441 void getFullJacobian(const fmat::Column<3>& p, std::vector<fmat::Column<6> >& j) const {
00442 if(parent!=NULL)
00443 parent->getFullJacobian(p,j);
00444 j.push_back(getJointJacobian(p));
00445 }
00446
00447
00448
00449
00450 void getMobileJacobian(const fmat::Column<3>& p, std::vector<fmat::Column<6> >& j) const {
00451 if(parent!=NULL)
00452 parent->getMobileJacobian(p,j);
00453 if(isMobile())
00454 j.push_back(getJointJacobian(p));
00455 }
00456
00457
00458 fmat::Column<3> getWorldPosition() const { return getFullT().translation(); }
00459
00460 fmat::Matrix<3,3> getWorldRotation() const { return getFullT().rotation(); }
00461
00462
00463 fmat::Column<3> getPosition() const { return Tq.translation(); }
00464
00465 fmat::Column<3> getParentPosition() const;
00466
00467 fmat::Matrix<3,3> getRotation() const { return Tq.rotation(); }
00468
00469
00470 fmat::Quaternion getWorldQuaternion() const;
00471
00472 fmat::Quaternion getQuaternion(const KinematicJoint& j) const;
00473
00474 fmat::Quaternion getQuaternion() const { return fmat::Quaternion::fromMatrix(Tq.rotation()); }
00475
00476
00477 virtual void loadXML(xmlNode* node);
00478
00479 virtual void saveXML(xmlNode* node, bool onlyOverwrite, std::set<std::string>& seen) const;
00480 using plist::Dictionary::saveXML;
00481
00482
00483
00484
00485
00486 template<class M> void buildChildMap(M& childMap, int deoffset, unsigned int max) {
00487 if(outputOffset!=plist::OutputSelector::UNUSED && static_cast<unsigned int>(outputOffset-deoffset)<max && !childMap[outputOffset-deoffset])
00488 childMap[outputOffset-deoffset] = this;
00489 for(std::set<KinematicJoint*>::const_iterator it=branches.begin(); it!=branches.end(); ++it)
00490 (*it)->buildChildMap(childMap,deoffset,max);
00491 }
00492
00493
00494
00495
00496 template<class M> void buildChildMap(M& childMap, int deoffset, unsigned int max) const {
00497 if(outputOffset!=plist::OutputSelector::UNUSED && static_cast<unsigned int>(outputOffset-deoffset)<max && !childMap[outputOffset-deoffset])
00498 childMap[outputOffset-deoffset] = this;
00499 for(std::set<KinematicJoint*>::const_iterator it=branches.begin(); it!=branches.end(); ++it)
00500 (*it)->buildChildMap(childMap,deoffset,max);
00501 }
00502
00503
00504
00505
00506 template<class M> void buildMobileChildMap(M& childMap, int deoffset, unsigned int max) {
00507 if(isMobile() && outputOffset!=plist::OutputSelector::UNUSED && static_cast<unsigned int>(outputOffset-deoffset)<max)
00508 childMap[outputOffset-deoffset] = this;
00509 for(std::set<KinematicJoint*>::const_iterator it=branches.begin(); it!=branches.end(); ++it)
00510 (*it)->buildMobileChildMap(childMap,deoffset,max);
00511 }
00512
00513
00514
00515
00516 template<class M> void buildMobileChildMap(M& childMap, int deoffset, unsigned int max) const {
00517 if(isMobile() && outputOffset!=plist::OutputSelector::UNUSED && static_cast<unsigned int>(outputOffset-deoffset)<max)
00518 childMap[outputOffset-deoffset] = this;
00519 for(std::set<KinematicJoint*>::const_iterator it=branches.begin(); it!=branches.end(); ++it)
00520 (*it)->buildMobileChildMap(childMap,deoffset,max);
00521 }
00522
00523
00524 typedef std::set<KinematicJoint*>::const_iterator branch_iterator;
00525
00526
00527 const std::set<KinematicJoint*>& getBranches() const { return branches; }
00528
00529
00530
00531 KinematicJoint* addBranch(KinematicJoint* b);
00532
00533
00534
00535 KinematicJoint* removeBranch(KinematicJoint* b);
00536
00537
00538 void clearBranches();
00539
00540
00541 bool isBranch() const { return branches.size()>1; }
00542
00543
00544
00545
00546 KinematicJoint* cloneBranch() const;
00547
00548
00549
00550 KinematicJoint* nextJoint() const { return *branches.begin(); }
00551
00552
00553 bool isMobile() const { return qmin!=qmax; }
00554
00555
00556 KinematicJoint* getRoot() { KinematicJoint* kj=this; while(kj->parent!=NULL) kj=kj->parent; return kj; }
00557
00558 const KinematicJoint* getRoot() const { const KinematicJoint* kj=this; while(kj->parent!=NULL) kj=kj->parent; return kj; }
00559
00560 std::string getPath(const std::string& sep = "/") const { return (parent==NULL ? std::string() : parent->getPath(sep)) + sep + outputOffset.get(); }
00561
00562 size_t getDepth() const { return depth; }
00563
00564 void addBranchListener(BranchListener* l) const;
00565 void removeBranchListener(BranchListener* l) const;
00566 bool isBranchListener(BranchListener* l) const;
00567
00568
00569 IKSolver& getIK() const;
00570
00571 PLIST_CLONE_DEF(KinematicJoint,new KinematicJoint(*this));
00572
00573 protected:
00574
00575 void initEntries() {
00576
00577
00578
00579 addEntry("JointType",jointType);
00580 addEntry("θ",theta);
00581 addEntry("d",d);
00582 addEntry("α",alpha);
00583 addEntry("r",r);
00584 addEntry("qOffset",qOffset);
00585 addEntry("Min",qmin);
00586 addEntry("Max",qmax);
00587 addEntry("Components",components);
00588 addEntry("FrictionForce",frictionForce);
00589 addEntry("AnistropicFrictionRatio",anistropicFrictionRatio);
00590 addEntry("IKSolver",ikSolver);
00591 addEntry("SensorInfo",sensorInfo);
00592 addEntry("ControllerInfo",controllerInfo);
00593 addEntry("Name",outputOffset);
00594 outputOffset.setRange(0,-1U);
00595 addSelfListener();
00596 setLoadSavePolicy(FIXED,SYNC);
00597 }
00598
00599
00600
00601
00602 void getFullT(fmat::Transform& t, const KinematicJoint* endj) const {
00603 if(parent!=endj) {
00604 parent->getFullT(t,endj);
00605 t*=Tq;
00606 } else {
00607 t=Tq;
00608 }
00609 }
00610 void getQuaternion(fmat::Quaternion& quat, const KinematicJoint* endj) const {
00611 if(parent!=endj) {
00612 parent->getQuaternion(quat,endj);
00613 quat *= getQuaternion();
00614 } else {
00615 quat = getQuaternion();
00616 }
00617 }
00618
00619
00620 void doSaveXMLNode(std::set<std::string>& seen, xmlNode* node, const std::string& key, const std::string& indentStr, size_t longestKeyLen) const {
00621 const_iterator it=findEntry(key);
00622 if(it==end())
00623 return;
00624 saveXMLNode(node, key, it->second, indentStr, longestKeyLen);
00625
00626 }
00627 virtual void plistValueChanged(const plist::PrimitiveBase& pl);
00628 virtual void addSelfListener();
00629 virtual void removeSelfListener();
00630 void updateTo();
00631 void updateTq();
00632 virtual void updateBB() const;
00633 void updateDepth() {
00634 if(parent==NULL)
00635 depth=0;
00636 else
00637 depth = parent->depth+1;
00638 std::for_each(branches.begin(), branches.end(), std::mem_fun(&KinematicJoint::updateDepth));
00639 }
00640
00641
00642 std::set<KinematicJoint*> branches;
00643
00644 void fireBranchAdded(KinematicJoint& val);
00645 void fireBranchRemoved(KinematicJoint& val);
00646 void fireReconfigured();
00647 mutable std::set<BranchListener*>* branchListeners;
00648
00649 size_t depth;
00650
00651 fmat::fmatReal q;
00652 fmat::Transform To;
00653 fmat::Transform Tq;
00654 mutable IKSolver * ik;
00655
00656 void setParent(LinkComponent& link) { link.parent = this; dirtyBB(); }
00657 void unsetParent(LinkComponent& link) { link.parent = NULL; dirtyBB(); }
00658
00659 class ComponentsListener : protected plist::CollectionListener {
00660 public:
00661 ComponentsListener(const plist::ArrayOf<LinkComponent>& source, KinematicJoint& kj) : plist::CollectionListener(), comps(source), parent(kj) {
00662 comps.addCollectionListener(this);
00663 }
00664 ~ComponentsListener() { comps.removeCollectionListener(this); }
00665 protected:
00666 virtual void plistCollectionEntryAdded(plist::Collection& , ObjectBase& primitive) { parent.setParent(dynamic_cast<LinkComponent&>(primitive)); }
00667 virtual void plistCollectionEntryRemoved(plist::Collection& , ObjectBase& primitive) { parent.unsetParent(dynamic_cast<LinkComponent&>(primitive)); }
00668 virtual void plistCollectionEntriesChanged(plist::Collection& ) {
00669 for(component_iterator it = comps.begin(); it!=comps.end(); ++it)
00670 parent.setParent(**it);
00671 }
00672 const plist::ArrayOf<LinkComponent>& comps;
00673 KinematicJoint& parent;
00674 } componentsListener;
00675
00676 virtual void dirtyBB() { bbDirty=true; }
00677 };
00678
00679
00680 class KinematicJointLoader : public plist::ArrayOf<KinematicJoint> {
00681 public:
00682
00683 explicit KinematicJointLoader(KinematicJoint& root, xmlNode* node)
00684 : plist::ArrayOf<KinematicJoint>(), parent(&root)
00685 {
00686 addEntry(root);
00687 loadXML(node);
00688 }
00689
00690 protected:
00691
00692 virtual bool loadXMLNode(size_t index, xmlNode* val, const std::string& comment);
00693
00694
00695 KinematicJoint* parent;
00696
00697 private:
00698 KinematicJointLoader(const KinematicJointLoader&);
00699 KinematicJointLoader& operator=(const KinematicJointLoader&);
00700 };
00701
00702
00703 class KinematicJointSaver : public plist::Array {
00704 public:
00705
00706 explicit KinematicJointSaver(const KinematicJoint& c, xmlNode* node=NULL) : plist::Array() {
00707 addEntry(const_cast<KinematicJoint&>(c));
00708 init(c.branches,node);
00709 }
00710
00711 explicit KinematicJointSaver(KinematicJoint& c, bool takeOwnership, xmlNode* node=NULL) : plist::Array() {
00712 if(takeOwnership)
00713 addEntry(&c);
00714 else
00715 addEntry(c);
00716 init(c.branches,node);
00717 }
00718
00719
00720
00721
00722 protected:
00723
00724 virtual void saveXML(xmlNode* node) const;
00725
00726 void init(const std::set<KinematicJoint*>& joints, xmlNode* node);
00727 };
00728
00729
00730
00731
00732
00733
00734 #endif