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 
45 namespace WFMath {
46 
47 #ifndef ATLAS_MESSAGE_ELEMENT_H
48 #error "You must include Atlas/Message/Element.h before wfmath/atlasconv.h"
49 #endif
50 
51 typedef 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 
78 inline 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 
88 inline 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 
102 template<int dim>
104 {
105  fromAtlas(a);
106 }
107 
108 template<int dim>
109 inline void Vector<dim>::fromAtlas(const AtlasInType& a)
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  }
117  }
118  m_valid = true;
119 }
120 
121 template<int dim>
123 {
124  return _ArrayToAtlas(m_elem, dim);
125 }
126 
127 inline 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 
172 inline 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 
183 template<int dim>
185 {
186  fromAtlas(a);
187 }
188 
189 template<int dim>
190 inline void Point<dim>::fromAtlas(const AtlasInType& a)
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 
202 template<int dim>
204 {
205  return _ArrayToAtlas(m_elem, dim);
206 }
207 
208 template<int dim>
210 {
211  fromAtlas(a);
212 }
213 
214 template<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 
256 template<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 
279 template<int dim>
280 inline void Ball<dim>::fromAtlas(const AtlasInType& a)
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 
308 template<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 
317 template<int dim>
318 inline Ball<dim>::Ball(const AtlasInType& a) : m_center(Point<dim>::ZERO()),
319  m_radius(0)
320 {
321  fromAtlas(a);
322 }
323 
324 inline 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 
334 template<template <int> class ShapeT>
335 inline 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 
345 template<template <int> class ShapeT>
346 inline 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 
356 template<template <int> class ShapeT, int dim>
357 inline 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 
378 inline void Polygon<2>::fromAtlas(const AtlasInType& a)
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 
411 template<int dim>
412 inline void Line<dim>::fromAtlas(const AtlasInType& a)
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 
433 template<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 
446 template<int dim>
447 inline Line<dim>::Line(const AtlasInType& a) {
448  fromAtlas(a);
449 }
450 
451 template<int dim>
452 inline void RotBox<dim>::fromAtlas(const AtlasInType& a)
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 
479 template<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 
489 template<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