00001 #ifndef LIBGEODECOMP_GEOMETRY_TOPOLOGIES_H 00002 #define LIBGEODECOMP_GEOMETRY_TOPOLOGIES_H 00003 00004 #include <stdexcept> 00005 #include <iostream> 00006 #include <libgeodecomp/geometry/coord.h> 00007 00008 namespace LibGeoDecomp { 00009 00010 namespace TopologiesHelpers { 00011 00012 template<int DIM, class TOPOLOGY> 00013 class WrapsAxis; 00014 00015 template<class TOPOLOGY> 00016 class WrapsAxis<0, TOPOLOGY> 00017 { 00018 public: 00019 static const bool VALUE = TOPOLOGY::WRAP_AXIS0; 00020 }; 00021 00022 template<class TOPOLOGY> 00023 class WrapsAxis<1, TOPOLOGY> 00024 { 00025 public: 00026 static const bool VALUE = TOPOLOGY::WRAP_AXIS1; 00027 }; 00028 00029 template<class TOPOLOGY> 00030 class WrapsAxis<2, TOPOLOGY> 00031 { 00032 public: 00033 static const bool VALUE = TOPOLOGY::WRAP_AXIS2; 00034 }; 00035 00036 template<class TOPOLOGY> 00037 class NormalizeEdges 00038 { 00039 public: 00040 Coord<1> operator()(const Coord<1>& coord, const Coord<1>& dim) 00041 { 00042 return Coord<1>( 00043 wrap(coord[0], dim[0])); 00044 } 00045 00046 Coord<2> operator()(const Coord<2>& coord, const Coord<2>& dim) 00047 { 00048 return Coord<2>( 00049 wrap(coord[0], dim[0]), 00050 wrap(coord[1], dim[1])); 00051 } 00052 00053 Coord<3> operator()(const Coord<3>& coord, const Coord<3>& dim) 00054 { 00055 return Coord<3>( 00056 wrap(coord[0], dim[0]), 00057 wrap(coord[1], dim[1]), 00058 wrap(coord[2], dim[2])); 00059 } 00060 00061 private: 00062 inline int wrap(int x, int dim) 00063 { 00064 if (x < 0) { 00065 return (x + dim) % dim; 00066 } 00067 if (x >= dim) { 00068 return x % dim; 00069 } 00070 00071 return x; 00072 } 00073 }; 00074 00075 template<class TOPOLOGY> 00076 class OutOfBounds 00077 { 00078 public: 00079 bool operator()(const Coord<1> coord, const Coord<1> dim) 00080 { 00081 return 00082 ((!WrapsAxis<0, TOPOLOGY>::VALUE) && ((coord[0] < 0) || (coord[0] >= dim[0]))); 00083 } 00084 00085 bool operator()(const Coord<2> coord, const Coord<2> dim) 00086 { 00087 return 00088 ((!WrapsAxis<0, TOPOLOGY>::VALUE) && ((coord[0] < 0) || (coord[0] >= dim[0]))) || 00089 ((!WrapsAxis<1, TOPOLOGY>::VALUE) && ((coord[1] < 0) || (coord[1] >= dim[1]))); 00090 } 00091 00092 bool operator()(const Coord<3> coord, const Coord<3> dim) 00093 { 00094 return 00095 ((!WrapsAxis<0, TOPOLOGY>::VALUE) && ((coord[0] < 0) || (coord[0] >= dim[0]))) || 00096 ((!WrapsAxis<1, TOPOLOGY>::VALUE) && ((coord[1] < 0) || (coord[1] >= dim[1]))) || 00097 ((!WrapsAxis<2, TOPOLOGY>::VALUE) && ((coord[2] < 0) || (coord[2] >= dim[2]))); 00098 } 00099 }; 00100 00101 template<class TOPOLOGY> 00102 class NormalizeCoord 00103 { 00104 public: 00105 template<int DIM> 00106 Coord<DIM> operator()(const Coord<DIM>& coord, const Coord<DIM>& dim) 00107 { 00108 if (OutOfBounds<TOPOLOGY>()(coord, dim)) { 00109 return Coord<DIM>::diagonal(-1); 00110 } 00111 00112 return NormalizeEdges<TOPOLOGY>()(coord, dim); 00113 } 00114 }; 00115 00116 template<int DIM> 00117 class Accessor; 00118 00119 template<> 00120 class Accessor<1> 00121 { 00122 public: 00123 template<typename STORAGE, typename VALUE> 00124 void operator()(STORAGE& storage, VALUE **value, const Coord<1>& coord) const 00125 { 00126 *value = &storage[coord.x()]; 00127 } 00128 00129 template<typename STORAGE, typename VALUE> 00130 void operator()(const STORAGE& storage, const VALUE **value, const Coord<1>& coord) const 00131 { 00132 *value = &storage[coord.x()]; 00133 } 00134 }; 00135 00136 template<> 00137 class Accessor<2> 00138 { 00139 public: 00140 template<typename STORAGE, typename VALUE> 00141 void operator()(STORAGE& storage, VALUE **value, const Coord<2>& coord) const 00142 { 00143 *value = &storage[coord.y()][coord.x()]; 00144 } 00145 00146 template<typename STORAGE, typename VALUE> 00147 void operator()(const STORAGE& storage, const VALUE **value, const Coord<2>& coord) const 00148 { 00149 *value = &storage[coord.y()][coord.x()]; 00150 } 00151 }; 00152 00153 template<> 00154 class Accessor<3> 00155 { 00156 public: 00157 template<typename STORAGE, typename VALUE> 00158 void operator()(STORAGE& storage, VALUE **value, const Coord<3>& coord) const 00159 { 00160 *value = &storage[coord.z()][coord.y()][coord.x()]; 00161 } 00162 00163 template<typename STORAGE, typename VALUE> 00164 void operator()(const STORAGE& storage, const VALUE **value, const Coord<3>& coord) const 00165 { 00166 *value = &storage[coord.z()][coord.y()][coord.x()]; 00167 } 00168 }; 00169 00170 template<int DIMENSIONS, bool WRAP_DIM0, bool WRAP_DIM1, bool WRAP_DIM2> 00171 class RawTopology 00172 { 00173 public: 00174 const static int DIM = DIMENSIONS; 00175 const static bool WRAP_AXIS0 = WRAP_DIM0; 00176 const static bool WRAP_AXIS1 = WRAP_DIM1; 00177 const static bool WRAP_AXIS2 = WRAP_DIM2; 00178 }; 00179 00180 template<int DIMENSIONS, bool WRAP_DIM0=false, bool WRAP_DIM1=false, bool WRAP_DIM2=false> 00181 class Topology 00182 { 00183 public: 00184 typedef RawTopology<DIMENSIONS, WRAP_DIM0, WRAP_DIM1, WRAP_DIM2> RawTopologyType; 00185 static const int DIM = DIMENSIONS; 00186 00187 template<typename GRID, int DIM> 00188 static inline const typename GRID::CellType& locate( 00189 const GRID& grid, 00190 const Coord<DIM>& coord) 00191 { 00192 const Coord<DIM>& dim = grid.getDimensions(); 00193 if (OutOfBounds<RawTopologyType>()(coord, dim)) { 00194 return grid.getEdgeCell(); 00195 } 00196 00197 typename GRID::CellType *ret; 00198 Accessor<DIM>()(grid, &ret, NormalizeEdges<RawTopologyType>()(coord, dim)); 00199 return *ret; 00200 } 00201 00202 template<typename GRID> 00203 static inline typename GRID::CellType& locate( 00204 GRID& grid, 00205 const Coord<DIMENSIONS>& coord) 00206 { 00207 const Coord<DIMENSIONS>& dim = grid.getDimensions(); 00208 if (OutOfBounds<RawTopologyType>()(coord, dim)) { 00209 return grid.getEdgeCell(); 00210 } 00211 00212 typename GRID::CellType *ret; 00213 Accessor<DIMENSIONS>()(grid, &ret, NormalizeEdges<RawTopologyType>()(coord, dim)); 00214 return *ret; 00215 } 00216 00217 template<int D> 00218 class WrapsAxis 00219 { 00220 public: 00221 static const bool VALUE = TopologiesHelpers::WrapsAxis<D, RawTopologyType>::VALUE; 00222 }; 00223 00224 static Coord<DIM> normalize(const Coord<DIMENSIONS>& coord, const Coord<DIMENSIONS>& dimensions) 00225 { 00226 return NormalizeCoord<RawTopologyType>()(coord, dimensions); 00227 } 00228 00229 static bool isOutOfBounds(const Coord<DIM>& coord, const Coord<DIM>& dim) 00230 { 00231 return TopologiesHelpers::OutOfBounds<RawTopologyType>()(coord, dim); 00232 } 00233 00240 static bool wrapsAxis(const int& dim) 00241 { 00242 if (dim == 0) { 00243 return WrapsAxis<0>::VALUE; 00244 } 00245 if (dim == 1) { 00246 return WrapsAxis<1>::VALUE; 00247 } 00248 00249 return WrapsAxis<2>::VALUE; 00250 } 00251 }; 00252 00253 } 00254 00255 class Topologies 00256 { 00257 public: 00258 template<int DIM> 00259 class Cube 00260 { 00261 public: 00262 typedef TopologiesHelpers::Topology<DIM, false, false, false> Topology; 00263 }; 00264 00265 template<int DIM> 00266 class Torus 00267 { 00268 public: 00269 typedef TopologiesHelpers::Topology<DIM, true, true, true> Topology; 00270 }; 00271 }; 00272 00273 } 00274 00275 #endif