Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

base/Path.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002   Copyright (C)2002 David Jung <opensim@pobox.com>
00003 
00004   This program/file is free software; you can redistribute it and/or modify
00005   it under the terms of the GNU General Public License as published by
00006   the Free Software Foundation; either version 2 of the License, or
00007   (at your option) any later version.
00008   
00009   This program is distributed in the hope that it will be useful,
00010   but WITHOUT ANY WARRANTY; without even the implied warranty of
00011   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012   GNU General Public License for more details. (http://www.gnu.org)
00013   
00014   You should have received a copy of the GNU General Public License
00015   along with this program; if not, write to the Free Software
00016   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017   
00018   $Id: Path.cpp 1029 2004-02-11 20:45:54Z jungd $
00019   $Revision: 1.8 $
00020   $Date: 2004-02-11 15:45:54 -0500 (Wed, 11 Feb 2004) $
00021   $Author: jungd $
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 // concrete representations
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   // default path (degenerate path - create as line segment with both ends the same)
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   // convert points to arrays of Point3 & Orients
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) { // assuming EulerRPY
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) { // assuming quat
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   // start with first distinguished value
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; // current distinguished value index
00210   while (i < numDistinguishedValues()) {
00211 
00212     // get next distinguished value
00213     s = distinguishedValue(i);
00214     pos = position(s);
00215     orient = orientation(s);
00216     
00217     // calc dx = this pos - last pos
00218     Vector3 dx = pos - lastpos;
00219     if (dx.length() > dxmax) { // dist was too big, set current pos to a distance of maxdx from last pos
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   // register instantiators for all the PathRep classes for dynamic instantiation upon deserialization
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; // empty line or eof indicates end of list
00278         while (line[0] == '#') line = e.readLine(); // skip comment lines
00279         
00280         // count separating spaces to determine if there are 6 or 7
00281         // numbers present
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--; // don't count leading space(s)
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 { // output
00310       std::ostringstream out;
00311       
00312       // comment header
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 // this is a hack, as under gcc the flags don't appear to stay set after an output op (!?)
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) { // rpy
00393           v[3] = vo[0]; v[4] = vo[1]; v[5] = vo[2];
00394         }
00395         else { // quat
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 { // input
00408       DOMNode* context = e.context();
00409       
00410       DOMElement* pathElem = e.getFirstElement(context, "path");
00411 
00412       // handle link
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 { // parametric
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 { // hasorient
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         } // else parametric
00558 
00559       }
00560 
00561       e.removeElement(pathElem);
00562 
00563     }
00564 
00565   } // format xml
00566 
00567 
00568 }
00569 

Generated on Thu Jul 29 15:56:09 2004 for OpenSim by doxygen 1.3.6