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