stream.h

00001 // stream.h (Functions in the WFMath library that use streams)
00002 //
00003 //  The WorldForge Project
00004 //  Copyright (C) 2001,2002  The WorldForge Project
00005 //
00006 //  This program is free software; you can redistribute it and/or modify
00007 //  it under the terms of the GNU General Public License as published by
00008 //  the Free Software Foundation; either version 2 of the License, or
00009 //  (at your option) any later version.
00010 //
00011 //  This program is distributed in the hope that it will be useful,
00012 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 //  GNU General Public License for more details.
00015 //
00016 //  You should have received a copy of the GNU General Public License
00017 //  along with this program; if not, write to the Free Software
00018 //  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00019 //
00020 //  For information about WorldForge and its authors, please contact
00021 //  the Worldforge Web Site at http://www.worldforge.org.
00022 
00023 // Author: Ron Steinke
00024 // Created: 2001-12-7
00025 
00026 #ifndef WFMATH_STREAM_H
00027 #define WFMATH_STREAM_H
00028 
00029 #include <wfmath/vector.h>
00030 #include <wfmath/rotmatrix.h>
00031 #include <wfmath/quaternion.h>
00032 #include <wfmath/point.h>
00033 #include <wfmath/axisbox.h>
00034 #include <wfmath/ball.h>
00035 #include <wfmath/segment.h>
00036 #include <wfmath/rotbox.h>
00037 #include <wfmath/polygon.h>
00038 #include <wfmath/error.h>
00039 #include <string>
00040 #include <iostream>
00041 #include <list> // For Polygon<>::operator>>()
00042 
00043 namespace WFMath {
00044 
00045 // sstream vs. strstream compatibility wrapper
00046 
00047 namespace _IOWrapper {
00048 
00049   // Need separate read/write classes, since one is const C& and the other is C&
00050 
00051   class BaseRead {
00052    public:
00053     virtual ~BaseRead() {}
00054 
00055     virtual void read(std::istream& is) = 0;
00056   };
00057 
00058   class BaseWrite {
00059    public:
00060     virtual ~BaseWrite() {}
00061 
00062     virtual void write(std::ostream& os) const = 0;
00063   };
00064 
00065   template<class C>
00066   class ImplRead : public BaseRead {
00067    public:
00068     ImplRead(C& c) : m_data(c) {}
00069     virtual ~ImplRead() {}
00070 
00071     virtual void read(std::istream& is) {is >> m_data;}
00072 
00073    private:
00074     C &m_data;
00075   };
00076 
00077   template<class C>
00078   class ImplWrite : public BaseWrite {
00079    public:
00080     ImplWrite(const C& c) : m_data(c) {}
00081     virtual ~ImplWrite() {}
00082 
00083     virtual void write(std::ostream& os) const {os << m_data;}
00084 
00085    private:
00086     const C &m_data;
00087   };
00088 
00089   std::string ToStringImpl(const BaseWrite& b, int precision);
00090   void FromStringImpl(BaseRead& b, const std::string& s, int precision);
00091 }
00092 
00094 
00097 template<class C>
00098 inline std::string ToString(const C& c, unsigned int precision = 6)
00099 {
00100   return _IOWrapper::ToStringImpl(_IOWrapper::ImplWrite<C>(c), 6);
00101 }
00102 
00104 
00107 template<class C>
00108 inline void FromString(C& c, const std::string& s, unsigned int precision = 6)
00109 {
00110   _IOWrapper::ImplRead<C> i(c);
00111   _IOWrapper::FromStringImpl(i, s, 6);
00112 }
00113 
00114 void _ReadCoordList(std::istream& is, CoordType* d, const int num);
00115 void _WriteCoordList(std::ostream& os, const CoordType* d, const int num);
00116 CoordType _GetEpsilon(std::istream& is);
00117 
00118 template<const int dim>
00119 inline std::ostream& operator<<(std::ostream& os, const Vector<dim>& v)
00120 {
00121   _WriteCoordList(os, v.m_elem, dim);
00122   return os;
00123 }
00124 
00125 template<const int dim>
00126 inline std::istream& operator>>(std::istream& is, Vector<dim>& v)
00127 {
00128   _ReadCoordList(is, v.m_elem, dim);
00129   v.m_valid = true;
00130   return is;
00131 }
00132 
00133 template<const int dim>
00134 inline std::ostream& operator<<(std::ostream& os, const RotMatrix<dim>& m)
00135 {
00136   os << '(';
00137 
00138   for(int i = 0; i < dim; ++i) {
00139     _WriteCoordList(os, m.m_elem[i], dim);
00140     os << (i < (dim - 1) ? ',' : ')');
00141   }
00142 
00143   return os;
00144 }
00145 
00146 template<const int dim>
00147 inline std::istream& operator>>(std::istream& is, RotMatrix<dim>& m)
00148 {
00149   CoordType d[dim*dim];
00150   char next;
00151 
00152   is >> next;
00153   if(next != '(')
00154     throw ParseError();
00155 
00156   for(int i = 0; i < dim; ++i) {
00157     _ReadCoordList(is, d + i * dim, dim);
00158     is >> next;
00159     char want = (i == dim - 1) ? ')' : ',';
00160     if(next != want)
00161       throw ParseError();
00162   }
00163 
00164   if(!m._setVals(d, FloatMax(WFMATH_EPSILON, _GetEpsilon(is))))
00165     throw ParseError();
00166 
00167   return is;
00168 }
00169 
00170 template<const int dim>
00171 inline std::ostream& operator<<(std::ostream& os, const Point<dim>& p)
00172 {
00173   _WriteCoordList(os, p.m_elem, dim);
00174   return os;
00175 }
00176 
00177 template<const int dim>
00178 inline std::istream& operator>>(std::istream& is, Point<dim>& p)
00179 {
00180   _ReadCoordList(is, p.m_elem, dim);
00181   p.m_valid = true;
00182   return is;
00183 }
00184 
00185 template<const int dim>
00186 inline std::ostream& operator<<(std::ostream& os, const AxisBox<dim>& a)
00187 {
00188   return os << "AxisBox: m_low = " << a.m_low << ", m_high = " << a.m_high;
00189 }
00190 
00191 template<const int dim>
00192 inline std::istream& operator>>(std::istream& is, AxisBox<dim>& a)
00193 {
00194   char next;
00195 
00196   do {
00197     is >> next;
00198   } while(next != '=');
00199 
00200   is >> a.m_low;
00201 
00202   do {
00203     is >> next;
00204   } while(next != '=');
00205 
00206   is >> a.m_high;
00207 
00208   return is;
00209 }
00210 
00211 template<const int dim>
00212 inline std::ostream& operator<<(std::ostream& os, const Ball<dim>& b)
00213 {
00214   return os << "Ball: m_center = " << b.m_center <<
00215           + ", m_radius = " << b.m_radius;
00216 }
00217 
00218 template<const int dim>
00219 inline std::istream& operator>>(std::istream& is, Ball<dim>& b)
00220 {
00221   char next;
00222 
00223   do {
00224     is >> next;
00225   } while(next != '=');
00226 
00227   is >> b.m_center;
00228 
00229   do {
00230     is >> next;
00231   } while(next != '=');
00232 
00233   is >> b.m_radius;
00234 
00235   return is;
00236 }
00237 
00238 template<const int dim>
00239 inline std::ostream& operator<<(std::ostream& os, const Segment<dim>& s)
00240 {
00241   return os << "Segment: m_p1 = " << s.m_p1 << ", m_p2 = " << s.m_p2;
00242 }
00243 
00244 template<const int dim>
00245 inline std::istream& operator>>(std::istream& is, Segment<dim>& s)
00246 {
00247   char next;
00248 
00249   do {
00250     is >> next;
00251   } while(next != '=');
00252 
00253   is >> s.m_p1;
00254 
00255   do {
00256     is >> next;
00257   } while(next != '=');
00258 
00259   is >> s.m_p2;
00260 
00261   return is;
00262 }
00263 
00264 template<const int dim>
00265 inline std::ostream& operator<<(std::ostream& os, const RotBox<dim>& r)
00266 {
00267   return os << "RotBox: m_corner0 = " << r.m_corner0
00268          << ", m_size = " << r.m_size
00269          << ", m_orient = " << r.m_orient;
00270 }
00271 
00272 template<const int dim>
00273 inline std::istream& operator>>(std::istream& is, RotBox<dim>& r)
00274 {
00275   char next;
00276 
00277   do {
00278     is >> next;
00279   } while(next != '=');
00280 
00281   is >> r.m_corner0;
00282 
00283   do {
00284     is >> next;
00285   } while(next != '=');
00286 
00287   is >> r.m_size;
00288 
00289   do {
00290     is >> next;
00291   } while(next != '=');
00292 
00293   is >> r.m_orient;
00294 
00295   return is;
00296 }
00297 
00298 template<> std::ostream& operator<<(std::ostream& os, const Polygon<2>& r);
00299 template<> std::istream& operator>>(std::istream& is, Polygon<2>& r);
00300 
00301 template<const int dim>
00302 inline std::ostream& operator<<(std::ostream& os, const Polygon<dim>& r)
00303 {
00304   int size = r.m_poly.numCorners();
00305 
00306   if(size == 0) {
00307     os << "<empty>";
00308     return os;
00309   }
00310 
00311   os << "Polygon: (";
00312 
00313   for(int i = 0; i < size; ++i)
00314     os << r.getCorner(i) << (i < (dim - 1) ? ',' : ')');
00315 
00316   return os;
00317 }
00318 
00319 // Can't stick this in operator>>(std::istream&, Polygon<>&), because
00320 // we use it as a template argument for list<>. Why isn't that allowed?
00321 template<const int dim> struct _PolyReader
00322 {
00323   Point<dim> pd;
00324   Point<2> p2;
00325 };
00326 
00327 template<const int dim>
00328 std::istream& operator>>(std::istream& is, Polygon<dim>& r)
00329 {
00330   char next;
00331   _PolyReader<dim> read;
00332   std::list<_PolyReader<dim> > read_list;
00333 
00334   // Read in the points
00335 
00336   do {
00337     is >> next;
00338     if(next == '<') { // empty polygon
00339        do {
00340          is >> next;
00341        } while(next != '>');
00342        return is;
00343     }
00344   } while(next != '(');
00345 
00346   while(true) {
00347     is >> read.pd;
00348     read_list.push_back(read);
00349     is >> next;
00350     if(next == ')')
00351       break;
00352     if(next != ',')
00353       throw ParseError();
00354   }
00355 
00356   // Convert to internal format. Be careful about the order points are
00357   // added to the orientation. If the first few points are too close together,
00358   // round off error can skew the plane, and later points that are further
00359   // away may fail.
00360 
00361   typename std::list<_PolyReader<dim> >::iterator i, end = read_list.end();
00362   bool succ;
00363 
00364   int str_prec = is.precision();
00365   double str_eps = 1;
00366   while(--str_prec > 0) // Precision of 6 gives epsilon = 1e-5
00367     str_eps /= 10;
00368   double epsilon = FloatMax(str_eps, WFMATH_EPSILON);
00369 
00370   r.m_orient = _Poly2Orient<dim>();
00371 
00372   if(read_list.size() < 3) { // This will always work
00373     for(i = read_list.begin(); i != end; ++i) {
00374       succ = r.m_orient.expand(i->pd, i->p2, epsilon);
00375       assert(succ);
00376     }
00377   }
00378   else { // Find the three furthest apart points
00379     typename std::list<_PolyReader<dim> >::iterator p1 = end, p2 = end, p3 = end, j; // invalid values
00380     CoordType dist = -1;
00381 
00382     for(i = read_list.begin(); i != end; ++i) {
00383       for(j = i, ++j; j != end; ++j) {
00384         CoordType new_dist = SloppyDistance(i->pd, j->pd);
00385         if(new_dist > dist) {
00386           p1 = i;
00387           p2 = j;
00388           dist = new_dist;
00389         }
00390       }
00391     }
00392 
00393     assert(p1 != end);
00394     assert(p2 != end);
00395 
00396     dist = -1;
00397 
00398     for(i = read_list.begin(); i != end; ++i) {
00399       // Don't want to be near either p1 or p2
00400       if(i == p1 || i == p2)
00401         continue;
00402       CoordType new_dist = FloatMin(SloppyDistance(i->pd, p1->pd),
00403                                     SloppyDistance(i->pd, p2->pd));
00404       if(new_dist > dist) {
00405         p3 = i;
00406         dist = new_dist;
00407       }
00408     }
00409 
00410     assert(p3 != end);
00411 
00412     // Add p1, p2, p3 first
00413 
00414     succ = r.m_orient.expand(p1->pd, p1->p2, epsilon);
00415     assert(succ);
00416     succ = r.m_orient.expand(p2->pd, p2->p2, epsilon);
00417     assert(succ);
00418     succ = r.m_orient.expand(p3->pd, p3->p2, epsilon);
00419     assert(succ);
00420 
00421     // Try to add the rest
00422 
00423     for(i = read_list.begin(); i != end; ++i) {
00424       if(i == p1 || i == p2 || i == p3) // Did these already
00425         continue;
00426       succ = r.m_orient.expand(i->pd, i->p2, epsilon);
00427       if(!succ) {
00428         r.clear();
00429         throw ParseError();
00430       }
00431     }
00432   }
00433 
00434   // Got valid points, add them to m_poly
00435 
00436   r.m_poly.resize(read_list.size());
00437 
00438   int pnum;
00439   for(i = read_list.begin(), pnum = 0; i != end; ++i, ++pnum)
00440     r.m_poly[pnum] = i->p2;
00441 
00442   return is;
00443 }
00444 
00445 } // namespace WFMath
00446 
00447 #endif // WFMATH_STREAM_H

Generated on Sun Aug 27 21:30:58 2006 for WFMath by  doxygen 1.4.7