00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <robot/sim/VisualIKORTest>
00026
00027 #include <base/Externalizer>
00028 #include <base/externalization_error>
00029 #include <base/Expression>
00030 #include <base/Matrix>
00031 #include <base/VDirectory>
00032 #include <base/VFile>
00033
00034 #include <osg/Group>
00035 #include <osg/Switch>
00036 #include <osg/Geode>
00037 #include <osg/Geometry>
00038 #include <osgText/Font>
00039 #include <osgText/Text>
00040
00041
00042 using robot::sim::VisualIKORTest;
00043
00044 using base::Vector;
00045 using base::Orient;
00046 using base::Time;
00047 using base::PathName;
00048 using base::VFile;
00049 using base::VDirectory;
00050 using base::externalization_error;
00051 using base::Path;
00052 using base::Trajectory;
00053 using base::dom::DOMNode;
00054 using base::dom::DOMElement;
00055 using gfx::Segment3;
00056 using gfx::Color4;
00057 using robot::sim::IKORTest;
00058 using robot::sim::BasicEnvironment;
00059 using robot::control::kinematics::FullSpaceSolver;
00060 using robot::control::kinematics::InverseKinematicsSolver;
00061 using robot::control::kinematics::FullSpaceSolver;
00062 using robot::control::kinematics::IKOR;
00063
00064
00065
00066
00067
00068 VisualIKORTest::VisualIKORTest(ref<base::VFile> testSpecification,
00069 ref<base::VFileSystem> fs, ref<base::Cache> cache)
00070 : IKORTest(testSpecification, fs, cache)
00071 {
00072 }
00073
00074
00075
00076 osg::Vec3Array* VisualIKORTest::newVertexArrayFromLines(const VisualIKORTest::LineSegArray& lines)
00077 {
00078 osg::Vec3Array& v(*NewObj osg::Vec3Array(lines.size()*2));
00079 for(Int i=0; i<lines.size(); i++) {
00080 const Point3& s(lines[i].s);
00081 const Point3& e(lines[i].e);
00082 v[2*i].set(s.x,s.y,s.z);
00083 v[2*i+1].set(e.x,e.y,e.z);
00084 }
00085 return &v;
00086 }
00087
00088
00089 osg::Geometry* VisualIKORTest::newGeometryFromLines(const VisualIKORTest::LineSegArray& lines, const gfx::Color4& color)
00090 {
00091 osg::Geometry* linesGeom = new osg::Geometry();
00092 osg::Vec3Array* verts(newVertexArrayFromLines(lines));
00093 linesGeom->setVertexArray(verts);
00094 osg::Vec4Array& colora(*new osg::Vec4Array(1));
00095 colora[0].set(color.r, color.g, color.b, color.a);
00096 linesGeom->setColorArray(&colora);
00097 linesGeom->setColorBinding(osg::Geometry::BIND_OVERALL);
00098 linesGeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINES,0,lines.size()*2));
00099 return linesGeom;
00100 }
00101
00102
00103
00104 VisualIKORTest::LineSegArray VisualIKORTest::manipToolAsLines(const KinematicChain& chain, const Vector& q, Int numPlatformLinks)
00105 {
00106
00107 LineSegArray lines;
00108
00109
00110 array<Vector> links( chain.getLinkOrigins(q) );
00111 for(Int l=numPlatformLinks+1; l<links.size(); l++) {
00112 const Vector& plink(links[l-1]);
00113 const Vector& link( links[l]);
00114 lines.push_back(Segment3(Point3(plink[0],plink[1],plink[2]), Point3(link[0],link[1],link[2])));
00115
00116 lines.push_back(Segment3(Point3(link[0],link[1],link[2]), Point3(link[0],link[1],link[2]+0.05)));
00117 }
00118
00119 return lines;
00120 }
00121
00122
00123 VisualIKORTest::LineSegArray VisualIKORTest::platformAsLines(ref<const PlatformDescription> platfDescr,
00124 const KinematicChain& platfChain,
00125 const Vector& q, Real steerAngle)
00126 {
00127
00128 LineSegArray lines;
00129
00130 const base::Dimension3 dim(platfDescr->dimensions());
00131 Vector3 offset(platfDescr->originOffset());
00132
00133 Vector3 c1(-dim.x/2.0, -dim.y/2.0, 0), c2(-dim.x/2.0, dim.y/2.0, 0),
00134 c3(dim.x/2.0, dim.y/2.0, 0), c4(dim.x/2.0, -dim.y/2.0, 0);
00135 c1-=offset; c2-=offset; c3-=offset; c4-=offset;
00136
00137 Vector pf_q;
00138 if (platfChain.dof() > 0) pf_q = vectorRange(q,Range(0,platfChain.dof()));
00139 Matrix4 pT(base::toMatrix4(platfChain.getForwardKinematics(pf_q)));
00140 c1 = pT*c1; c2 = pT*c2; c3 = pT*c3; c4 = pT*c4;
00141
00142 lines.push_back(Segment3(c1,c2));
00143 lines.push_back(Segment3(c2,c3));
00144 lines.push_back(Segment3(c3,c4));
00145 lines.push_back(Segment3(c4,c1));
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176 return lines;
00177 }
00178
00179
00180
00181 static inline gfx::Segment3 translate(const gfx::Segment3& s, const base::Vector3& t)
00182 {
00183 gfx::Segment3 ts(s); ts.s += t; ts.e += t;
00184 return ts;
00185 }
00186
00187
00188 VisualIKORTest::LineSegArray VisualIKORTest::obstaclesAsLines(ref<const BasicEnvironment> env)
00189 {
00190 LineSegArray lines;
00191
00192 for(Int i=0; i<env->numObstacles(); i++) {
00193 ref<const BasicEnvironment::Obstacle> obst(env->getObstacle(i));
00194
00195 switch (obst->type) {
00196
00197 case BasicEnvironment::Obstacle::BoxObstacle: {
00198 const base::Dimension3& dim(obst->dims);
00199 Vector3 c1(-dim.x/2.0, -dim.y/2.0, -dim.z/2.0), c2(-dim.x/2.0, dim.y/2.0, -dim.z/2.0),
00200 c3(dim.x/2.0, dim.y/2.0, -dim.z/2.0), c4(dim.x/2.0, -dim.y/2.0, -dim.z/2.0);
00201 Vector3 c5(-dim.x/2.0, -dim.y/2.0, dim.z/2.0), c6(-dim.x/2.0, dim.y/2.0, dim.z/2.0),
00202 c7(dim.x/2.0, dim.y/2.0, dim.z/2.0), c8(dim.x/2.0, -dim.y/2.0, dim.z/2.0);
00203
00204
00205 Matrix4 T( obst->orientation.getRotationMatrix3() );
00206 T.setTranslationComponent( obst->position );
00207 c1 = T*c1; c2 = T*c2; c3 = T*c3; c4 = T*c4;
00208 c5 = T*c5; c6 = T*c6; c7 = T*c7; c8 = T*c8;
00209
00210
00211 lines.push_back(Segment3(c1,c2));
00212 lines.push_back(Segment3(c2,c3));
00213 lines.push_back(Segment3(c3,c4));
00214 lines.push_back(Segment3(c4,c1));
00215
00216
00217 lines.push_back(Segment3(c5,c6));
00218 lines.push_back(Segment3(c6,c7));
00219 lines.push_back(Segment3(c7,c8));
00220 lines.push_back(Segment3(c8,c5));
00221
00222
00223 lines.push_back(Segment3(c1,c5));
00224 lines.push_back(Segment3(c2,c6));
00225 lines.push_back(Segment3(c3,c7));
00226 lines.push_back(Segment3(c4,c8));
00227 } break;
00228
00229 case BasicEnvironment::Obstacle::SphereObstacle: {
00230
00231 Transform rot(Orient(consts::Pi/4.0, consts::Pi/4.0, 0));
00232
00233 Real r = obst->radius;
00234 Point3 c = obst->position;
00235 Real inc = consts::Pi/32.0;
00236 for(Real a=inc; a<=2*consts::Pi; a+=inc) {
00237 Real c1 = r*cos(a-inc);
00238 Real s1 = r*sin(a-inc);
00239 Real c2 = r*cos(a);
00240 Real s2 = r*sin(a);
00241
00242 Point3 xy1( c1, s1, 0);
00243 Point3 xy2( c2, s2, 0);
00244 Segment3 xy(xy1, xy2);
00245 lines.push_back(translate(xy,c));
00246 xy.transform(rot);
00247 lines.push_back(translate(xy,c));
00248 Point3 yz1( 0, c1, s1);
00249 Point3 yz2( 0, c2, s2);
00250 Segment3 yz(yz1, yz2);
00251 lines.push_back(translate(yz,c));
00252 yz.transform(rot);
00253 lines.push_back(translate(yz,c));
00254 Point3 xz1( c1, 0, s1);
00255 Point3 xz2( c2, 0, s2);
00256 Segment3 xz(xz1,xz2);
00257 lines.push_back(translate(xz,c));
00258 xz.transform(rot);
00259 lines.push_back(translate(xz,c));
00260
00261 }
00262
00263 } break;
00264
00265 default:
00266 Logfln("warning: unknown obstacle type (" << obst->type << ") not displayed");
00267 }
00268
00269 }
00270
00271 return lines;
00272 }
00273
00274
00275
00276 VisualIKORTest::LineSegArray VisualIKORTest::trajectoryAsLines(const array<base::Vector>& xs)
00277 {
00278 LineSegArray lines;
00279
00280 for(Int i=0; i<xs.size()-1; i++) {
00281 const Vector& xi(xs[i]);
00282 const Vector& xip1(xs[i+1]);
00283 lines.push_back(Segment3(Point3(xi[0],xi[1],xi[2]), Point3(xip1[0],xip1[1],xip1[2])));
00284 }
00285
00286 return lines;
00287 }
00288
00289
00290
00291
00292 osg::Node* VisualIKORTest::createOSGVisual(Attributes visualAttributes) const
00293 {
00294 if ((node!=0) && (attributes==visualAttributes))
00295 return &(*node);
00296
00297 osg::Switch* worldNode = new osg::Switch();
00298 worldNode->addChild( osgCreateObstacles() );
00299 worldNode->addChild( osgCreateAxes() );
00300 worldNode->addChild( osgCreateTrajectory() );
00301
00302 worldNode->addChild( osgCreateManipulator() );
00303
00304 worldNode->setAllChildrenOn();
00305 worldNode->setValue(0,displayObstacles);
00306 worldNode->setValue(1,displayAxes);
00307 worldNode->setValue(2,displayEEPath);
00308
00309 worldNode->getOrCreateStateSet()->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
00310
00311 node = worldNode;
00312 return &(*node);
00313 }
00314
00315
00316
00317 osg::Node* VisualIKORTest::osgCreateAxes() const
00318 {
00319 const Real l = 1.0;
00320 const Real charSize = 0.2;
00321 osg::Vec4 labelCol(0,0,0,1);
00322
00323 osg::Geode* geode = new osg::Geode();
00324
00325 LineSegArray axes;
00326 axes.push_back(Vector3(l,0,0));
00327 axes.push_back(Vector3(0,l,0));
00328 axes.push_back(Vector3(0,0,l));
00329 osg::Geometry* linesGeom = newGeometryFromLines(axes, Color4(0.5,0.5,0.5));
00330 geode->addDrawable(linesGeom);
00331
00332
00333 String font("fonts/times.ttf");
00334
00335 osgText::Text* xtext = new osgText::Text;
00336 xtext->setFont(font);
00337 xtext->setCharacterSize(charSize);
00338 xtext->setFontSize(20,20);
00339 xtext->setColor(labelCol);
00340 xtext->setPosition(osg::Vec3(1.05,0,0));
00341 xtext->setAxisAlignment(osgText::Text::SCREEN);
00342 xtext->setText("X");
00343 geode->addDrawable(xtext);
00344
00345 osgText::Text* ytext = new osgText::Text;
00346 ytext->setFont(font);
00347 ytext->setCharacterSize(charSize);
00348 ytext->setFontSize(20,20);
00349 ytext->setColor(labelCol);
00350 ytext->setPosition(osg::Vec3(0,1.05,0));
00351 ytext->setAxisAlignment(osgText::Text::SCREEN);
00352 ytext->setText("Y");
00353 geode->addDrawable(ytext);
00354
00355 osgText::Text* ztext = new osgText::Text;
00356 ztext->setFont(font);
00357 ztext->setCharacterSize(charSize);
00358 ztext->setFontSize(20,20);
00359 ztext->setColor(labelCol);
00360 ztext->setPosition(osg::Vec3(0,0,1.05));
00361 ztext->setAxisAlignment(osgText::Text::SCREEN);
00362 ztext->setText("Z");
00363 geode->addDrawable(ztext);
00364
00365 return geode;
00366 }
00367
00368
00369 osg::Node* VisualIKORTest::osgCreateObstacles() const
00370 {
00371 osg::Geode* geode = new osg::Geode();
00372 geode->addDrawable( newGeometryFromLines(obstaclesAsLines(env),Color4(0.3,0.3,0.9)) );
00373 return geode;
00374 }
00375
00376
00377 osg::Node* VisualIKORTest::osgCreateManipulator() const
00378 {
00379 ref<const BasicEnvironment> env(getEnvironment());
00380 ref<const SimulatedRobot> robot( narrow_ref<const SimulatedRobot>(getRobot()) );
00381 Int testManipulatorIndex = getManipulatorIndex();
00382
00383 ref<const RobotDescription> robotDescr(robot->getRobotDescription());
00384 ref<const PlatformDescription> platfDescr(robotDescr->platform() );
00385
00386 Matrix4 platformTransform( robot->getOrientation().getRotationMatrix3() );
00387 platformTransform.setTranslationComponent( robot->getPosition() );
00388
00389 KinematicChain robotChain(robotDescr->getKinematicChain(3,platformTransform,testManipulatorIndex,0));
00390 KinematicChain platfChain(platfDescr->getKinematicChain(3,platformTransform));
00391 Int numPlatfLinks = platfChain.size();
00392
00393
00394 osg::Group* testsGroup = new osg::Group();
00395
00396 Int stepCount=0;
00397 for(Int t=0; t<tests.size(); t++) {
00398 const Test& test(tests[t]);
00399
00400 KinematicChain chain(robotChain);
00401
00402
00403 bool toolAttached = false;
00404 if (test.toolAttached) {
00405 for(Int i=0; (i<env->numTools()) && !toolAttached; i++) {
00406 ref<const ToolDescription> td( env->getTool(i)->getToolDescription() );
00407
00408 if (td->getName() == test.toolName) {
00409 toolAttached = true;
00410 KinematicChain toolChain( td->getKinematicChain() );
00411 chain += toolChain;
00412 }
00413 }
00414 }
00415
00416
00417
00418 osg::Switch* testPlatfSwitch = new osg::Switch();
00419 osg::Switch* testManipSwitch = new osg::Switch();
00420
00421 Vector pf_prevq(platfChain.dof());
00422 Vector pf_q(platfChain.dof());
00423
00424 for(Int i=0; i<test.qs.size(); i++) {
00425 const Vector& q( test.qs[i] );
00426
00427 osg::Geode* platfGeode = new osg::Geode();
00428 osg::Geode* manipGeode = new osg::Geode();
00429
00430 pf_prevq = pf_q;
00431 pf_q = vectorRange(q, Range(0, platfChain.dof()) );
00432 if(i==0) pf_prevq = pf_q;
00433
00434 Real steerAngle = platfDescr->requiredSteeringAngle(pf_prevq, pf_q);
00435
00436 platfGeode->addDrawable( newGeometryFromLines(platformAsLines(platfDescr,platfChain,pf_q,steerAngle ),
00437 Color4(0.4,0.4,0.4)) );
00438
00439 manipGeode->addDrawable( newGeometryFromLines(manipToolAsLines(chain,q,numPlatfLinks),Color4(0.3,0.3,0.3)) );
00440
00441 stepCount++;
00442
00443 testPlatfSwitch->addChild(platfGeode);
00444 testManipSwitch->addChild(manipGeode);
00445 if (test.displayRangeSpecified) {
00446 testPlatfSwitch->setValue(i, ((i >= test.displayStartIndex) && (i < test.displayEndIndex) && ((stepCount%displayStepMod) == 0) && displayPlatform ) );
00447 testManipSwitch->setValue(i, ((i >= test.displayStartIndex) && (i < test.displayEndIndex) && ((stepCount%displayStepMod) == 0) ) );
00448 }
00449 else {
00450 testPlatfSwitch->setValue(i, ((stepCount%displayStepMod) == 0) && displayPlatform );
00451 testManipSwitch->setValue(i, (stepCount%displayStepMod) == 0);
00452 }
00453 }
00454
00455 testPlatfSwitches.push_back( testPlatfSwitch );
00456 testManipSwitches.push_back( testManipSwitch );
00457 testsGroup->addChild( testPlatfSwitch );
00458 testsGroup->addChild( testManipSwitch );
00459 }
00460
00461 return testsGroup;
00462 }
00463
00464
00465 osg::Node* VisualIKORTest::osgCreateTrajectory() const
00466 {
00467 osg::Geode* geode = new osg::Geode();
00468
00469 for(Int t=0; t<tests.size(); t++) {
00470 const Test& test(tests[t]);
00471 geode->addDrawable( newGeometryFromLines(trajectoryAsLines(test.xs),Color4(0.9,0.3,0.3)) );
00472 }
00473 return geode;
00474 }
00475
00476
00477 void VisualIKORTest::updateVisuals() const
00478 {
00479 if ((node == 0) || (testPlatfSwitches.size()==0)) return;
00480
00481 node->setValue(0, displayObstacles);
00482 node->setValue(1, displayAxes);
00483 node->setValue(2, displayEEPath);
00484
00485 Int stepCount=0;
00486 for(Int t=0; t<tests.size(); t++) {
00487 const Test& test(tests[t]);
00488
00489 osg::Switch* testPlatfSwitch = &(*testPlatfSwitches[t]);
00490 osg::Switch* testManipSwitch = &(*testManipSwitches[t]);
00491 for(Int i=0; i<test.times.size(); i++) {
00492 testPlatfSwitch->setValue(i, ((i >= test.displayStartIndex) && (i < test.displayEndIndex) && ((stepCount%displayStepMod)==0) && displayPlatform ));
00493 testManipSwitch->setValue(i, ((i >= test.displayStartIndex) && (i < test.displayEndIndex) && ((stepCount%displayStepMod)==0) ));
00494 stepCount++;
00495 }
00496
00497 }
00498
00499 }
00500
00501
00502
00503 void VisualIKORTest::svgLine(base::Externalizer& e, base::dom::DOMElement* svgElem, const gfx::Segment3& line) const
00504 {
00505 Point3 start(line.s);
00506 Point3 end(line.e);
00507 start = svgTransform*start;
00508 end = svgTransform*end;
00509
00510 DOMElement* lineElem = e.createElement("line");
00511 e.setElementAttribute(lineElem, "x1", base::realToString(start.x));
00512 e.setElementAttribute(lineElem, "y1", base::realToString(start.y));
00513 e.setElementAttribute(lineElem, "x2", base::realToString(end.x));
00514 e.setElementAttribute(lineElem, "y2", base::realToString(end.y));
00515
00516 e.appendNode(svgElem, lineElem);
00517
00518 }
00519
00520
00521 void VisualIKORTest::svgLines(base::Externalizer& e, base::dom::DOMElement* svgElem, const LineSegArray& lines) const
00522 {
00523 for(Int l=0; l<lines.size(); l++)
00524 svgLine(e, svgElem, lines[l]);
00525 }
00526
00527
00528 void VisualIKORTest::svgText(base::Externalizer& e, base::dom::DOMElement* svgElem, const Point3& pos, const String& text, Real size) const
00529 {
00530 DOMElement* textElem = e.createElement("text");
00531 e.setElementAttribute(textElem, "x", base::realToString(pos.x));
00532 e.setElementAttribute(textElem, "y", base::realToString(pos.y));
00533 e.setElementAttribute(textElem, "style", "font-size:"+base::realToString(size)
00534 +"; font-family:Arial, sans-serif");
00535 e.appendText(textElem, text);
00536 e.appendNode(svgElem, textElem);
00537 }
00538
00539
00540
00541 void VisualIKORTest::svgOutputAxes(base::Externalizer& e, base::dom::DOMElement* svgElem) const
00542 {
00543 const Real l = 1.0;
00544
00545 LineSegArray axes;
00546 axes.push_back(Vector3(l,0,0));
00547 axes.push_back(Vector3(0,l,0));
00548 axes.push_back(Vector3(0,0,l));
00549
00550 svgLines(e, svgElem, axes);
00551
00552 svgText(e, svgElem, Point3(1,0,0), "X");
00553 svgText(e, svgElem, Point3(0,1,0), "Y");
00554 svgText(e, svgElem, Point3(0,0,1), "Z");
00555 }
00556
00557
00558
00559
00560 void VisualIKORTest::externalize(base::Externalizer& e, String format, Real version)
00561 {
00562 if (format == "") format = "xml";
00563
00564 if (!formatSupported(format,version,e.ioType()))
00565 throw std::invalid_argument(Exception(String("format ")+format+" v"+base::realToString(version)+" unsupported"));
00566
00567 if (format == "xml")
00568 IKORTest::externalize(e,format,version);
00569 else if (format == "svg") {
00570
00571 if (e.isInput()) {
00572 Unimplemented;
00573 }
00574 else {
00575
00576 svgTransform.setIdentity();
00577
00578
00579 e.setDocumentType("svg","-//W3C//DTD SVG 20010904//EN",
00580 "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd");
00581
00582
00583 DOMElement* svgElem = e.createElement("svg");
00584
00585 e.setElementAttribute(svgElem, "xmlns", "http://www.w3.org/2000/svg");
00586 e.setElementAttribute(svgElem, "width", "100%");
00587 e.setElementAttribute(svgElem, "height", "100%");
00588
00589
00590 svgOutputAxes(e, svgElem);
00591
00592
00593 e.appendElement(svgElem);
00594 e.appendBreak(svgElem);
00595
00596
00597 }
00598
00599 }
00600
00601 }