Main Page | Namespace List | Class List | File List | Namespace Members | Class Members

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 Thu Jul 29 07:09:56 2004 for WFMath by doxygen 1.3.7