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
36namespace WFMath {
37
38std::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
49void _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?
61template<int dim> struct PolyReader
62{
63 Point<dim> pd;
64 Point<2> p2;
65};
66
67template<int dim>
68std::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
185template<int dim>
186inline 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
206template std::ostream& operator<< <3>(std::ostream& os, const Vector<3>& r);
207template std::istream& operator>> <3>(std::istream& is, Vector<3>& r);
208template std::ostream& operator<< <2>(std::ostream& os, const Vector<2>& r);
209template std::istream& operator>> <2>(std::istream& is, Vector<2>& r);
210template std::ostream& operator<< <3>(std::ostream& os, const Point<3>& r);
211template std::istream& operator>> <3>(std::istream& is, Point<3>& r);
212template std::ostream& operator<< <2>(std::ostream& os, const Point<2>& r);
213template std::istream& operator>> <2>(std::istream& is, Point<2>& r);
214template std::ostream& operator<< <3>(std::ostream& os, const RotMatrix<3>& r);
215template std::istream& operator>> <3>(std::istream& is, RotMatrix<3>& r);
216template std::ostream& operator<< <2>(std::ostream& os, const RotMatrix<2>& r);
217template std::istream& operator>> <2>(std::istream& is, RotMatrix<2>& r);
218template std::ostream& operator<< <3>(std::ostream& os, const AxisBox<3>& r);
219template std::istream& operator>> <3>(std::istream& is, AxisBox<3>& r);
220template std::ostream& operator<< <2>(std::ostream& os, const AxisBox<2>& r);
221template std::istream& operator>> <2>(std::istream& is, AxisBox<2>& r);
222template std::ostream& operator<< <3>(std::ostream& os, const Ball<3>& r);
223template std::istream& operator>> <3>(std::istream& is, Ball<3>& r);
224template std::ostream& operator<< <2>(std::ostream& os, const Ball<2>& r);
225template std::istream& operator>> <2>(std::istream& is, Ball<2>& r);
226template std::ostream& operator<< <3>(std::ostream& os, const Segment<3>& r);
227template std::istream& operator>> <3>(std::istream& is, Segment<3>& r);
228template std::ostream& operator<< <2>(std::ostream& os, const Segment<2>& r);
229template std::istream& operator>> <2>(std::istream& is, Segment<2>& r);
230template std::ostream& operator<< <3>(std::ostream& os, const RotBox<3>& r);
231template std::istream& operator>> <3>(std::istream& is, RotBox<3>& r);
232template std::ostream& operator<< <2>(std::ostream& os, const RotBox<2>& r);
233template std::istream& operator>> <2>(std::istream& is, RotBox<2>& r);
234// don't need 2d for Polygon, since it's a specialization
235template std::ostream& operator<< <3>(std::ostream& os, const Polygon<3>& r);
236template std::istream& operator>> <3>(std::istream& is, Polygon<3>& r);
237
238void 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
246void 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
263CoordType 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
277template<>
278std::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
296template<>
297std::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
325std::ostream& operator<<(std::ostream& os, const Quaternion& q)
326{
327 return os << "Quaternion: (" << q.m_w << ',' << q.m_vec << ')';
328}
329
330std::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
360std::ostream& operator<<(std::ostream& os, MTRand const& mtrand)
361{
362 return mtrand.save(os);
363}
364
365
366std::istream& operator>>(std::istream& is, MTRand& mtrand)
367{
368 return mtrand.load(is);
369}
370
371} // 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.