wfmath 1.0.3
A math library for the Worldforge system.
atlasconv.h
1// atlasconv.h (Functions to convert WFMath library object to/from an Atlas Message)
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-11
25
26// Since we don't want WFMath and Atlas to depend on each other,
27// we're putting all the atlas interface functions into this header.
28
29// WARNING! WARNING! Do not include this file in any other file in wfmath.
30
31#ifndef WFMATH_ATLAS_CONV_H
32#define WFMATH_ATLAS_CONV_H
33
34#include "point.h"
35#include "vector.h"
36#include "quaternion.h"
37#include "axisbox.h"
38#include "polygon.h"
39#include "ball.h"
40#include "rotbox.h"
41#include "line.h"
42
43#include <cmath>
44
45namespace WFMath {
46
47#ifndef ATLAS_MESSAGE_ELEMENT_H
48#error "You must include Atlas/Message/Element.h before wfmath/atlasconv.h"
49#endif
50
51typedef Atlas::Message::WrongTypeException _AtlasBadParse;
52
54{
55 public:
56 AtlasInType(const Atlas::Message::Element& val) : m_val(val) {}
57 // allow nice conversions when necessary
58 template<class C> AtlasInType(C c) : m_obj(c), m_val(m_obj) {}
59 operator const Atlas::Message::Element&() const {return m_val;}
60 bool IsList() const {return m_val.isList();}
61 const Atlas::Message::ListType& AsList() const {return m_val.asList();}
62 private:
63 Atlas::Message::Element m_obj;
64 const Atlas::Message::Element& m_val;
65};
66
68{
69 public:
70 AtlasOutType(const Atlas::Message::ListType& l) : m_val(l) {}
71 AtlasOutType(const Atlas::Message::MapType& l) : m_val(l) {}
72 operator Atlas::Message::Element&() {return m_val;}
73 operator const Atlas::Message::Element&() const {return m_val;}
74 private:
75 Atlas::Message::Element m_val;
76};
77
78inline AtlasOutType _ArrayToAtlas(const CoordType* array, unsigned len)
79{
80 Atlas::Message::ListType a(len);
81
82 for(unsigned i = 0; i < len; ++i)
83 a[i] = array[i];
84
85 return a;
86}
87
88inline void _ArrayFromAtlas(CoordType* array, unsigned len, const AtlasInType& a)
89{
90 if(!a.IsList())
91 throw _AtlasBadParse();
92
93 const Atlas::Message::ListType& list(a.AsList());
94
95 if(list.size() != (unsigned int) len)
96 throw _AtlasBadParse();
97
98 for(unsigned i = 0; i < len; ++i)
99 array[i] = static_cast<CoordType>(list[i].asNum());
100}
101
102template<int dim>
105 fromAtlas(a);
106}
107
108template<int dim>
110{
111 _ArrayFromAtlas(m_elem, dim, a);
112 for (int i = 0; i < dim; ++i) {
113 if (!std::isfinite(m_elem[i])) {
114 m_valid = false;
115 return;
116 }
118 m_valid = true;
120
121template<int dim>
123{
124 return _ArrayToAtlas(m_elem, dim);
125}
126
127inline void Quaternion::fromAtlas(const AtlasInType& a)
128{
129 if(!a.IsList())
130 throw _AtlasBadParse();
131
132
133 const Atlas::Message::ListType& list(a.AsList());
134
135 if(list.size() != 4)
136 throw _AtlasBadParse();
137
138
139 for(int i = 0; i < 3; ++i)
140 m_vec[i] = static_cast<CoordType>(list[i].asNum());
141
142 for (int i = 0; i < 3; ++i) {
143 if (!std::isfinite(m_vec[i])) {
144 m_valid = false;
145 m_vec.setValid(false);
146 return;
147 }
148 }
149
150 m_w = static_cast<CoordType>(list[3].asNum());
151 if (!std::isfinite(m_w)) {
152 m_valid = false;
153 return;
154 }
155
156 CoordType norm = std::sqrt(m_w * m_w + m_vec.sqrMag());
157
158 if (norm <= numeric_constants<CoordType>::epsilon()) {
159 m_valid = false;
160 m_vec.setValid(false);
161 return;
162 }
163
164 m_vec /= norm;
165 m_w /= norm;
166
167 m_valid = true;
168 m_age = 1;
169 m_vec.setValid();
170}
171
172inline AtlasOutType Quaternion::toAtlas() const
173{
174 Atlas::Message::ListType a(4);
175
176 for(int i = 0; i < 3; ++i)
177 a[i] = m_vec[i];
178 a[3] = m_w;
179
180 return a;
181}
182
183template<int dim>
185{
186 fromAtlas(a);
187}
188
189template<int dim>
191{
192 _ArrayFromAtlas(m_elem, dim, a);
193 for (int i = 0; i < dim; ++i) {
194 if (!std::isfinite(m_elem[i])) {
195 m_valid = false;
196 return;
197 }
198 }
199 m_valid = true;
200}
201
202template<int dim>
204{
205 return _ArrayToAtlas(m_elem, dim);
206}
207
208template<int dim>
210{
211 fromAtlas(a);
212}
213
214template<int dim>
216{
217 if(!a.IsList())
218 throw _AtlasBadParse();
219
220 const Atlas::Message::ListType& list(a.AsList());
221
222 switch(list.size()) {
223 case dim:
224 m_low.setToOrigin();
225 m_high.fromAtlas(a);
226 break;
227 case (2 * dim):
228 for(int i = 0; i < dim; ++i) {
229 m_low[i] = list[i].asNum();
230 if (!std::isfinite((m_low[i]))) {
231 m_low.setValid(false);
232 return;
233 }
234 m_high[i] = list[i+dim].asNum();
235 if (!std::isfinite((m_high[i]))) {
236 m_high.setValid(false);
237 return;
238 }
239 }
240 m_low.setValid();
241 m_high.setValid();
242 break;
243 default:
244 throw _AtlasBadParse();
245 }
246
247 for(int i = 0; i < dim; ++i) {
248 if(m_low[i] > m_high[i]) { // spec may allow this?
249 CoordType tmp = m_low[i];
250 m_low[i] = m_high[i];
251 m_high[i] = tmp;
252 }
253 }
254}
255
256template<int dim>
258{
259 int i;
260
261 for(i = 0; i < dim; ++i)
262 if(m_low[i] != 0)
263 break;
264
265 if(i == dim)
266 return m_high.toAtlas(); // matches case 'dim' above
267
268 // Do case '2 * dim' above
269
270 Atlas::Message::ListType a(2*dim);
271 for(i = 0; i < dim; ++i) {
272 a[i] = m_low[i];
273 a[dim+i] = m_high[i];
274 }
275
276 return a;
277}
278
279template<int dim>
281{
282 const Atlas::Message::Element& message(a);
283 if (message.isMap()) {
284 const Atlas::Message::MapType& shapeElement(message.asMap());
285 // Get sphere's radius
286 auto shape_I = shapeElement.find("radius");
287 if (shape_I != shapeElement.end()) {
288 const Atlas::Message::Element& shapeRadiusElem(shape_I->second);
289 if (shapeRadiusElem.isNum()) {
290 m_radius = shapeRadiusElem.asNum();
291 //Perhaps we should add a check to Ball::isValid for non-nan radius? Until that we'll just invalidate the center instead.
292 if (!std::isfinite(m_radius)) {
293 m_center.setValid(false);
294 return;
295 }
296 }
297 }
298 auto pos_I = shapeElement.find("position");
299 if (pos_I != shapeElement.end()) {
300 const Atlas::Message::Element& posElem(pos_I->second);
301 if (posElem.isList()) {
302 m_center.fromAtlas(posElem);
303 }
304 }
305 }
306}
307
308template<int dim>
310{
311 Atlas::Message::MapType map;
312 map.insert(Atlas::Message::MapType::value_type("radius", m_radius));
313 map.insert(Atlas::Message::MapType::value_type("position", m_center.toAtlas()));
314 return map;
315}
316
317template<int dim>
318inline Ball<dim>::Ball(const AtlasInType& a) : m_center(Point<dim>::ZERO()),
319 m_radius(0)
320{
321 fromAtlas(a);
322}
323
324inline bool _ListNumCheck(const Atlas::Message::ListType & list, int dim)
325{
326 for(int i = 0; i < dim; ++i) {
327 if (!list[i].isNum()) {
328 return false;
329 }
330 }
331 return true;
332}
333
334template<template <int> class ShapeT>
335inline void _AddCorner(ShapeT<3> & shape,
336 const Atlas::Message::ListType & point)
337{
338 Point<3> wpt(point[0].asNum(), point[1].asNum(), point[2].asNum());
339 if (!std::isfinite(wpt.x()) || !std::isfinite(wpt.y()) || !std::isfinite(wpt.z())) {
340 return;
341 }
342 shape.addCorner(shape.numCorners(), wpt);
343}
344
345template<template <int> class ShapeT>
346inline void _AddCorner(ShapeT<2> & shape,
347 const Atlas::Message::ListType & point)
348{
349 Point<2> wpt(point[0].asNum(), point[1].asNum());
350 if (!std::isfinite(wpt.x()) || !std::isfinite(wpt.y())) {
351 return;
352 }
353 shape.addCorner(shape.numCorners(), wpt);
354}
355
356template<template <int> class ShapeT, int dim>
357inline void _CornersFromAtlas(ShapeT<dim> & shape,
358 const Atlas::Message::Element& message)
359{
360 if (message.isList()) {
361 const Atlas::Message::ListType& pointsData(message.asList());
362
363 for (const auto & p : pointsData) {
364 if (!p.isList()) {
365 continue;
366 }
367
368 const Atlas::Message::ListType& point(p.asList());
369 if ((point.size() < dim) || !_ListNumCheck(point, dim)) {
370 continue;
371 }
372
373 _AddCorner(shape, point);
374 }
375 }
376}
377
379{
380 const Atlas::Message::Element& message(a);
381 if (message.isMap()) {
382 const Atlas::Message::MapType& shapeElement(message.asMap());
383 auto it = shapeElement.find("points");
384 if ((it != shapeElement.end()) && it->second.isList()) {
385 _CornersFromAtlas(*this, it->second);
386 if (numCorners() > 2) {
387 return;
388 }
389 }
390 } else if (message.isList()) {
391 _CornersFromAtlas(*this, message);
392 if (numCorners() > 2) {
393 return;
394 }
395 }
396 throw _AtlasBadParse();
397}
398
400{
401 Atlas::Message::ListType points;
402 for (const auto & point : m_points)
403 {
404 points.push_back(point.toAtlas());
405 }
406 Atlas::Message::MapType map;
407 map.insert(Atlas::Message::MapType::value_type("points", points));
408 return map;
409}
410
411template<int dim>
413{
414 const Atlas::Message::Element& message(a);
415 if (message.isMap()) {
416 const Atlas::Message::MapType& shapeElement(message.asMap());
417 auto it = shapeElement.find("points");
418 if ((it != shapeElement.end()) && it->second.isList()) {
419 _CornersFromAtlas(*this, it->second);
420 if (numCorners() > 0) {
421 return;
422 }
423 }
424 } else if (message.isList()) {
425 _CornersFromAtlas(*this, message);
426 if (numCorners() > 0) {
427 return;
428 }
429 }
430 throw _AtlasBadParse();
431}
432
433template<int dim>
435{
436 Atlas::Message::ListType points;
437 for (const_iterator I = m_points.begin(); I != m_points.end(); ++I)
438 {
439 points.push_back(I->toAtlas());
440 }
441 Atlas::Message::MapType map;
442 map.insert(Atlas::Message::MapType::value_type("points", points));
443 return map;
444}
445
446template<int dim>
447inline Line<dim>::Line(const AtlasInType& a) {
448 fromAtlas(a);
449}
450
451template<int dim>
453{
454 const Atlas::Message::Element& message(a);
455 if (message.isMap()) {
456 const Atlas::Message::MapType& shapeElement(message.asMap());
457 // Get rotbox's position
458 auto shape_I = shapeElement.find("point");
459 if (shape_I != shapeElement.end()) {
460 const Atlas::Message::Element& shapePointElem(shape_I->second);
461 Point<dim> shapePoint;
462 shapePoint.fromAtlas(shapePointElem);
463 // Get rotbox's vector
464 shape_I = shapeElement.find("size");
465 if (shape_I != shapeElement.end()) {
466 const Atlas::Message::Element& shapeVectorElem(shape_I->second);
467 Vector<dim> shapeVector;
468 shapeVector.fromAtlas(shapeVectorElem);
469 m_corner0 = shapePoint;
470 m_size = shapeVector;
471 m_orient = RotMatrix<dim>().identity(); //TODO: parse rotation matrix (is it needed?)
472 return;
473 }
474 }
475 }
476 throw _AtlasBadParse();
477}
478
479template<int dim>
481{
482 Atlas::Message::MapType map;
483 map.insert(Atlas::Message::MapType::value_type("point", m_corner0.toAtlas()));
484 map.insert(Atlas::Message::MapType::value_type("size", m_size.toAtlas()));
485 //TODO: also add the rotmatrix
486 return map;
487}
488
489template<int dim>
491 fromAtlas(a);
492}
493
494} // namespace WFMath
495
496#endif // WFMATH_ATLAS_CONV_H
A dim dimensional axis-aligned box.
Definition: axisbox.h:64
AtlasOutType toAtlas() const
Create an Atlas object from the box.
Definition: atlasconv.h:257
A dim dimensional ball.
Definition: ball.h:61
void fromAtlas(const AtlasInType &a)
Set the box's value to that given by an Atlas object.
Definition: atlasconv.h:280
A dim dimensional line.
Definition: line.h:43
void fromAtlas(const AtlasInType &a)
Set the line's value to that given by an Atlas object.
Definition: atlasconv.h:412
AtlasOutType toAtlas() const
Create an Atlas object from the line.
Definition: atlasconv.h:434
A dim dimensional point.
Definition: point.h:96
void fromAtlas(const AtlasInType &a)
Set the point's value to that given by an Atlas object.
Definition: atlasconv.h:190
A polygon, all of whose points lie in a plane, embedded in dim dimensions.
Definition: polygon.h:306
RotBox()
construct an uninitialized box
Definition: rotbox.h:50
void fromAtlas(const AtlasInType &a)
Set the box's value to that given by an Atlas object.
Definition: atlasconv.h:452
AtlasOutType toAtlas() const
Create an Atlas object from the box.
Definition: atlasconv.h:480
A dim dimensional rotation matrix. Technically, a member of the group O(dim).
Definition: rotmatrix.h:87
RotMatrix & identity()
set the matrix to the identity matrix
A dim dimensional vector.
Definition: vector.h:121
Vector()
Construct an uninitialized vector.
Definition: vector.h:125
void fromAtlas(const AtlasInType &a)
Set the vector's value to that given by an Atlas object.
Definition: atlasconv.h:109
Generic library namespace.
Definition: shape.h:41
double CoordType
Basic floating point type.
Definition: const.h:140