WFMath  0.3.12
stream.h
1 // stream.h (Functions in the WFMath library that use streams)
2 //
3 // The WorldForge Project
4 // Copyright (C) 2001,2002 The WorldForge Project
5 //
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2 of the License, or
9 // (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 //
20 // For information about WorldForge and its authors, please contact
21 // the Worldforge Web Site at http://www.worldforge.org.
22 
23 // Author: Ron Steinke
24 // Created: 2001-12-7
25 
26 #ifndef WFMATH_STREAM_H
27 #define WFMATH_STREAM_H
28 
29 #include <wfmath/vector.h>
30 #include <wfmath/rotmatrix.h>
31 #include <wfmath/point.h>
32 #include <wfmath/axisbox.h>
33 #include <wfmath/ball.h>
34 #include <wfmath/segment.h>
35 #include <wfmath/rotbox.h>
36 #include <wfmath/polygon.h>
37 #include <wfmath/error.h>
38 #include <string>
39 #include <iostream>
40 #include <list> // For Polygon<>::operator>>()
41 
42 #include <cassert>
43 
44 namespace WFMath {
45 
46 // sstream vs. strstream compatibility wrapper
47 
48 namespace _IOWrapper {
49 
50  // Need separate read/write classes, since one is const C& and the other is C&
51 
52  class BaseRead {
53  public:
54  virtual ~BaseRead() {}
55 
56  virtual void read(std::istream& is) = 0;
57  };
58 
59  class BaseWrite {
60  public:
61  virtual ~BaseWrite() {}
62 
63  virtual void write(std::ostream& os) const = 0;
64  };
65 
66  template<class C>
67  class ImplRead : public BaseRead {
68  public:
69  ImplRead(C& c) : m_data(c) {}
70  virtual ~ImplRead() {}
71 
72  virtual void read(std::istream& is) {is >> m_data;}
73 
74  private:
75  C &m_data;
76  };
77 
78  template<class C>
79  class ImplWrite : public BaseWrite {
80  public:
81  ImplWrite(const C& c) : m_data(c) {}
82  virtual ~ImplWrite() {}
83 
84  virtual void write(std::ostream& os) const {os << m_data;}
85 
86  private:
87  const C &m_data;
88  };
89 
90  std::string ToStringImpl(const BaseWrite& b, int precision);
91  void FromStringImpl(BaseRead& b, const std::string& s, int precision);
92 }
93 
95 
98 template<class C>
99 inline std::string ToString(const C& c, unsigned int precision = 6)
100 {
101  return _IOWrapper::ToStringImpl(_IOWrapper::ImplWrite<C>(c), 6);
102 }
103 
105 
108 template<class C>
109 inline void FromString(C& c, const std::string& s, unsigned int precision = 6)
110 {
111  _IOWrapper::ImplRead<C> i(c);
112  _IOWrapper::FromStringImpl(i, s, 6);
113 }
114 
115 void _ReadCoordList(std::istream& is, CoordType* d, const int num);
116 void _WriteCoordList(std::ostream& os, const CoordType* d, const int num);
117 CoordType _GetEpsilon(std::istream& is);
118 
119 template<int dim>
120 inline std::ostream& operator<<(std::ostream& os, const Vector<dim>& v)
121 {
122  _WriteCoordList(os, v.m_elem, dim);
123  return os;
124 }
125 
126 template<int dim>
127 inline std::istream& operator>>(std::istream& is, Vector<dim>& v)
128 {
129  _ReadCoordList(is, v.m_elem, dim);
130  v.m_valid = true;
131  return is;
132 }
133 
134 template<int dim>
135 inline std::ostream& operator<<(std::ostream& os, const RotMatrix<dim>& m)
136 {
137  os << '(';
138 
139  for(int i = 0; i < dim; ++i) {
140  _WriteCoordList(os, m.m_elem[i], dim);
141  os << (i < (dim - 1) ? ',' : ')');
142  }
143 
144  return os;
145 }
146 
147 template<int dim>
148 inline std::istream& operator>>(std::istream& is, RotMatrix<dim>& m)
149 {
150  CoordType d[dim*dim];
151  char next;
152 
153  is >> next;
154  if(next != '(')
155  throw ParseError();
156 
157  for(int i = 0; i < dim; ++i) {
158  _ReadCoordList(is, d + i * dim, dim);
159  is >> next;
160  char want = (i == dim - 1) ? ')' : ',';
161  if(next != want)
162  throw ParseError();
163  }
164 
165  if(!m._setVals(d, FloatMax(WFMATH_EPSILON, _GetEpsilon(is))))
166  throw ParseError();
167 
168  return is;
169 }
170 
171 template<int dim>
172 inline std::ostream& operator<<(std::ostream& os, const Point<dim>& p)
173 {
174  _WriteCoordList(os, p.m_elem, dim);
175  return os;
176 }
177 
178 template<int dim>
179 inline std::istream& operator>>(std::istream& is, Point<dim>& p)
180 {
181  _ReadCoordList(is, p.m_elem, dim);
182  p.m_valid = true;
183  return is;
184 }
185 
186 template<int dim>
187 inline std::ostream& operator<<(std::ostream& os, const AxisBox<dim>& a)
188 {
189  return os << "AxisBox: m_low = " << a.m_low << ", m_high = " << a.m_high;
190 }
191 
192 template<int dim>
193 inline std::istream& operator>>(std::istream& is, AxisBox<dim>& a)
194 {
195  char next;
196 
197  do {
198  is >> next;
199  } while(next != '=');
200 
201  is >> a.m_low;
202 
203  do {
204  is >> next;
205  } while(next != '=');
206 
207  is >> a.m_high;
208 
209  return is;
210 }
211 
212 template<int dim>
213 inline std::ostream& operator<<(std::ostream& os, const Ball<dim>& b)
214 {
215  return os << "Ball: m_center = " << b.m_center <<
216  + ", m_radius = " << b.m_radius;
217 }
218 
219 template<int dim>
220 inline std::istream& operator>>(std::istream& is, Ball<dim>& b)
221 {
222  char next;
223 
224  do {
225  is >> next;
226  } while(next != '=');
227 
228  is >> b.m_center;
229 
230  do {
231  is >> next;
232  } while(next != '=');
233 
234  is >> b.m_radius;
235 
236  return is;
237 }
238 
239 template<int dim>
240 inline std::ostream& operator<<(std::ostream& os, const Segment<dim>& s)
241 {
242  return os << "Segment: m_p1 = " << s.m_p1 << ", m_p2 = " << s.m_p2;
243 }
244 
245 template<int dim>
246 inline std::istream& operator>>(std::istream& is, Segment<dim>& s)
247 {
248  char next;
249 
250  do {
251  is >> next;
252  } while(next != '=');
253 
254  is >> s.m_p1;
255 
256  do {
257  is >> next;
258  } while(next != '=');
259 
260  is >> s.m_p2;
261 
262  return is;
263 }
264 
265 template<int dim>
266 inline std::ostream& operator<<(std::ostream& os, const RotBox<dim>& r)
267 {
268  return os << "RotBox: m_corner0 = " << r.m_corner0
269  << ", m_size = " << r.m_size
270  << ", m_orient = " << r.m_orient;
271 }
272 
273 template<int dim>
274 inline std::istream& operator>>(std::istream& is, RotBox<dim>& r)
275 {
276  char next;
277 
278  do {
279  is >> next;
280  } while(next != '=');
281 
282  is >> r.m_corner0;
283 
284  do {
285  is >> next;
286  } while(next != '=');
287 
288  is >> r.m_size;
289 
290  do {
291  is >> next;
292  } while(next != '=');
293 
294  is >> r.m_orient;
295 
296  return is;
297 }
298 
299 template<> std::ostream& operator<<(std::ostream& os, const Polygon<2>& r);
300 template<> std::istream& operator>>(std::istream& is, Polygon<2>& r);
301 
302 template<int dim>
303 inline std::ostream& operator<<(std::ostream& os, const Polygon<dim>& r)
304 {
305  int size = r.m_poly.numCorners();
306 
307  if(size == 0) {
308  os << "<empty>";
309  return os;
310  }
311 
312  os << "Polygon: (";
313 
314  for(int i = 0; i < size; ++i)
315  os << r.getCorner(i) << (i < (dim - 1) ? ',' : ')');
316 
317  return os;
318 }
319 
320 // Can't stick this in operator>>(std::istream&, Polygon<>&), because
321 // we use it as a template argument for list<>. Why isn't that allowed?
322 template<int dim> struct _PolyReader
323 {
324  Point<dim> pd;
325  Point<2> p2;
326 };
327 
328 template<int dim>
329 std::istream& operator>>(std::istream& is, Polygon<dim>& r)
330 {
331  char next;
332  _PolyReader<dim> read;
333  std::list<_PolyReader<dim> > read_list;
334 
335  // Read in the points
336 
337  do {
338  is >> next;
339  if(next == '<') { // empty polygon
340  do {
341  is >> next;
342  } while(next != '>');
343  return is;
344  }
345  } while(next != '(');
346 
347  while(true) {
348  is >> read.pd;
349  read_list.push_back(read);
350  is >> next;
351  if(next == ')')
352  break;
353  if(next != ',')
354  throw ParseError();
355  }
356 
357  // Convert to internal format. Be careful about the order points are
358  // added to the orientation. If the first few points are too close together,
359  // round off error can skew the plane, and later points that are further
360  // away may fail.
361 
362  typename std::list<_PolyReader<dim> >::iterator i, end = read_list.end();
363  bool succ;
364 
365  int str_prec = is.precision();
366  double str_eps = 1;
367  while(--str_prec > 0) // Precision of 6 gives epsilon = 1e-5
368  str_eps /= 10;
369  double epsilon = DoubleMax(str_eps, WFMATH_EPSILON);
370 
371  r.m_orient = _Poly2Orient<dim>();
372 
373  if(read_list.size() < 3) { // This will always work
374  for(i = read_list.begin(); i != end; ++i) {
375  succ = r.m_orient.expand(i->pd, i->p2, epsilon);
376  assert(succ);
377  }
378  }
379  else { // Find the three furthest apart points
380  typename std::list<_PolyReader<dim> >::iterator p1 = end, p2 = end, p3 = end, j; // invalid values
381  CoordType dist = -1;
382 
383  for(i = read_list.begin(); i != end; ++i) {
384  for(j = i, ++j; j != end; ++j) {
385  CoordType new_dist = SloppyDistance(i->pd, j->pd);
386  if(new_dist > dist) {
387  p1 = i;
388  p2 = j;
389  dist = new_dist;
390  }
391  }
392  }
393 
394  assert(p1 != end);
395  assert(p2 != end);
396 
397  dist = -1;
398 
399  for(i = read_list.begin(); i != end; ++i) {
400  // Don't want to be near either p1 or p2
401  if(i == p1 || i == p2)
402  continue;
403  CoordType new_dist = FloatMin(SloppyDistance(i->pd, p1->pd),
404  SloppyDistance(i->pd, p2->pd));
405  if(new_dist > dist) {
406  p3 = i;
407  dist = new_dist;
408  }
409  }
410 
411  assert(p3 != end);
412 
413  // Add p1, p2, p3 first
414 
415  succ = r.m_orient.expand(p1->pd, p1->p2, epsilon);
416  assert(succ);
417  succ = r.m_orient.expand(p2->pd, p2->p2, epsilon);
418  assert(succ);
419  succ = r.m_orient.expand(p3->pd, p3->p2, epsilon);
420  assert(succ);
421 
422  // Try to add the rest
423 
424  for(i = read_list.begin(); i != end; ++i) {
425  if(i == p1 || i == p2 || i == p3) // Did these already
426  continue;
427  succ = r.m_orient.expand(i->pd, i->p2, epsilon);
428  if(!succ) {
429  r.clear();
430  throw ParseError();
431  }
432  }
433  }
434 
435  // Got valid points, add them to m_poly
436 
437  r.m_poly.resize(read_list.size());
438 
439  int pnum;
440  for(i = read_list.begin(), pnum = 0; i != end; ++i, ++pnum)
441  r.m_poly[pnum] = i->p2;
442 
443  return is;
444 }
445 
446 } // namespace WFMath
447 
448 #endif // WFMATH_STREAM_H
void FromString(C &c, const std::string &s, unsigned int precision=6)
Parse a WFMath type from a string.
Definition: stream.h:109
float CoordType
Basic floating point type.
Definition: const.h:79
std::string ToString(const C &c, unsigned int precision=6)
Output a WFMath type as a string.
Definition: stream.h:99