wfmath  1.0.3
A math library for the Worldforge system.
stream.cpp
1 // stream.cpp (Stream conversion backend in the WFMath library)
2 //
3 // The WorldForge Project
4 // Copyright (C) 2001 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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-13
25 
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29 
30 #include "stream.h"
31 #include "quaternion.h"
32 #include "MersenneTwister.h"
33 
34 #include <sstream>
35 #include <cassert>
36 #include <list>
37 
38 namespace WFMath {
39 
40 std::string _IOWrapper::ToStringImpl(const _IOWrapper::BaseWrite& b,
41  std::streamsize precision)
42 {
43  std::ostringstream ost;
44 
45  ost.precision(precision);
46  b.write(ost);
47 
48  return ost.str();
49 }
50 
51 void _IOWrapper::FromStringImpl(_IOWrapper::BaseRead& b,
52  const std::string& s, std::streamsize precision)
53 {
54  std::istringstream ist(s);
55 
56  ist.precision(precision);
57  b.read(ist);
58 }
59 
60 
61 // Can't stick this in operator>>(std::istream&, Polygon<>&), because
62 // we use it as a template argument for list<>. Why isn't that allowed?
63 template<int dim> struct PolyReader
64 {
65  Point<dim> pd;
66  Point<2> p2;
67 };
68 
69 template<int dim>
70 std::istream& operator>>(std::istream& is, Polygon<dim>& r)
71 {
72  char next;
73  PolyReader<dim> read;
74  std::list<PolyReader<dim> > read_list;
75 
76  // Read in the points
77 
78  do {
79  is >> next;
80  if(next == '<') { // empty polygon
81  do {
82  is >> next;
83  } while(next != '>');
84  return is;
85  }
86  } while(next != '(');
87 
88  while(true) {
89  is >> read.pd;
90  read_list.push_back(read);
91  is >> next;
92  if(next == ')')
93  break;
94  if(next != ',')
95  throw ParseError();
96  }
97 
98  // Convert to internal format. Be careful about the order points are
99  // added to the orientation. If the first few points are too close together,
100  // round off error can skew the plane, and later points that are further
101  // away may fail.
102 
103  typename std::list<PolyReader<dim> >::iterator i, end = read_list.end();
104  bool succ;
105 
106  std::streamsize str_prec = is.precision();
107  float str_eps = 1;
108  while(--str_prec > 0) // Precision of 6 gives epsilon = 1e-5
109  str_eps /= 10;
110  CoordType epsilon = FloatMax(str_eps, numeric_constants<CoordType>::epsilon());
111 
112  r.m_orient = Poly2Orient<dim>();
113 
114  if(read_list.size() < 3) { // This will always work
115  for(i = read_list.begin(); i != end; ++i) {
116  succ = r.m_orient.expand(i->pd, i->p2, epsilon);
117  assert(succ);
118  }
119  }
120  else { // Find the three furthest apart points
121  typename std::list<PolyReader<dim> >::iterator p1 = end, p2 = end, p3 = end, j; // invalid values
122  CoordType dist = -1;
123 
124  for(i = read_list.begin(); i != end; ++i) {
125  for(j = i, ++j; j != end; ++j) {
126  CoordType new_dist = SloppyDistance(i->pd, j->pd);
127  if(new_dist > dist) {
128  p1 = i;
129  p2 = j;
130  dist = new_dist;
131  }
132  }
133  }
134 
135  assert(p1 != end);
136  assert(p2 != end);
137 
138  dist = -1;
139 
140  for(i = read_list.begin(); i != end; ++i) {
141  // Don't want to be near either p1 or p2
142  if(i == p1 || i == p2)
143  continue;
144  CoordType new_dist = FloatMin(SloppyDistance(i->pd, p1->pd),
145  SloppyDistance(i->pd, p2->pd));
146  if(new_dist > dist) {
147  p3 = i;
148  dist = new_dist;
149  }
150  }
151 
152  assert(p3 != end);
153 
154  // Add p1, p2, p3 first
155 
156  succ = r.m_orient.expand(p1->pd, p1->p2, epsilon);
157  assert(succ);
158  succ = r.m_orient.expand(p2->pd, p2->p2, epsilon);
159  assert(succ);
160  succ = r.m_orient.expand(p3->pd, p3->p2, epsilon);
161  assert(succ);
162 
163  // Try to add the rest
164 
165  for(i = read_list.begin(); i != end; ++i) {
166  if(i == p1 || i == p2 || i == p3) // Did these already
167  continue;
168  succ = r.m_orient.expand(i->pd, i->p2, epsilon);
169  if(!succ) {
170  r.clear();
171  throw ParseError();
172  }
173  }
174  }
175 
176  // Got valid points, add them to m_poly
177 
178  r.m_poly.resize(read_list.size());
179 
180  int pnum;
181  for(i = read_list.begin(), pnum = 0; i != end; ++i, ++pnum)
182  r.m_poly[pnum] = i->p2;
183 
184  return is;
185 }
186 
187 template<int dim>
188 inline std::ostream& operator<<(std::ostream& os, const Polygon<dim>& r)
189 {
190  size_t size = r.m_poly.numCorners();
191 
192  if(size == 0) {
193  os << "<empty>";
194  return os;
195  }
196 
197  os << "Polygon: (";
198 
199  for(size_t i = 0; i < size; ++i)
200  os << r.getCorner(i) << (i < (dim - 1) ? ',' : ')');
201 
202  return os;
203 }
204 
205 
206 // force a bunch of instantiations
207 
208 template std::ostream& operator<< <3>(std::ostream& os, const Vector<3>& r);
209 template std::istream& operator>> <3>(std::istream& is, Vector<3>& r);
210 template std::ostream& operator<< <2>(std::ostream& os, const Vector<2>& r);
211 template std::istream& operator>> <2>(std::istream& is, Vector<2>& r);
212 template std::ostream& operator<< <3>(std::ostream& os, const Point<3>& r);
213 template std::istream& operator>> <3>(std::istream& is, Point<3>& r);
214 template std::ostream& operator<< <2>(std::ostream& os, const Point<2>& r);
215 template std::istream& operator>> <2>(std::istream& is, Point<2>& r);
216 template std::ostream& operator<< <3>(std::ostream& os, const RotMatrix<3>& r);
217 template std::istream& operator>> <3>(std::istream& is, RotMatrix<3>& r);
218 template std::ostream& operator<< <2>(std::ostream& os, const RotMatrix<2>& r);
219 template std::istream& operator>> <2>(std::istream& is, RotMatrix<2>& r);
220 template std::ostream& operator<< <3>(std::ostream& os, const AxisBox<3>& r);
221 template std::istream& operator>> <3>(std::istream& is, AxisBox<3>& r);
222 template std::ostream& operator<< <2>(std::ostream& os, const AxisBox<2>& r);
223 template std::istream& operator>> <2>(std::istream& is, AxisBox<2>& r);
224 template std::ostream& operator<< <3>(std::ostream& os, const Ball<3>& r);
225 template std::istream& operator>> <3>(std::istream& is, Ball<3>& r);
226 template std::ostream& operator<< <2>(std::ostream& os, const Ball<2>& r);
227 template std::istream& operator>> <2>(std::istream& is, Ball<2>& r);
228 template std::ostream& operator<< <3>(std::ostream& os, const Segment<3>& r);
229 template std::istream& operator>> <3>(std::istream& is, Segment<3>& r);
230 template std::ostream& operator<< <2>(std::ostream& os, const Segment<2>& r);
231 template std::istream& operator>> <2>(std::istream& is, Segment<2>& r);
232 template std::ostream& operator<< <3>(std::ostream& os, const RotBox<3>& r);
233 template std::istream& operator>> <3>(std::istream& is, RotBox<3>& r);
234 template std::ostream& operator<< <2>(std::ostream& os, const RotBox<2>& r);
235 template std::istream& operator>> <2>(std::istream& is, RotBox<2>& r);
236 // don't need 2d for Polygon, since it's a specialization
237 template std::ostream& operator<< <3>(std::ostream& os, const Polygon<3>& r);
238 template std::istream& operator>> <3>(std::istream& is, Polygon<3>& r);
239 
240 void WriteCoordList(std::ostream& os, const CoordType* d, const int num)
241 {
242  os << '(';
243 
244  for(int i = 0; i < num; ++i)
245  os << d[i] << (i < (num - 1) ? ',' : ')');
246 }
247 
248 void ReadCoordList(std::istream& is, CoordType* d, const int num)
249 {
250  char next;
251 
252  is >> next;
253 
254  if(next != '(')
255  throw ParseError();
256 
257  for(int i = 0; i < num; ++i) {
258  is >> d[i] >> next;
259  char want = (i == num - 1) ? ')' : ',';
260  if(next != want)
261  throw ParseError();
262  }
263 }
264 
265 CoordType GetEpsilon(std::istream& is)
266 {
267  std::streamsize str_prec = is.precision();
268  CoordType str_eps = 1;
269  while(--str_prec > 0) // Precision of 6 gives epsilon = 1e-5
270  str_eps /= 10;
271 
272  return str_eps;
273 }
274 
275 
276 // This is the only way I could get the operator<<() and operator>>()
277 // templates to recognize the declarations in the headers
278 
279 template<>
280 std::ostream& operator<<(std::ostream& os, const Polygon<2>& r)
281 {
282  size_t size = r.m_points.size();
283 
284  if(size == 0) {
285  os << "<empty>";
286  return os;
287  }
288 
289  os << "Polygon: (";
290 
291  for(size_t i = 0; i < size; ++i) {
292  os << r.m_points[i] << (i < (size - 1) ? ',' : ')');
293  }
294 
295  return os;
296 }
297 
298 template<>
299 std::istream& operator>>(std::istream& is, Polygon<2>& r)
300 {
301  char next;
302  Point<2> p;
303 
304  r.m_points.clear();
305 
306  do {
307  is >> next;
308  if(next == '<') { // empty polygon
309  do {
310  is >> next;
311  } while(next != '>');
312  return is;
313  }
314  } while(next != '(');
315 
316  while(true) {
317  is >> p;
318  r.m_points.push_back(p);
319  is >> next;
320  if(next == ')')
321  return is;
322  if(next != ',')
323  throw ParseError();
324  }
325 }
326 
327 std::ostream& operator<<(std::ostream& os, const Quaternion& q)
328 {
329  return os << "Quaternion: (" << q.m_w << ',' << q.m_vec << ')';
330 }
331 
332 std::istream& operator>>(std::istream& is, Quaternion& q)
333 {
334  char next;
335 
336  do {
337  is >> next;
338  } while(next != '(');
339 
340  is >> q.m_w;
341 
342  is >> next;
343  if(next != ',')
344  throw ParseError();
345 
346  is >> q.m_vec;
347 
348  CoordType norm = q.m_w * q.m_w + q.m_vec.sqrMag();
349 
350  norm = std::sqrt(norm);
351  q.m_w /= norm;
352  q.m_vec /= norm;
353  q.m_valid = true;
354 
355  is >> next;
356  if(next != ')')
357  throw ParseError();
358 
359  return is;
360 }
361 
362 std::ostream& operator<<(std::ostream& os, MTRand const& mtrand)
363 {
364  return mtrand.save(os);
365 }
366 
367 
368 std::istream& operator>>(std::istream& is, MTRand& mtrand)
369 {
370  return mtrand.load(is);
371 }
372 
373 } // namespace WFMath
A polygon, all of whose points lie in a plane, embedded in dim dimensions.
Definition: polygon.h:306
Generic library namespace.
Definition: shape.h:41
double CoordType
Basic floating point type.
Definition: const.h:140
static FloatType epsilon()
This is the attempted precision of the library.