Voxel
 All Classes Namespaces Files Functions Typedefs Enumerations Enumerator Macros Pages
shape.h
1 #pragma once
2 
3 #ifndef SHAPE_H
4 #define SHAPE_H
5 
6 
7 
8 
9 #include "vector.h"
10 
11 #include <vector>
12 #include <array>
13 #include <cmath>
14 
15 
16 
17 
18 /*==============================================================================
19  Shape class
20 ==============================================================================*/
21 
22 
23 template< typename t_Identifier >
24 struct Shape {
25 
26  t_Identifier const Inside( t_Identifier const& identifierDefault, Vector< double, 3 > const& position ) const;
27  bool const Split( Vector< double, 3 > const& position, double const side ) const;
28 
29 
30  void PushBall( t_Identifier const& identifier, Vector< double, 3 > const& center, double const radius, double const power );
31 
32 
33 private:
34 
35  struct Ball {
36 
37  t_Identifier identifier;
38 
39  Vector< double, 3 > center;
40  double radius;
41  double radiusPower;
42  double power;
43  };
44 
45  enum Comparison {
46 
47  COMPARISON_INSIDE,
48  COMPARISON_OUTSIDE,
49  COMPARISON_BOTH
50  };
51 
52 
53  static inline bool const IsInside( Ball const& ball, Vector< double, 3 > const& position );
54  static inline Comparison const IsInside( Ball const& ball, Vector< double, 3 > const& position, double const side );
55 
56 
57  std::vector< Ball > m_balls;
58 };
59 
60 
61 
62 
63 /*==============================================================================
64  Shape methods
65 ==============================================================================*/
66 
67 
68 template< typename t_Identifier >
69 t_Identifier const Shape< t_Identifier >::Inside( t_Identifier const& identifierDefault, Vector< double, 3 > const& position ) const {
70 
71  t_Identifier result = identifierDefault;
72 
73  typename std::vector< Ball >::const_iterator ii = m_balls.begin();
74  typename std::vector< Ball >::const_iterator iiEnd = m_balls.end();
75  for ( ; ii != iiEnd; ++ii )
76  if ( IsInside( *ii, position ) )
77  result = ii->identifier;
78 
79  return result;
80 }
81 
82 
83 template< typename t_Identifier >
84 bool const Shape< t_Identifier >::Split( Vector< double, 3 > const& position, double const side ) const {
85 
86  bool split = false;
87  { typename std::vector< Ball >::const_iterator ii = m_balls.begin();
88  typename std::vector< Ball >::const_iterator iiEnd = m_balls.end();
89  for ( ; ( ! split ) && ( ii != iiEnd ); ++ii )
90  if ( IsInside( *ii, position, side ) == COMPARISON_BOTH )
91  split = true;
92  }
93  return split;
94 }
95 
96 
97 template< typename t_Identifier >
98 void Shape< t_Identifier >::PushBall( t_Identifier const& identifier, Vector< double, 3 > const& center, double const radius, double const power ) {
99 
100  Ball ball;
101  ball.identifier = identifier;
102  ball.center = center;
103  ball.radius = radius;
104  ball.radiusPower = std::pow( radius, power );
105  ball.power = power;
106 
107  m_balls.push_back( ball );
108 }
109 
110 
111 template< typename t_Identifier >
112 bool const Shape< t_Identifier >::IsInside( Ball const& ball, Vector< double, 3 > const& position ) {
113 
114  bool result = false;
115 
116  Vector< double, 3 > delta = std::abs( position - ball.center );
117  if ( ( delta[ 0 ] < ball.radius ) && ( delta[ 1 ] < ball.radius ) && ( delta[ 2 ] < ball.radius ) ) {
118 
119  double const distance = std::pow( delta[ 0 ], ball.power ) + std::pow( delta[ 1 ], ball.power ) + std::pow( delta[ 2 ], ball.power );
120  result = ( distance < ball.radiusPower );
121  }
122 
123  return result;
124 }
125 
126 
127 template< typename t_Identifier >
128 typename Shape< t_Identifier >::Comparison const Shape< t_Identifier >::IsInside( Ball const& ball, Vector< double, 3 > const& position, double const side ) {
129 
130  Vector< double, 3 > minimumDelta = std::abs( position + side - ball.center );
131  Vector< double, 3 > maximumDelta = std::abs( position - ball.center );
132 
133  if ( maximumDelta[ 0 ] < minimumDelta[ 0 ] )
134  std::swap( maximumDelta[ 0 ], minimumDelta[ 0 ] );
135  if ( ( ball.center[ 0 ] >= position[ 0 ] ) && ( ball.center[ 0 ] <= position[ 0 ] + side ) )
136  minimumDelta[ 0 ] = 0;
137 
138  if ( maximumDelta[ 1 ] < minimumDelta[ 1 ] )
139  std::swap( maximumDelta[ 1 ], minimumDelta[ 1 ] );
140  if ( ( ball.center[ 1 ] >= position[ 1 ] ) && ( ball.center[ 1 ] <= position[ 1 ] + side ) )
141  minimumDelta[ 1 ] = 0;
142 
143  if ( maximumDelta[ 2 ] < minimumDelta[ 2 ] )
144  std::swap( maximumDelta[ 2 ], minimumDelta[ 2 ] );
145  if ( ( ball.center[ 2 ] >= position[ 2 ] ) && ( ball.center[ 2 ] <= position[ 2 ] + side ) )
146  minimumDelta[ 2 ] = 0;
147 
148  bool maximumInside = false;
149  if ( ( maximumDelta[ 0 ] < ball.radius ) && ( maximumDelta[ 1 ] < ball.radius ) && ( maximumDelta[ 2 ] < ball.radius ) ) {
150 
151  double const distance = std::pow( maximumDelta[ 0 ], ball.power ) + std::pow( maximumDelta[ 1 ], ball.power ) + std::pow( maximumDelta[ 2 ], ball.power );
152  maximumInside = ( distance < ball.radiusPower );
153  }
154 
155  bool minimumInside = maximumInside;
156  if ( ( ! minimumInside ) && ( minimumDelta[ 0 ] < ball.radius ) && ( minimumDelta[ 1 ] < ball.radius ) && ( minimumDelta[ 2 ] < ball.radius ) ) {
157 
158  double const distance = std::pow( minimumDelta[ 0 ], ball.power ) + std::pow( minimumDelta[ 1 ], ball.power ) + std::pow( minimumDelta[ 2 ], ball.power );
159  minimumInside = ( distance < ball.radiusPower );
160  }
161 
162  Comparison result = COMPARISON_BOTH;
163  if ( maximumInside )
164  result = COMPARISON_INSIDE;
165  else if ( ! minimumInside )
166  result = COMPARISON_OUTSIDE;
167  return result;
168 }
169 
170 
171 
172 
173 #endif // SHAPE_H