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
45namespace WFMath {
46
47// sstream vs. strstream compatibility wrapper
48
49namespace _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
99template<class C>
100inline std::string ToString(const C& c, std::streamsize precision = 6)
101{
102 return _IOWrapper::ToStringImpl(_IOWrapper::ImplWrite<C>(c), precision);
103}
104
106
109template<class C>
110inline 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
116void _ReadCoordList(std::istream& is, CoordType* d, const int num);
117void _WriteCoordList(std::ostream& os, const CoordType* d, const int num);
118CoordType _GetEpsilon(std::istream& is);
119
120template<int dim>
121inline std::ostream& operator<<(std::ostream& os, const Vector<dim>& v)
122{
123 _WriteCoordList(os, v.m_elem, dim);
124 return os;
125}
126
127template<int dim>
128inline 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
135template<int dim>
136inline 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
148template<int dim>
149inline 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
172template<int dim>
173inline std::ostream& operator<<(std::ostream& os, const Point<dim>& p)
174{
175 _WriteCoordList(os, p.m_elem, dim);
176 return os;
177}
178
179template<int dim>
180inline 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
187template<int dim>
188inline 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
193template<int dim>
194inline 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
213template<int dim>
214inline 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
220template<int dim>
221inline 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
240template<int dim>
241inline 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
246template<int dim>
247inline 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
266template<int dim>
267inline 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
274template<int dim>
275inline 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
300template<> std::ostream& operator<<(std::ostream& os, const Polygon<2>& r);
301template<> std::istream& operator>>(std::istream& is, Polygon<2>& r);
302
303template<int dim>
304inline 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?
323template<int dim> struct _PolyReader
324{
325 Point<dim> pd;
326 Point<2> p2;
327};
328
329template<int dim>
330std::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
447template<int dim>
448inline 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
void FromString(C &c, const std::string &s, std::streamsize=6)
Parse a WFMath type from a string.
Definition stream.h:110
float CoordType
Basic floating point type.
Definition const.h:140
std::string ToString(const C &c, std::streamsize precision=6)
Output a WFMath type as a string.
Definition stream.h:100