00001 #include "KinematicJoint.h"
00002 #include "IKSolver.h"
00003 #include "Shared/RobotInfo.h"
00004 #include <cmath>
00005 #include <limits>
00006
00007 using namespace std;
00008
00009 const char* KinematicJoint::jointTypeNames[3] = { "revolute", "prismatic", NULL };
00010 INSTANTIATE_NAMEDENUMERATION_STATICS(KinematicJoint::JointType_t);
00011
00012 PLIST_CLONE_IMP(LinkComponent,new LinkComponent(*this));
00013
00014
00015 bool KinematicJointLoader::loadXMLNode(size_t index, xmlNode* val, const std::string& comment) {
00016 if(xNodeHasName(val,"array")) {
00017 if(index==0) {
00018 xmlChar* path=xGetNodePath(val);
00019 std::cerr << "WARNING: loading kinematic file " << xNodeGetURL(val) << ":" << xmlGetLineNo(val) << " (" << path << "), encountered branch without prior link" << std::endl;
00020 xmlFree(path);
00021 }
00022 if(skipToElement(xNodeGetChildren(val))!=NULL) {
00023 KinematicJoint * kj = new KinematicJoint;
00024 KinematicJointLoader(*kj,val);
00025 parent->addBranch(kj);
00026 } else {
00027 xmlChar* path=xGetNodePath(val);
00028 std::cerr << "WARNING: loading kinematic file " << xNodeGetURL(val) << ":" << xmlGetLineNo(val) << " (" << path << "), skipping empty array" << std::endl;
00029 xmlFree(path);
00030 }
00031 } else {
00032 if(!plist::ArrayOf<KinematicJoint>::loadXMLNode(index==0 ? 0 : size(),val,comment))
00033 return false;
00034 if(index>0) {
00035 parent->addBranch(&back());
00036 parent = &back();
00037 myRef.clear();
00038 }
00039 }
00040 return true;
00041 }
00042
00043
00044
00045
00046 void KinematicJointSaver::saveXML(xmlNode* node) const {
00047 if(node==NULL)
00048 return;
00049 if(xNodeGetChildren(node)==NULL && (xNodeGetParent(node)==NULL || xNodeGetParent(xNodeGetParent(node))==NULL || xNodeHasName(xNodeGetParent(node),"plist"))) {
00050 std::string indentStr=getIndentationPrefix(node);
00051 std::string jointTypes;
00052 const char ** jtName = KinematicJoint::jointTypeNames;
00053 while(*jtName!=NULL && (*jtName)[0]!='\0') {
00054 if(jointTypes.size()>0)
00055 jointTypes+=" | ";
00056 jointTypes+=*jtName++;
00057 }
00058
00059 std::string headerComment="\n"
00060 "##################################################################\n"
00061 "################## Kinematics Configuration ##################\n"
00062 "##################################################################\n"
00063 "\n"
00064 "This is an XML-based format using the Property List (plist) layout.\n"
00065 "\n"
00066 "Each joint is defined by a <dict> element with the keys listed below.\n"
00067 "A branch in the chain is denoted by an <array> containing the\n"
00068 "joints of the sub-chain.\n"
00069 "\n"
00070 " JointType: Indicates the type of motion produced by the joint\n"
00071 " One of: "+jointTypes+"\n"
00072 "\n"
00073 " Denavit-Hartenberg parameters: (here in order of application)\n"
00074 " d: Displacement along the previous joint's z axis\n"
00075 " θ: Rotation about the previous joint's z axis (theta, U+03B8)\n"
00076 " r: Displacement from prev. z along the current joint's x axis\n"
00077 " α: Rotation about the current joint's x axis (alpha, U+03B1)\n"
00078 " In other words, θ and d align the previous joint's x axis with\n"
00079 " this joint's x axis, and then a displacement of r (radius of\n"
00080 " rotation) along this x defines the current joint's origin.\n"
00081 " α then defines the current joint's z axis (the axis of actuation).\n"
00082 "\n"
00083 " qOffset: An additional parameter which shifts the final reference\n"
00084 " frame to the physical joint's 0 position. This is a rotation\n"
00085 " about the joint's z axis for revolute joints, or translation\n"
00086 " along z for prismatic.\n"
00087 " Min: The minimum acceptable joint value for inverse kinematics\n"
00088 " Max: The maximum acceptable joint value for inverse kinematics\n"
00089 " Inverse kinematics ignores this joint if Min==Max (immobile).\n"
00090 "\n"
00091 " Model: for 3D graphics, the name of the OGRE mesh file to render\n"
00092 " for the link following the joint. (drop the \".mesh\" suffix)\n"
00093 " Material: for 3D graphics, the name of the material to apply to\n"
00094 " the model, or blank to use the model's defaults\n"
00095 "\n"
00096 "All distances are in millimeters. Angles are radians, unless a\n"
00097 "'unit' attribute is specified, or a '°' is suffixed. You can\n"
00098 "also specify radians as multiples of Pi, e.g. 'π/2'.\n";
00099 xmlAddChild(node,xmlNewText((const xmlChar*)("\n"+indentStr).c_str()));
00100 xmlAddChild(node,xmlNewComment((const xmlChar*)headerComment.c_str()));
00101 xmlAddChild(node,xmlNewText((const xmlChar*)("\n"+indentStr).c_str()));
00102 }
00103 plist::Array::saveXML(node);
00104 }
00105
00106 void KinematicJointSaver::init(const std::set<KinematicJoint*>& joints, xmlNode* node) {
00107 const std::set<KinematicJoint*>* branches = &joints;
00108 while(branches->size()>0) {
00109 if(branches->size()==1) {
00110 addEntry(**branches->begin());
00111 branches = &(*branches->begin())->branches;
00112 } else {
00113 for(std::set<KinematicJoint*>::const_iterator it=branches->begin(); it!=branches->end(); ++it)
00114 addEntry(new KinematicJointSaver(**it));
00115 break;
00116 }
00117 }
00118 if(node!=NULL)
00119 saveXML(node);
00120 }
00121
00122 KinematicJoint::~KinematicJoint() {
00123 removeSelfListener();
00124 clearBranches();
00125 delete branchListeners;
00126 branchListeners=NULL;
00127 delete ik;
00128 ik=NULL;
00129 }
00130
00131 void KinematicJoint::addBranchListener(BranchListener* l) const {
00132 if(l!=NULL) {
00133 if(branchListeners==NULL)
00134 branchListeners=new std::set<BranchListener*>;
00135 branchListeners->insert(l);
00136 }
00137 }
00138
00139 void KinematicJoint::removeBranchListener(BranchListener* l) const {
00140 if(branchListeners==NULL)
00141 return;
00142 std::set<BranchListener*>::iterator it=branchListeners->find(l);
00143 if(it!=branchListeners->end()) {
00144 branchListeners->erase(it);
00145 if(branchListeners->empty()) {
00146 delete branchListeners;
00147 branchListeners=NULL;
00148 }
00149 }
00150 }
00151
00152 bool KinematicJoint::isBranchListener(BranchListener* l) const {
00153 if(l==NULL)
00154 return false;
00155 if(branchListeners==NULL)
00156 return false;
00157 return ( branchListeners->count(l) > 0 );
00158 }
00159
00160 IKSolver& KinematicJoint::getIK() const {
00161 if(ik!=NULL)
00162 return *ik;
00163 ik = IKSolver::getRegistry().create(ikSolver);
00164 if(ik==NULL) {
00165 ik = IKSolver::getRegistry().create("");
00166 if(ik==NULL)
00167 throw std::runtime_error("Could not create any IKSolvers");
00168 std::cerr << "Warning: could not create any IKSolver '" << ikSolver << "' for " << outputOffset.get() << ", falling back on default generic solver" << std::endl;
00169 }
00170 ikSolver.addPrimitiveListener(const_cast<KinematicJoint*>(this));
00171 return *ik;
00172 }
00173
00174 PLIST_CLONE_IMP(KinematicJoint,new KinematicJoint(*this));
00175
00176 void KinematicJoint::fireBranchAdded(KinematicJoint& val) {
00177 if(branchListeners==NULL)
00178 return;
00179
00180 std::set<BranchListener*> pls=*branchListeners;
00181 for(std::set<BranchListener*>::const_iterator it=pls.begin(); branchListeners!=NULL && it!=pls.end(); ++it) {
00182
00183 if(branchListeners->count(*it)>0)
00184 (*it)->kinematicJointBranchAdded(*this,val);
00185 }
00186 }
00187
00188 void KinematicJoint::fireBranchRemoved(KinematicJoint& val) {
00189 if(branchListeners==NULL)
00190 return;
00191
00192 std::set<BranchListener*> pls=*branchListeners;
00193 for(std::set<BranchListener*>::const_iterator it=pls.begin(); branchListeners!=NULL && it!=pls.end(); ++it) {
00194
00195 if(branchListeners->count(*it)>0)
00196 (*it)->kinematicJointBranchRemoved(*this,val);
00197 }
00198 }
00199
00200 void KinematicJoint::fireReconfigured() {
00201 if(branchListeners==NULL)
00202 return;
00203
00204 std::set<BranchListener*> pls=*branchListeners;
00205 for(std::set<BranchListener*>::const_iterator it=pls.begin(); branchListeners!=NULL && it!=pls.end(); ++it) {
00206
00207 if(branchListeners->count(*it)>0)
00208 (*it)->kinematicJointReconfigured(*this);
00209 }
00210 }
00211
00212
00213
00214 bool KinematicJoint::tryQ(float x) {
00215 const float EPSILON = numeric_limits<float>::epsilon()*100;
00216 if(x>qmax) {
00217 if(q!=qmax) {
00218 q=qmax;
00219 updateTq();
00220 }
00221 return (x-EPSILON < qmax);
00222 } else if(x<qmin) {
00223 if(q!=qmin) {
00224 q=qmin;
00225 updateTq();
00226 }
00227 return (x+EPSILON > qmin);
00228 } else {
00229 if(x!=q) {
00230 q=x;
00231 updateTq();
00232 }
00233 return true;
00234 }
00235 }
00236
00237 void KinematicJoint::zeroChildrenQ() {
00238 if(qmin!=qmax)
00239 setQ(0);
00240 for(std::set<KinematicJoint*>::const_iterator it=branches.begin(); it!=branches.end(); ++it)
00241 (*it)->zeroChildrenQ();
00242 }
00243
00244 void KinematicJoint::zeroAncestorQ() {
00245 for(KinematicJoint* p = this; p!=NULL; p=p->getParent())
00246 if(p->qmin!=p->qmax)
00247 p->setQ(0);
00248 }
00249
00250
00251 fmat::Transform KinematicJoint::getFullT() const {
00252 fmat::Transform t;
00253 getFullT(t,NULL);
00254 return t;
00255 }
00256
00257 fmat::Transform KinematicJoint::getT(const KinematicJoint& j) const {
00258 if(&j==this)
00259 return fmat::Transform::identity();
00260 fmat::Transform t;
00261 const KinematicJoint* myAnc=parent;
00262 const KinematicJoint* jAnc=j.parent;
00263 while(myAnc!=NULL || jAnc!=NULL) {
00264 if(myAnc!=NULL) {
00265 if(myAnc==&j) {
00266 getFullT(t,&j);
00267 return t;
00268 }
00269 myAnc=myAnc->parent;
00270 }
00271 if(jAnc!=NULL) {
00272 if(jAnc==this) {
00273 j.getFullT(t,this);
00274 return t.rigidInverse();
00275 }
00276 jAnc=jAnc->parent;
00277 }
00278 }
00279 getFullT(t,NULL);
00280 return j.getFullInvT() * t;
00281 }
00282
00283 void KinematicJoint::sumCenterOfMass(fmat::Column<3>& cOfM, float& totalMass) const {
00284 fmat::Column<4> com = sumCenterOfMass();
00285 cOfM = fmat::SubVector<3>(com);
00286 if(com[3]>std::numeric_limits<fmat::fmatReal>::epsilon())
00287 cOfM/=com[3];
00288 totalMass=com[3];
00289 }
00290
00291 fmat::Column<4> KinematicJoint::sumCenterOfMass() const {
00292 fmat::Column<4> com = sumLinkCenterOfMass();
00293 for(branch_iterator it=branches.begin(); it!=branches.end(); ++it)
00294 com += (*it)->getTq() * (*it)->sumCenterOfMass();
00295 return com;
00296 }
00297
00298 void LinkComponent::sumLinkCenterOfMass(fmat::Column<3>& cOfM, float& totalMass) const {
00299 fmat::Column<4> com = sumLinkCenterOfMass();
00300 cOfM = fmat::SubVector<3>(com);
00301 if(com[3]>std::numeric_limits<fmat::fmatReal>::epsilon())
00302 cOfM/=com[3];
00303 totalMass=com[3];
00304 }
00305
00306 fmat::Column<4> KinematicJoint::sumLinkCenterOfMass() const {
00307 fmat::Column<4> com = getMassVector();
00308 for(component_iterator it=components.begin(); it!=components.end(); ++it)
00309 com += (*it)->getMassVector();
00310 return com;
00311 }
00312
00313 bool KinematicJoint::hasMass() const {
00314 if(mass > 0)
00315 return true;
00316 for(component_iterator it=components.begin(); it!=components.end(); ++it)
00317 if((*it)->mass > 0)
00318 return true;
00319 return false;
00320 }
00321
00322 fmat::Column<6> KinematicJoint::getJointJacobian(const fmat::Column<3>& p) const {
00323 fmat::Column<6> j;
00324 if(outputOffset>=NumOutputs)
00325 return j;
00326 fmat::Transform t = fmat::Transform::identity();
00327 getFullT(t,NULL);
00328
00329 switch(jointType) {
00330 case REVOLUTE: {
00331 fmat::Column<3> z(t.column(2));
00332 fmat::Column<3> v(t.column(3));
00333 v = p - v;
00334 fmat::SubVector<3>(j,0) = fmat::crossProduct(z,v);
00335 fmat::SubVector<3>(j,3) = &t.column(2)[0];
00336 } break;
00337 case PRISMATIC: {
00338 j=0.f;
00339 fmat::SubVector<3>(j,0) = &t.column(2)[0];
00340 } break;
00341 }
00342 return j;
00343 }
00344
00345 fmat::Column<3> KinematicJoint::getParentPosition() const {
00346 fmat::Column<3> p = -Tq.column(3);
00347 return fmat::pack(fmat::dotProduct(Tq.column(0),p), fmat::dotProduct(Tq.column(1),p), fmat::dotProduct(Tq.column(2),p));
00348 }
00349
00350 fmat::Quaternion KinematicJoint::getWorldQuaternion() const {
00351 fmat::Quaternion quat;
00352 getQuaternion(quat,NULL);
00353 return quat;
00354 }
00355
00356 fmat::Quaternion KinematicJoint::getQuaternion(const KinematicJoint& j) const {
00357 if(&j==this)
00358 return fmat::Quaternion::identity();
00359 fmat::Quaternion quat;
00360 const KinematicJoint* myAnc=parent;
00361 const KinematicJoint* jAnc=j.parent;
00362 while(myAnc!=NULL || jAnc!=NULL) {
00363 if(myAnc!=NULL) {
00364 if(myAnc==&j) {
00365 getQuaternion(quat,&j);
00366 return quat;
00367 }
00368 myAnc=myAnc->parent;
00369 }
00370 if(jAnc!=NULL) {
00371 if(jAnc==this) {
00372 j.getQuaternion(quat,this);
00373 return quat.inverse();
00374 }
00375 jAnc=jAnc->parent;
00376 }
00377 }
00378 getQuaternion(quat,NULL);
00379 fmat::Quaternion jq;
00380 j.getQuaternion(jq,NULL);
00381 return jq.inverse() * quat;
00382 }
00383
00384 void KinematicJoint::loadXML(xmlNode* node) {
00385 removeSelfListener();
00386 clearBranches();
00387 if(xNodeHasName(node,"array")) {
00388 try {
00389 KinematicJointLoader(*this,node);
00390 } catch(...) {
00391 addSelfListener();
00392 throw;
00393 }
00394 } else {
00395 try {
00396 LinkComponent::loadXML(node);
00397 } catch(...) {
00398 addSelfListener();
00399 throw;
00400 }
00401 }
00402 addSelfListener();
00403 }
00404
00405 void KinematicJoint::saveXML(xmlNode* node, bool onlyOverwrite, std::set<std::string>& seen) const {
00406 if(node==NULL)
00407 return;
00408 if(xNodeGetParent(node)==NULL || xNodeGetParent(xNodeGetParent(node))==NULL || xNodeHasName(xNodeGetParent(node),"plist")) {
00409 KinematicJointSaver(*this,node);
00410 } else {
00411 if(xNodeGetChildren(node)==NULL && seen.size()==0) {
00412
00413 std::string indentStr=getIndentationPrefix(node);
00414 size_t longestKeyLen = getLongestKeyLen(NULL,1);
00415 doSaveXMLNode(seen, node, "Name", indentStr, longestKeyLen);
00416 doSaveXMLNode(seen, node, "JointType", indentStr, longestKeyLen);
00417 doSaveXMLNode(seen, node, "d", indentStr, longestKeyLen);
00418 doSaveXMLNode(seen, node, "θ", indentStr, longestKeyLen);
00419 doSaveXMLNode(seen, node, "r", indentStr, longestKeyLen);
00420 doSaveXMLNode(seen, node, "α", indentStr, longestKeyLen);
00421 doSaveXMLNode(seen, node, "qOffset", indentStr, longestKeyLen);
00422 doSaveXMLNode(seen, node, "Min", indentStr, longestKeyLen);
00423 doSaveXMLNode(seen, node, "Max", indentStr, longestKeyLen);
00424 std::string parentIndent;
00425 if(indentStr.size()>=perIndent().size())
00426 parentIndent=indentStr.substr(perIndent().size());
00427 xmlAddChild(node,xmlNewText((const xmlChar*)("\n"+parentIndent).c_str()));
00428 }
00429
00430 LinkComponent::saveXML(node,onlyOverwrite,seen);
00431 }
00432 }
00433
00434 void KinematicJoint::plistValueChanged(const plist::PrimitiveBase& pl) {
00435 updateTo();
00436 if(&pl==&jointType) {
00437 switch(*jointType) {
00438 case REVOLUTE: {
00439 qOffset.setFormat(plist::Angle::FORMAT_SAME);
00440 qmin.setFormat(plist::Angle::FORMAT_SAME);
00441 qmax.setFormat(plist::Angle::FORMAT_SAME);
00442 } break;
00443 case PRISMATIC: {
00444 qOffset.setFormat(plist::Angle::FORMAT_NONE);
00445 qmin.setFormat(plist::Angle::FORMAT_NONE);
00446 qmax.setFormat(plist::Angle::FORMAT_NONE);
00447 } break;
00448 }
00449 } else if(&pl==&ikSolver) {
00450 delete ik;
00451 ik=NULL;
00452 ikSolver.removePrimitiveListener(this);
00453 }
00454 fireReconfigured();
00455 }
00456
00457 void KinematicJoint::addSelfListener() {
00458 jointType.addPrimitiveListener(this);
00459 theta.addPrimitiveListener(this);
00460 d.addPrimitiveListener(this);
00461 alpha.addPrimitiveListener(this);
00462 r.addPrimitiveListener(this);
00463 qOffset.addPrimitiveListener(this);
00464 plistValueChanged(jointType);
00465 }
00466
00467 void KinematicJoint::removeSelfListener() {
00468 jointType.removePrimitiveListener(this);
00469 theta.removePrimitiveListener(this);
00470 d.removePrimitiveListener(this);
00471 alpha.removePrimitiveListener(this);
00472 r.removePrimitiveListener(this);
00473 qOffset.removePrimitiveListener(this);
00474 }
00475
00476 void KinematicJoint::updateTo() {
00477 fmat::fmatReal ct = std::cos(static_cast<fmat::fmatReal>(theta));
00478 fmat::fmatReal st = std::sin(static_cast<fmat::fmatReal>(theta));
00479 fmat::fmatReal ca = std::cos(static_cast<fmat::fmatReal>(alpha));
00480 fmat::fmatReal sa = std::sin(static_cast<fmat::fmatReal>(alpha));
00481
00482
00483
00484
00485
00486
00487
00488
00489 fmat::fmatReal mat[16] = {
00490 ct, st, 0,
00491 -st*ca, ct*ca, sa,
00492 st*sa, -ct*sa, ca,
00493 r*ct, r*st, d
00494 };
00495 To = mat;
00496
00497
00498
00499
00500
00501
00502
00503 Tq = mat; updateTq();
00504 }
00505
00506 void KinematicJoint::updateTq() {
00507 const fmat::fmatReal qv = static_cast<fmat::fmatReal>(q+qOffset);
00508 switch(jointType) {
00509 case REVOLUTE: {
00510 const fmat::fmatReal cq = std::cos(qv);
00511 const fmat::fmatReal sq = std::sin(qv);
00512 const fmat::fmatReal t11=To(0,0), t12=To(0,1), t21=To(1,0), t22=To(1,1), t32=To(2,1);
00513 Tq(0,0) = cq*t11 + sq*t12;
00514 Tq(1,0) = cq*t21 + sq*t22;
00515 Tq(2,0) = sq*t32;
00516 Tq(0,1) = -sq*t11 + cq*t12;
00517 Tq(1,1) = -sq*t21 + cq*t22;
00518 Tq(2,1) = cq*t32;
00519 } break;
00520 case PRISMATIC: {
00521 Tq(0,3) = To(0,2)*qv + To(0,3);
00522 Tq(1,3) = To(1,2)*qv + To(1,3);
00523 Tq(2,3) = To(2,2)*qv + To(2,3);
00524 } break;
00525 }
00526 }
00527
00528 void LinkComponent::getModelTransform(fmat::Transform& tr) const {
00529 tr.rotation() = fmat::Quaternion::fromAxis(modelRotation).toMatrix();
00530 tr.translation().importFrom(modelOffset);
00531 }
00532
00533 void LinkComponent::getCollisionModelTransform(fmat::Transform& tr) const {
00534 tr.rotation() = fmat::Quaternion::fromAxis(collisionModelRotation).toMatrix();
00535 tr.translation().importFrom(collisionModelOffset);
00536 }
00537
00538 KinematicJoint* LinkComponent::getNextMobileAncestor() const {
00539 KinematicJoint* joint = parent;
00540 if (!joint) return NULL;
00541 while (joint->isMobile() == false) {
00542 joint = joint->getParent();
00543 if (!joint) return NULL;
00544 }
00545 return joint;
00546 }
00547
00548 PlannerObstacle2D* LinkComponent::getObstacle(const fmat::Transform& worldT) const {
00549 if(collisionModel.empty())
00550 return NULL;
00551 bool asCirc=false;
00552 if(collisionModel=="Sphere") {
00553 asCirc = true;
00554 } else if(collisionModel=="Cylinder") {
00555 fmat::Quaternion q = fmat::Quaternion::fromAxis(collisionModelRotation);
00556 fmat::Matrix<3,3> rot = worldT.rotation() * q.toMatrix();
00557 if(std::abs(rot(2,2))>0.9)
00558 asCirc=true;
00559 }
00560 if(asCirc) {
00561 RectangularObstacle ro;
00562 getOwnBB2D(worldT, ro);
00563 return new EllipticalObstacle(ro.getCenter(), ro.getWidth()/2, ro.getHeight()/2, ro.getOrientation());
00564 } else {
00565 RectangularObstacle * ro = new RectangularObstacle;
00566 getOwnBB2D(worldT, *ro);
00567 return ro;
00568 }
00569 }
00570
00571 void LinkComponent::getObstacles(const fmat::Transform& worldT, HierarchicalObstacle& obs, bool ) const {
00572 PlannerObstacle2D * o = getObstacle(worldT);
00573 if(o!=NULL)
00574 obs.add(o);
00575 }
00576
00577 void KinematicJoint::getObstacles(const fmat::Transform& worldT, HierarchicalObstacle& obs, bool recurse) const {
00578 fmat::Transform tr = worldT * getTq();
00579 LinkComponent::getObstacles(tr,obs,recurse);
00580 for(component_iterator it = components.begin(); it!=components.end(); ++it) {
00581 (*it)->getObstacles(tr,obs,recurse);
00582 }
00583 if(recurse) {
00584 for(branch_iterator it = branches.begin(); it!=branches.end(); ++it) {
00585 (*it)->getObstacles(tr, obs, recurse);
00586 }
00587 }
00588 }
00589
00590 void LinkComponent::dirtyBB() {
00591 bbDirty=true;
00592 if(parent!=NULL)
00593 static_cast<LinkComponent&>(*parent).dirtyBB();
00594 }
00595
00596 void LinkComponent::computeOwnAABB(BoundingBox3D& bb) const {
00597 if(collisionModel.size()==0) {
00598
00599 bb.clear();
00600 return;
00601 }
00602 fmat::Column<3> ex;
00603 ex.importFrom(collisionModelScale);
00604 ex/=2;
00605 fmat::Quaternion q = fmat::Quaternion::fromAxis(collisionModelRotation);
00606
00607
00608 fmat::Column<3> b = fmat::abs(ex);
00609 ex[0]=-ex[0]; b.maximize(fmat::abs(q*ex));
00610 ex[1]=-ex[1]; b.maximize(fmat::abs(q*ex));
00611 ex[0]=-ex[0]; b.maximize(fmat::abs(q*ex));
00612
00613
00614 fmat::Column<3> off; off.importFrom(collisionModelOffset);
00615 bb.min = off - b;
00616 bb.max = off + b;
00617 }
00618
00619 void LinkComponent::updateBB() const {
00620 computeOwnAABB(boundingBox);
00621 bbDirty=false;
00622 }
00623
00624 void KinematicJoint::updateBB() const {
00625 LinkComponent::updateBB();
00626 for(component_iterator it = components.begin(); it!=components.end(); ++it) {
00627 if((*it)->collisionModel.size()==0)
00628 continue;
00629 boundingBox.expand((*it)->getAABB());
00630 }
00631 }
00632
00633 bool LinkComponent::getOwnBB2D(const fmat::Transform& worldT, RectangularObstacle& ro) const {
00634 if (collisionModel.empty())
00635 return false;
00636 fmat::Transform obT;
00637 getCollisionModelTransform(obT);
00638 fmat::Transform fullT = worldT * obT;
00639 computeBB2D(fullT, ro, collisionModelScale.exportTo<fmat::Column<3> >());
00640 return true;
00641 }
00642
00643 bool LinkComponent::getOwnBB3D(const fmat::Transform& worldT, BoxObstacle& bo) const {
00644 if (collisionModel.empty())
00645 return false;
00646 fmat::Transform obT;
00647 getCollisionModelTransform(obT);
00648 fmat::Transform fullT = worldT * obT;
00649 bo.reset(fullT.translation(),
00650 collisionModelScale.exportTo<fmat::Column<3> >()/2,
00651 fmat::SubMatrix<3,3,const fmat::fmatReal>(fullT.rotation()));
00652 return true;
00653 }
00654
00655 bool LinkComponent::getBB2D(const fmat::Transform& worldT, RectangularObstacle& ro) const {
00656 const BoundingBox3D& bb = getAABB();
00657 if (bb.empty())
00658 return false;
00659 fmat::Transform fullT = worldT;
00660 fullT.translation()+=bb.getCenter();
00661 computeBB2D(fullT, ro, bb.getDimensions());
00662 return true;
00663 }
00664
00665 bool LinkComponent::getBB3D(const fmat::Transform& worldT, BoxObstacle& bo) const {
00666 const BoundingBox3D& bb = getAABB();
00667 if (bb.empty())
00668 return false;
00669 fmat::Transform fullT = worldT;
00670 fullT.translation()+=bb.getCenter();
00671 bo.reset(fullT.translation(),
00672 bb.getDimensions()/2,
00673 fmat::SubMatrix<3,3,const fmat::fmatReal>(fullT.rotation()));
00674 return true;
00675 }
00676
00677 void LinkComponent::computeBB2D(const fmat::Transform& fullT, RectangularObstacle& ro, const fmat::Column<3>& obD) {
00678
00679
00680
00681
00682
00683 fmat::Matrix<2,3> projR(fullT.rotation());
00684
00685
00686 fmat::Column<3> prD;
00687 for(size_t i=0; i<3; ++i)
00688 prD[i] = std::abs(projR.column(i).norm() * obD[i]);
00689
00690
00691
00692 fmat::Column<2> primary = projR.column(0);
00693 if(prD[2] > prD[1]) {
00694 if(prD[2] > prD[0]) {
00695
00696
00697 if(prD[0] > prD[1]) {
00698 if(fullT(2,1)>0) {
00699 primary = fmat::normalRight(projR.column(2));
00700 } else {
00701 primary = fmat::normalLeft(projR.column(2));
00702 }
00703 } else {
00704 primary = projR.column(2);
00705 }
00706
00707
00708
00709 }
00710 } else if(prD[1] > prD[0]) {
00711
00712
00713 if(prD[0] > prD[2]) {
00714 if(fullT(2,2)>0) {
00715 primary = fmat::normalRight(projR.column(1));
00716 } else {
00717 primary = fmat::normalLeft(projR.column(1));
00718 }
00719 } else {
00720 if(fullT(2,0)>0) {
00721 primary = fmat::normalLeft(projR.column(1));
00722 } else {
00723 primary = fmat::normalRight(projR.column(1));
00724 }
00725 }
00726
00727
00728
00729 }
00730 fmat::fmatReal primaryNorm = primary.norm();
00731 if(primaryNorm==0) {
00732
00733 ro.reset(fmat::SubVector<2,const fmat::fmatReal>(fullT.translation()), fmat::pack(0,0), 0);
00734 return;
00735 }
00736 primary/=primaryNorm;
00737
00738
00739 fmat::Matrix<2,2> boxR;
00740 boxR(0,0) = primary[0]; boxR(0,1) = primary[1];
00741 boxR(1,0) =-primary[1]; boxR(1,1) = primary[0];
00742
00743 fmat::Matrix<2,2> boxProj = boxR * fmat::SubMatrix<2,2>(projR);
00744
00745 fmat::Column<2> off = boxR * projR.column(2) * obD[2];
00746
00747
00748
00749 fmat::Column<2> xyD(obD);
00750 fmat::Column<2> dim = fmat::abs(boxProj*xyD + off);
00751 xyD[0]=-xyD[0];
00752 dim.maximize(fmat::abs(boxProj*xyD + off));
00753 xyD[1]=-xyD[1];
00754 dim.maximize(fmat::abs(boxProj*xyD + off));
00755 xyD[0]=-xyD[0];
00756 dim.maximize(fmat::abs(boxProj*xyD + off));
00757
00758 ro.reset(fmat::SubVector<2,const fmat::fmatReal>(fullT.translation()), dim/2, boxR.transpose());
00759 }
00760
00761 KinematicJoint* KinematicJoint::addBranch(KinematicJoint* b) {
00762 if(b==NULL)
00763 throw std::runtime_error("Attempted to add NULL branch to KinematicJoint");
00764 if(b==this)
00765 throw std::runtime_error("Attempted to add KinematicJoint as its own branch (no loops!)");
00766 if(!branches.insert(b).second)
00767 return b;
00768 if(b->parent!=NULL)
00769 throw std::runtime_error("KinematicJoint was told to add a branch which already has a parent. Pass a clone instead (no loops)");
00770 if(b->depth>0)
00771 throw std::runtime_error("KinematicJoint was told to add a branch which has a non-zero depth (but doesn't have a parent!?!? Something's broken.)");
00772 b->parent=this;
00773 b->updateDepth();
00774 fireBranchAdded(*b);
00775 return b;
00776 }
00777
00778 KinematicJoint* KinematicJoint::removeBranch(KinematicJoint* b) {
00779 if(branches.erase(b)==0)
00780 return NULL;
00781 b->parent=NULL;
00782 b->depth=0;
00783 fireBranchRemoved(*b);
00784 return b;
00785 }
00786
00787 void KinematicJoint::clearBranches() {
00788 if(branchListeners==NULL) {
00789 for(std::set<KinematicJoint*>::const_iterator it=branches.begin(); it!=branches.end(); ++it)
00790 delete *it;
00791 branches.clear();
00792 } else {
00793 while(branches.size()>0)
00794 delete removeBranch(*branches.begin());
00795 }
00796 }
00797
00798 KinematicJoint* KinematicJoint::cloneBranch() const {
00799 KinematicJoint * leaf=NULL, *cur = NULL;
00800 const KinematicJoint * next=this;
00801 while(next!=NULL) {
00802 KinematicJoint * tmp = new KinematicJoint;
00803 tmp->shallowCopy(*next);
00804 if(cur!=NULL)
00805 tmp->addBranch(cur);
00806 else
00807 leaf = tmp;
00808 cur=tmp;
00809 next = next->parent;
00810 }
00811 return leaf;
00812 }
00813
00814
00815
00816
00817