WFMath  1.0.2
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/line.h>
38 #include <wfmath/error.h>
39 #include <string>
40 #include <iostream>
41 #include <list> // For Polygon<>::operator>>()
42 
43 #include <cassert>
44 
45 namespace WFMath {
46 
47 // sstream vs. strstream compatibility wrapper
48 
49 namespace _IOWrapper {
50 
51  // Need separate read/write classes, since one is const C& and the other is C&
52 
53  class BaseRead {
54  public:
55  virtual ~BaseRead() {}
56 
57  virtual void read(std::istream& is) = 0;
58  };
59 
60  class BaseWrite {
61  public:
62  virtual ~BaseWrite() {}
63 
64  virtual void write(std::ostream& os) const = 0;
65  };
66 
67  template<class C>
68  class ImplRead : public BaseRead {
69  public:
70  ImplRead(C& c) : m_data(c) {}
71  virtual ~ImplRead() {}
72 
73  virtual void read(std::istream& is) {is >> m_data;}
74 
75  private:
76  C &m_data;
77  };
78 
79  template<class C>
80  class ImplWrite : public BaseWrite {
81  public:
82  ImplWrite(const C& c) : m_data(c) {}
83  virtual ~ImplWrite() {}
84 
85  virtual void write(std::ostream& os) const {os << m_data;}
86 
87  private:
88  const C &m_data;
89  };
90 
91  std::string ToStringImpl(const BaseWrite& b, std::streamsize precision);
92  void FromStringImpl(BaseRead& b, const std::string& s, std::streamsize precision);
93 }
94 
96 
99 template<class C>
100 inline std::string ToString(const C& c, std::streamsize precision = 6)
101 {
102  return _IOWrapper::ToStringImpl(_IOWrapper::ImplWrite<C>(c), precision);
103 }
104 
106 
109 template<class C>
110 inline void FromString(C& c, const std::string& s, std::streamsize = 6)
111 {
112  _IOWrapper::ImplRead<C> i(c);
113  _IOWrapper::FromStringImpl(i, s, 6);
114 }
115 
116 void _ReadCoordList(std::istream& is, CoordType* d, const int num);
117 void _WriteCoordList(std::ostream& os, const CoordType* d, const int num);
118 CoordType _GetEpsilon(std::istream& is);
119 
120 template<int dim>
121 inline std::ostream& operator<<(std::ostream& os, const Vector<dim>& v)
122 {
123  _WriteCoordList(os, v.m_elem, dim);
124  return os;
125 }
126 
127 template<int dim>
128 inline std::istream& operator>>(std::istream& is, Vector<dim>& v)
129 {
130  _ReadCoordList(is, v.m_elem, dim);
131  v.m_valid = true;
132  return is;
133 }
134 
135 template<int dim>
136 inline std::ostream& operator<<(std::ostream& os, const RotMatrix<dim>& m)
137 {
138  os << '(';
139 
140  for(int i = 0; i < dim; ++i) {
141  _WriteCoordList(os, m.m_elem[i], dim);
142  os << (i < (dim - 1) ? ',' : ')');
143  }
144 
145  return os;
146 }
147 
148 template<int dim>
149 inline std::istream& operator>>(std::istream& is, RotMatrix<dim>& m)
150 {
151  CoordType d[dim*dim];
152  char next;
153 
154  is >> next;
155  if(next != '(')
156  throw ParseError();
157 
158  for(int i = 0; i < dim; ++i) {
159  _ReadCoordList(is, d + i * dim, dim);
160  is >> next;
161  char want = (i == dim - 1) ? ')' : ',';
162  if(next != want)
163  throw ParseError();
164  }
165 
166  if(!m._setVals(d, FloatMax(numeric_constants<CoordType>::epsilon(), _GetEpsilon(is))))
167  throw ParseError();
168 
169  return is;
170 }
171 
172 template<int dim>
173 inline std::ostream& operator<<(std::ostream& os, const Point<dim>& p)
174 {
175  _WriteCoordList(os, p.m_elem, dim);
176  return os;
177 }
178 
179 template<int dim>
180 inline std::istream& operator>>(std::istream& is, Point<dim>& p)
181 {
182  _ReadCoordList(is, p.m_elem, dim);
183  p.m_valid = true;
184  return is;
185 }
186 
187 template<int dim>
188 inline std::ostream& operator<<(std::ostream& os, const AxisBox<dim>& a)
189 {
190  return os << "AxisBox: m_low = " << a.m_low << ", m_high = " << a.m_high;
191 }
192 
193 template<int dim>
194 inline std::istream& operator>>(std::istream& is, AxisBox<dim>& a)
195 {
196  char next;
197 
198  do {
199  is >> next;
200  } while(next != '=');
201 
202  is >> a.m_low;
203 
204  do {
205  is >> next;
206  } while(next != '=');
207 
208  is >> a.m_high;
209 
210  return is;
211 }
212 
213 template<int dim>
214 inline std::ostream& operator<<(std::ostream& os, const Ball<dim>& b)
215 {
216  return os << "Ball: m_center = " << b.m_center <<
217  + ", m_radius = " << b.m_radius;
218 }
219 
220 template<int dim>
221 inline std::istream& operator>>(std::istream& is, Ball<dim>& b)
222 {
223  char next;
224 
225  do {
226  is >> next;
227  } while(next != '=');
228 
229  is >> b.m_center;
230 
231  do {
232  is >> next;
233  } while(next != '=');
234 
235  is >> b.m_radius;
236 
237  return is;
238 }
239 
240 template<int dim>
241 inline std::ostream& operator<<(std::ostream& os, const Segment<dim>& s)
242 {
243  return os << "Segment: m_p1 = " << s.m_p1 << ", m_p2 = " << s.m_p2;
244 }
245 
246 template<int dim>
247 inline std::istream& operator>>(std::istream& is, Segment<dim>& s)
248 {
249  char next;
250 
251  do {
252  is >> next;
253  } while(next != '=');
254 
255  is >> s.m_p1;
256 
257  do {
258  is >> next;
259  } while(next != '=');
260 
261  is >> s.m_p2;
262 
263  return is;
264 }
265 
266 template<int dim>
267 inline std::ostream& operator<<(std::ostream& os, const RotBox<dim>& r)
268 {
269  return os << "RotBox: m_corner0 = " << r.m_corner0
270  << ", m_size = " << r.m_size
271  << ", m_orient = " << r.m_orient;
272 }
273 
274 template<int dim>
275 inline std::istream& operator>>(std::istream& is, RotBox<dim>& r)
276 {
277  char next;
278 
279  do {
280  is >> next;
281  } while(next != '=');
282 
283  is >> r.m_corner0;
284 
285  do {
286  is >> next;
287  } while(next != '=');
288 
289  is >> r.m_size;
290 
291  do {
292  is >> next;
293  } while(next != '=');
294 
295  is >> r.m_orient;
296 
297  return is;
298 }
299 
300 template<> std::ostream& operator<<(std::ostream& os, const Polygon<2>& r);
301 template<> std::istream& operator>>(std::istream& is, Polygon<2>& r);
302 
303 template<int dim>
304 inline std::ostream& operator<<(std::ostream& os, const Polygon<dim>& r)
305 {
306  size_t size = r.m_poly.numCorners();
307 
308  if(size == 0) {
309  os << "<empty>";
310  return os;
311  }
312 
313  os << "Polygon: (";
314 
315  for(size_t i = 0; i < size; ++i)
316  os << r.getCorner(i) << (i < (dim - 1) ? ',' : ')');
317 
318  return os;
319 }
320 
321 // Can't stick this in operator>>(std::istream&, Polygon<>&), because
322 // we use it as a template argument for list<>. Why isn't that allowed?
323 template<int dim> struct _PolyReader
324 {
325  Point<dim> pd;
326  Point<2> p2;
327 };
328 
329 template<int dim>
330 std::istream& operator>>(std::istream& is, Polygon<dim>& r)
331 {
332  char next;
333  _PolyReader<dim> read;
334  std::list<_PolyReader<dim> > read_list;
335 
336  // Read in the points
337 
338  do {
339  is >> next;
340  if(next == '<') { // empty polygon
341  do {
342  is >> next;
343  } while(next != '>');
344  return is;
345  }
346  } while(next != '(');
347 
348  while(true) {
349  is >> read.pd;
350  read_list.push_back(read);
351  is >> next;
352  if(next == ')')
353  break;
354  if(next != ',')
355  throw ParseError();
356  }
357 
358  // Convert to internal format. Be careful about the order points are
359  // added to the orientation. If the first few points are too close together,
360  // round off error can skew the plane, and later points that are further
361  // away may fail.
362 
363  typename std::list<_PolyReader<dim> >::iterator i, end = read_list.end();
364  bool succ;
365 
366  std::streamsize str_prec = is.precision();
367  float str_eps = 1;
368  while(--str_prec > 0) // Precision of 6 gives epsilon = 1e-5
369  str_eps /= 10;
370  CoordType epsilon = FloatMax(str_eps, numeric_constants<CoordType>::epsilon());
371 
372  r.m_orient = _Poly2Orient<dim>();
373 
374  if(read_list.size() < 3) { // This will always work
375  for(i = read_list.begin(); i != end; ++i) {
376  succ = r.m_orient.expand(i->pd, i->p2, epsilon);
377  assert(succ);
378  }
379  }
380  else { // Find the three furthest apart points
381  typename std::list<_PolyReader<dim> >::iterator p1 = end, p2 = end, p3 = end, j; // invalid values
382  CoordType dist = -1;
383 
384  for(i = read_list.begin(); i != end; ++i) {
385  for(j = i, ++j; j != end; ++j) {
386  CoordType new_dist = SloppyDistance(i->pd, j->pd);
387  if(new_dist > dist) {
388  p1 = i;
389  p2 = j;
390  dist = new_dist;
391  }
392  }
393  }
394 
395  assert(p1 != end);
396  assert(p2 != end);
397 
398  dist = -1;
399 
400  for(i = read_list.begin(); i != end; ++i) {
401  // Don't want to be near either p1 or p2
402  if(i == p1 || i == p2)
403  continue;
404  CoordType new_dist = FloatMin(SloppyDistance(i->pd, p1->pd),
405  SloppyDistance(i->pd, p2->pd));
406  if(new_dist > dist) {
407  p3 = i;
408  dist = new_dist;
409  }
410  }
411 
412  assert(p3 != end);
413 
414  // Add p1, p2, p3 first
415 
416  succ = r.m_orient.expand(p1->pd, p1->p2, epsilon);
417  assert(succ);
418  succ = r.m_orient.expand(p2->pd, p2->p2, epsilon);
419  assert(succ);
420  succ = r.m_orient.expand(p3->pd, p3->p2, epsilon);
421  assert(succ);
422 
423  // Try to add the rest
424 
425  for(i = read_list.begin(); i != end; ++i) {
426  if(i == p1 || i == p2 || i == p3) // Did these already
427  continue;
428  succ = r.m_orient.expand(i->pd, i->p2, epsilon);
429  if(!succ) {
430  r.clear();
431  throw ParseError();
432  }
433  }
434  }
435 
436  // Got valid points, add them to m_poly
437 
438  r.m_poly.resize(read_list.size());
439 
440  int pnum;
441  for(i = read_list.begin(), pnum = 0; i != end; ++i, ++pnum)
442  r.m_poly[pnum] = i->p2;
443 
444  return is;
445 }
446 
447 template<int dim>
448 inline std::ostream& operator<<(std::ostream& os, const Line<dim>& r)
449 {
450  size_t size = r.numCorners();
451 
452  if(size == 0) {
453  os << "<empty>";
454  return os;
455  }
456 
457  os << "Line: (";
458 
459  for(size_t i = 0; i < size; ++i)
460  os << r.getCorner(i) << (i < (dim - 1) ? ',' : ')');
461 
462  return os;
463 }
464 
465 } // namespace WFMath
466 
467 #endif // WFMATH_STREAM_H
Generic library namespace.
Definition: atlasconv.h:45
A dim dimensional axis-aligned box.
Definition: axisbox.h:62
A dim dimensional rotation matrix. Technically, a member of the group O(dim).
Definition: const.h:53
A dim dimensional box, lying at an arbitrary angle.
Definition: const.h:52
A polygon, all of whose points lie in a plane, embedded in dim dimensions.
Definition: const.h:51
A dim dimensional vector.
Definition: const.h:55
float CoordType
Basic floating point type.
Definition: const.h:140
The 2D specialization of the Polygon<> template.
Definition: polygon.h:47
void FromString(C &c, const std::string &s, std::streamsize=6)
Parse a WFMath type from a string.
Definition: stream.h:110
A line segment embedded in dim dimensions.
Definition: const.h:54
An error thrown by operator>>() when it fails to parse wfmath types.
Definition: error.h:46
A dim dimensional point.
Definition: const.h:50
std::string ToString(const C &c, std::streamsize precision=6)
Output a WFMath type as a string.
Definition: stream.h:100
A dim dimensional ball.
Definition: ball.h:34