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 <base/Path>
00026
00027 #include <sstream>
00028
00029 #include <base/PathRep>
00030 #include <base/Externalizer>
00031 #include <base/externalization_error>
00032 #include <base/Application>
00033 #include <base/VFile>
00034
00035
00036 #include <base/LineSegPathRep>
00037 #include <base/WaypointPathRep>
00038 #include <base/ParametricPathRep>
00039
00040
00041 using base::Path;
00042
00043 using base::LineSegPathRep;
00044 using base::WaypointPathRep;
00045 using base::ParametricPathRep;
00046
00047 using base::externalization_error;
00048 using base::Application;
00049 using base::VFile;
00050 using base::PathName;
00051
00052 using base::dom::DOMNode;
00053 using base::dom::DOMElement;
00054
00055
00056
00057
00058 Path::Path()
00059 {
00060 create();
00061 }
00062
00063
00064 Path::Path(const Path& p)
00065 {
00066 create(p);
00067 }
00068
00069
00070 Path::Path(const Point3& sp, const Orient& so, const Point3& ep, const Orient& eo)
00071 {
00072 create(sp,so,ep,eo);
00073 }
00074
00075
00076 Path::Path(const array<Point3>& points, const array<Orient>& orients, bool deltas)
00077 {
00078 create(points,orients,deltas);
00079 }
00080
00081
00082 Path::Path(const array<Vector>& points, bool deltas)
00083 {
00084 create(points,deltas);
00085 }
00086
00087
00088 Path::Path(const ExpressionVector& p)
00089 {
00090 create(p);
00091 }
00092
00093
00094
00095 void Path::create()
00096 {
00097
00098 rep = ref<PathRep>(NewObj LineSegPathRep(Point3(),Orient(),Point3(),Orient()));
00099 }
00100
00101 void Path::create(const Path& p)
00102 {
00103 rep = ref<PathRep>( &base::clone( *p.rep ) );
00104 }
00105
00106 void Path::create(const Point3& sp, const Orient& so, const Point3& ep, const Orient& eo)
00107 {
00108 rep = ref<PathRep>(NewObj LineSegPathRep(sp,so,ep,eo));
00109 }
00110
00111 void Path::create(const array<Point3>& points, const array<Orient>& orients, bool deltas)
00112 {
00113 init(points, orients, deltas);
00114 }
00115
00116 void Path::create(const array<Vector>& points, bool deltas)
00117 {
00118
00119 Assert(points.size() > 0);
00120 Assert(points[0].size() >= 3);
00121
00122 array<Point3> pos(points.size());
00123 for(Int i=0; i<points.size(); i++) {
00124 const Vector& v(points[i]);
00125 pos[i] = Point3(v[0],v[1],v[2]);
00126 }
00127
00128 array<Orient> orient(points.size());
00129 if (points[0].size() == 6) {
00130 for(Int i=0; i<points.size(); i++) {
00131 const Vector& v(points[i]);
00132 orient[i] = Orient(v[3],v[4],v[5]);
00133 }
00134 }
00135 else
00136 if (points[0].size() == 7) {
00137 for(Int i=0; i<points.size(); i++) {
00138 const Vector& v(points[i]);
00139 orient[i] = Orient(Quat4(v[3],v[4],v[5],v[6]));
00140 }
00141 }
00142
00143 init(pos,orient,deltas);
00144 }
00145
00146
00147 void Path::create(const ExpressionVector& p)
00148 {
00149 rep = ref<PathRep>(NewObj ParametricPathRep(p));
00150 }
00151
00152
00153 void Path::init(const array<Point3>& points, const array<Orient>& orients, bool deltas)
00154 {
00155 if (!deltas)
00156 rep = ref<PathRep>(NewObj WaypointPathRep(points, orients));
00157 else {
00158 array<Point3> apoints(points.size()+1);
00159 apoints[0] = Point3(0,0,0);
00160 for(Int i=0; i<points.size(); i++)
00161 apoints[i+1] = apoints[i]+points[i];
00162
00163 array<Orient> aorients(orients.size()+1);
00164 aorients[0] = Orient();
00165 for(Int i=0; i<orients.size(); i++) {
00166 Quat4 q1(aorients[i].getQuat4());
00167 Quat4 q2(orients[i].getQuat4());
00168 aorients[i+1] = Orient(q2*q1);
00169 }
00170
00171 rep = ref<PathRep>(NewObj WaypointPathRep(apoints, aorients));
00172 }
00173 }
00174
00175
00176
00177 void Path::resample(Int samples)
00178 {
00179 array<Point3> points(samples);
00180 array<Orient> orients(samples);
00181
00182 for(Int i=0; i<samples; i++) {
00183 Real s = Real(i)/Real(samples-1);
00184 points[i] = Path::position(s);
00185 orients[i] = Path::orientation(s);
00186 }
00187
00188 init(points, orients, false);
00189
00190 }
00191
00192
00193 void Path::resample(const Real dxmax)
00194 {
00195 Assert(dxmax > 0);
00196
00197 array<Point3> points;
00198 array<Orient> orients;
00199
00200
00201 Real s = distinguishedValue(0);
00202 Point3 pos( position(s) );
00203 Orient orient( orientation(s) );
00204 points.push_back( pos );
00205 orients.push_back( orient );
00206
00207 Real lasts(s);
00208 Point3 lastpos( pos );
00209 Int i = 1;
00210 while (i < numDistinguishedValues()) {
00211
00212
00213 s = distinguishedValue(i);
00214 pos = position(s);
00215 orient = orientation(s);
00216
00217
00218 Vector3 dx = pos - lastpos;
00219 if (dx.length() > dxmax) {
00220 Real scale = dxmax/dx.length();
00221 s = lasts + scale*(s-lasts);
00222 pos = position(s);
00223 orient = orientation(s);
00224 }
00225 else
00226 ++i;
00227
00228 points.push_back( pos );
00229 orients.push_back( orient );
00230
00231 lasts = s;
00232 lastpos = pos;
00233 }
00234
00235 init(points, orients, false);
00236
00237 }
00238
00239
00240
00241
00242
00243
00244 void Path::serialize(Serializer& s)
00245 {
00246
00247 Serializable::registerSerializableInstantiator<PathRep,LineSegPathRep>(lineSegPathRepInstantiator);
00248 Serializable::registerSerializableInstantiator<PathRep,WaypointPathRep>(waypointPathRepInstantiator);
00249 s.baseRef(rep,"PathRep");
00250 }
00251
00252
00253 bool Path::formatSupported(String format, Real version, ExternalizationType type) const
00254 {
00255 return ((format=="txt") && (version==1.0))
00256 || ((format=="xml") && (version==1.0));
00257 }
00258
00259
00260 void Path::externalize(Externalizer& e, String format, Real version)
00261 {
00262 if (format=="") format = String("xml");
00263
00264 if (!formatSupported(format,version,e.ioType()))
00265 throw std::invalid_argument(Exception(String("format ")+format+" "+base::realToString(version)+" unsupported"));
00266
00267 if (format == "txt") {
00268
00269 if (e.isInput()) {
00270
00271 array<Point3> points;
00272 array<Orient> orients;
00273
00274 while (e.moreInput()) {
00275
00276 String line(e.readLine());
00277 if (line.empty()) break;
00278 while (line[0] == '#') line = e.readLine();
00279
00280
00281
00282 Int spaces=0;
00283 for(Int i=0; i<line.size(); i++)
00284 if (line[i]==' ') {
00285 spaces++;
00286 while ( (i<line.size()-1) && (line[i]==' ')) i++;
00287 }
00288 if (line[0]==' ') spaces--;
00289
00290 Assert(spaces >= 5);
00291 bool quat = (spaces>5);
00292 std::istringstream iss(line);
00293 iss.setf(std::ios_base::skipws | std::ios_base::dec);
00294
00295 Point3 p;
00296 iss >> p.x >> p.y >> p.z;
00297 Vector v(quat?4:3);
00298 iss >> v[0] >> v[1] >> v[2];
00299 if (quat) iss >> v[3];
00300
00301 points.push_back(p);
00302
00303 orients.push_back(Orient(v, quat? Orient::Quat : Orient::EulerRPY));
00304 }
00305
00306 init(points,orients,false);
00307
00308 }
00309 else {
00310 std::ostringstream out;
00311
00312
00313 out << "# waypoint path (positions & orientations)" << std::endl;
00314 out << "# x y z ";
00315 if (orientation(distinguishedValue(0)).representation() == Orient::EulerRPY)
00316 out << " R P Y" << std::endl;
00317 else
00318 out << " qx qy qz qw" << std::endl;
00319
00320 std::ostream::fmtflags savedFlags = out.setf(std::ios_base::dec | std::ios_base::right);
00321 Int savedPrec = out.precision(10);
00322 Int savedWidth = out.width(13);
00323
00324 for(Int i=0; i<numDistinguishedValues(); i++) {
00325 Point3 p(position(distinguishedValue(i)));
00326 Orient o(orientation(distinguishedValue(i)));
00327
00328
00329 #define setflags \
00330 out.setf(std::ios_base::dec | std::ios_base::right); \
00331 out.precision(10); \
00332 out.width(13);
00333
00334 out << p.x << " "; setflags;
00335 out << p.y << " "; setflags;
00336 out << p.z << " "; setflags;
00337 if ( (o.representation() != Orient::Quat) && (o.representation() != Orient::EulerRPY) )
00338 o.changeRepresentation(Orient::Quat);
00339
00340 Vector v(o);
00341 out << v[0] << " "; setflags;
00342 out << v[1] << " "; setflags;
00343 out << v[2]; setflags;
00344 if (v.size() > 3 ) out << " " << v[3];
00345 out << std::endl;
00346
00347 }
00348
00349 out.setf(savedFlags);
00350 out.precision(savedPrec);
00351 out.width(savedWidth);
00352
00353 e.writeString(out.str());
00354 }
00355
00356 } else if (format == "xml") {
00357
00358 if (e.isOutput()) {
00359
00360 DOMElement* pathElem = e.createElement("path");
00361
00362 bool parametric = instanceof(*rep, ParametricPathRep);
00363
00364 if (parametric) { Unimplemented; }
00365
00366 Orient::Representation rep = orientation(distinguishedValue(0)).representation();
00367 if ((rep != Orient::Quat) && (rep != Orient::EulerRPY) )
00368 rep = Orient::Quat;
00369
00370 if (rep==Orient::Quat) {
00371 e.setElementAttribute(pathElem,"representation", "x y z qx qy qz qw" );
00372 e.appendComment(pathElem, "position (x,y,z) orientation quaternion (qx,qy,qz,qw) [w is scalar component]");
00373 } else {
00374 e.setElementAttribute(pathElem,"representation", "x y z r p y" );
00375 e.appendComment(pathElem,"position (x,y,z) orientation Euler angles (roll, pitch yaw)");
00376 }
00377
00378 e.setElementAttribute(pathElem,"pointtype", "absolute");
00379 if (frame!="")
00380 e.setElementAttribute(pathElem,"frame", frame);
00381
00382 if (units!="")
00383 e.setElementAttribute(pathElem,"units", units);
00384
00385 for(Int i=0; i<numDistinguishedValues(); i++) {
00386 Point3 p(position(distinguishedValue(i)));
00387 Orient o(orientation(distinguishedValue(i)));
00388
00389 Vector vo(o);
00390 Vector v(3+vo.size());
00391 v[0] = p.x; v[1] = p.y; v[2] = p.z;
00392 if (vo.size() == 3) {
00393 v[3] = vo[0]; v[4] = vo[1]; v[5] = vo[2];
00394 }
00395 else {
00396 v[3] = vo[0]; v[4] = vo[1]; v[5] = vo[2]; v[6] = vo[3];
00397 }
00398
00399 e.appendText( pathElem, e.toString(v) );
00400 e.appendBreak( pathElem );
00401
00402 }
00403
00404 e.appendElement(pathElem);
00405
00406 }
00407 else {
00408 DOMNode* context = e.context();
00409
00410 DOMElement* pathElem = e.getFirstElement(context, "path");
00411
00412
00413 String link = e.getElementAttribute(pathElem,"link",false);
00414 if (link != "") {
00415
00416 ref<VFile> linkFile = Application::getInstance()->universe()->cache()->findFile(link,e.getArchivePath());
00417 load(linkFile,format,version);
00418 }
00419 else {
00420
00421 String repText = e.getElementAttribute(pathElem, "representation");
00422
00423 bool absolute = ( e.getDefaultedElementAttribute(pathElem, "pointtype", "absolute") == "absolute" );
00424 frame = e.getDefaultedElementAttribute(pathElem, "frame", "");
00425 units = e.getDefaultedElementAttribute(pathElem, "units", "");
00426
00427 Orient::Representation rep;
00428 bool hasorient = true;
00429 bool parametric = false;
00430 bool scalarFirst = false;
00431
00432 if (repText == "x y z") {
00433 hasorient = false;
00434 }
00435 else if (repText == "x y z qx qy qz qw") {
00436 rep = Orient::Quat;
00437 }
00438 else if (repText == "x y z qw qx qy qz") {
00439 rep = Orient::Quat;
00440 scalarFirst=true;
00441 }
00442 else if (repText == "x y z r p y") {
00443 rep = Orient::EulerRPY;
00444 }
00445 else if (repText == "x(s) y(s) z(s)") {
00446 hasorient = false;
00447 parametric = true;
00448 }
00449 else if (repText == "x(s) y(s) z(s) qx(s) qy(s) qz(s) qw(s)") {
00450 parametric = true;
00451 rep = Orient::Quat;
00452 }
00453 else if (repText == "x(s) y(s) z(s) qw(s) qx(s) qy(s) qz(s)") {
00454 parametric = true;
00455 rep = Orient::Quat;
00456 scalarFirst=true;
00457 }
00458 else if (repText == "x(s) y(s) z(s) r(s) p(s) y(s)") {
00459 parametric = true;
00460 rep = Orient::EulerRPY;
00461 }
00462 else
00463 throw externalization_error(Exception("unknown or unsupported path representation"));
00464
00465 String pathText = e.getContainedText(pathElem,true);
00466 array<String> pathLines = e.splitIntoLines(pathText);
00467
00468 if (!parametric) {
00469 array<Point3> points;
00470 array<Orient> orients;
00471
00472
00473 if (pathLines.size() < 2)
00474 throw externalization_error(Exception("path must contain at least two points"));
00475
00476 for(Int i=0; i<pathLines.size(); i++) {
00477 array<String> elts = e.splitAtDelimiter(pathLines[i], ' ');
00478 if ( (hasorient && (rep==Orient::Quat) && (elts.size() != 7))
00479 || (hasorient && (rep==Orient::EulerRPY) && (elts.size() != 6))
00480 || (!hasorient && (elts.size() != 3)) )
00481 throw externalization_error(Exception("path point with wrong number of elements encountered"));
00482 Vector v( e.stringsToReals(elts) );
00483 points.push_back( Point3(v[0],v[1],v[2]) );
00484 if (hasorient) {
00485 if (rep==Orient::Quat) {
00486 if (!scalarFirst)
00487 orients.push_back( Orient(Quat4(v[3],v[4],v[5],v[6])) );
00488 else
00489 orients.push_back( Orient(Quat4(v[6],v[3],v[4],v[5])) );
00490 }
00491 else if (rep==Orient::EulerRPY) {
00492 orients.push_back( Orient(v[3],v[4],v[5]) );
00493 }
00494 }
00495 else
00496 orients.push_back( Orient() );
00497
00498 }
00499
00500 init(points,orients,!absolute);
00501 }
00502 else {
00503
00504 if (!absolute)
00505 throw externalization_error(Exception("pointtype of 'relative' doesn't make sense for parametric expression paths"));
00506
00507 ExpressionVector v(3);
00508
00509 try {
00510
00511 if (!hasorient) {
00512 if (pathLines.size() != 3)
00513 throw externalization_error(Exception("path should have one line for each parametric expression x(s), y(s) and z(s)"));
00514 v[0] = Expression(pathLines[0]);
00515 v[1] = Expression(pathLines[1]);
00516 v[2] = Expression(pathLines[2]);
00517 }
00518 else {
00519 if (rep == Orient::Quat) {
00520 if (pathLines.size() != 7)
00521 throw externalization_error(Exception("path should have one line for each parametric expression x(s), y(s), z(s), qx(s), qy(s), qz(s) and qw(s)"));
00522 v.resize(7);
00523 v[0] = Expression(pathLines[0]);
00524 v[1] = Expression(pathLines[1]);
00525 v[2] = Expression(pathLines[2]);
00526 if (!scalarFirst) {
00527 v[3] = Expression(pathLines[3]);
00528 v[4] = Expression(pathLines[4]);
00529 v[5] = Expression(pathLines[5]);
00530 v[6] = Expression(pathLines[6]);
00531 }
00532 else {
00533 v[3] = Expression(pathLines[6]);
00534 v[4] = Expression(pathLines[3]);
00535 v[5] = Expression(pathLines[4]);
00536 v[6] = Expression(pathLines[5]);
00537 }
00538 }
00539 else {
00540 if (pathLines.size() != 6)
00541 throw externalization_error(Exception("path should have one line for each parametric expression x(s), y(s), z(s), R(s), P(s), and Y(s)"));
00542 v.resize(6);
00543 v[0] = Expression(pathLines[0]);
00544 v[1] = Expression(pathLines[1]);
00545 v[2] = Expression(pathLines[2]);
00546 v[3] = Expression(pathLines[3]);
00547 v[4] = Expression(pathLines[4]);
00548 v[5] = Expression(pathLines[5]);
00549 }
00550 }
00551 } catch (std::exception& e) {
00552 throw externalization_error(Exception("error parsing parametric path component expression:"+String(e.what())));
00553 }
00554
00555 this->rep = ref<PathRep>(NewObj ParametricPathRep(v));
00556
00557 }
00558
00559 }
00560
00561 e.removeElement(pathElem);
00562
00563 }
00564
00565 }
00566
00567
00568 }
00569