HyperspaceExplorer 0.7.1
|
00001 /* 00002 Hyperspace Explorer - visualizing higher-dimensional geometry 00003 Copyright (C) 2009-2010 Lene Preuss <lene.preuss@gmail.com> 00004 00005 This program is free software; you can redistribute it and/or modify 00006 it under the terms of the GNU General Public License as published by 00007 the Free Software Foundation; either version 2 of the License, or 00008 (at your option) any later version. 00009 00010 This program is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 GNU General Public License for more details. 00014 00015 You should have received a copy of the GNU General Public License along 00016 with this program; if not, write to the Free Software Foundation, Inc., 00017 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 00018 00019 */ 00020 00021 #ifndef ROTATE_H 00022 #define ROTATE_H 00023 00024 #include "Rotope.h" 00025 00026 #include "MultiDimensionalVector.h" 00027 00029 00033 template <unsigned D> 00034 class rotate_base: public VertexData<D> { 00035 00036 public: 00038 rotate_base(const VertexData<D> &v): VertexData<D>(v) { } 00039 00041 void rotate(unsigned d); 00042 00043 private: 00045 void checkRotationArguments(unsigned d); 00046 00048 VecMath::Vector<D> rotate_vertex(const VecMath::Vector<D> &, double, 00049 unsigned, unsigned); 00051 void rotate_line(unsigned); 00053 void rotate_triangle(unsigned, const VecMath::MultiDimensionalVector<unsigned, 1> &); 00055 void rotate_quad(unsigned, const VecMath::MultiDimensionalVector<unsigned, 1> &); 00057 void rotate_polygon(unsigned, const VecMath::MultiDimensionalVector<unsigned, 1> &); 00058 }; 00059 00061 00091 template <unsigned D, unsigned Dmin, unsigned Dmax> 00092 class Rotate: public Rotate<D, Dmin, Dmax-1> { 00093 public: 00095 00101 Rotate(const VertexData<D> &v): Rotate<D, Dmin, Dmax-1>(v) { 00102 rotate_base<D>::rotate(Dmax); 00103 } 00104 00105 }; 00106 00108 00114 template <unsigned D, unsigned Dmin> 00115 class Rotate<D, Dmin, Dmin>: public rotate_base<D> { 00116 public: 00118 00123 Rotate(const VertexData<D> &v): rotate_base<D>(v) { 00124 rotate_base<D>::rotate(Dmin); 00125 } 00126 00127 }; 00128 00139 template <unsigned D> void rotate_base<D>::rotate(unsigned d) { 00140 # if DEBUG_ROTOPES 00141 SingletonLog::Instance().log(__PRETTY_FUNCTION__); 00142 # endif 00143 00144 checkRotationArguments(d); 00145 00146 std::vector<VecMath::Vector<D> > Xold = VertexData<D>::raw_vertices(); 00147 for (unsigned i = 1; i <= RotopeInterface::_numSegments; ++i) { 00148 double rot = 1.*i*M_PI/RotopeInterface::_numSegments; 00149 for (typename std::vector<VecMath::Vector<D> >::iterator j = Xold.begin(); 00150 j != Xold.end(); ++j) { 00151 VertexData<D>::raw_vertices().push_back(rotate_vertex(*j, rot, d, d-1)); 00152 } 00153 } 00154 00155 VertexData<D>::dimension()++; // object is now one dimension higher 00156 00157 VertexData<D>::realm() = VertexData<D>::realm().rotated(RotopeInterface::_numSegments, Xold.size()); 00158 } 00159 00160 template <unsigned D> void rotate_base<D>::checkRotationArguments(unsigned d) { 00161 if (d >= D) { 00162 throw std::invalid_argument( 00163 "rotate_base::rotate() called on a higher dimension" 00164 " than the vector space allows"); 00165 } 00166 if (d == 0) { 00167 throw std::invalid_argument( 00168 "rotate_base::rotate() must be called on an object of dimension" 00169 " at least 1"); 00170 } 00171 } 00172 00178 template <unsigned D> VecMath::Vector<D> rotate_base<D>::rotate_vertex( 00179 const VecMath::Vector<D> &v, double rot, 00180 unsigned new_axis, unsigned old_axis) { 00181 # if DEBUG_ROTOPES >= 2 00182 SingletonLog::Instance().log(__PRETTY_FUNCTION__); 00183 # endif 00184 VecMath::Vector<D> v_new(v); 00185 v_new[new_axis] = v_new[old_axis]*sin(rot); 00186 v_new[old_axis] *= cos(rot); 00187 return v_new; 00188 } 00189 00193 template <unsigned D> void rotate_base<D>::rotate_line(unsigned d) { 00194 # if DEBUG_ROTOPES 00195 SingletonLog::Instance().log(__PRETTY_FUNCTION__); 00196 # endif 00197 VecMath::MultiDimensionalVector<unsigned, 1> new_surface; // defines the disk 00198 new_surface.push_back(0); 00199 VertexData<D>::raw_vertices().pop_back(); 00200 for (unsigned i = 1; i <= RotopeInterface::_numSegments; ++i) { 00201 double rot = 2.*i*M_PI/RotopeInterface::_numSegments; 00202 VecMath::Vector<D> current = VertexData<D>::raw_vertices()[0]; 00203 VecMath::Vector<D> rotated_current = rotate_vertex(current, rot, 00204 d, d-1); 00205 VertexData<D>::raw_vertices().push_back(rotated_current); 00206 new_surface.push_back(VertexData<D>::raw_vertices().size()-1); 00207 } 00208 VertexData<D>::surface().push_back(new_surface); 00209 } 00210 00215 template <unsigned D> void rotate_base<D>::rotate_triangle( 00216 unsigned d, const VecMath::MultiDimensionalVector<unsigned, 1> ¤t_surface) { 00217 00218 # if DEBUG_ROTOPES 00219 SingletonLog::Instance().log(__PRETTY_FUNCTION__); 00220 # endif 00221 VecMath::MultiDimensionalVector<unsigned, 1> new_surface; // defines the first cap 00222 new_surface.push_back(current_surface[0]); 00223 00224 unsigned old_current = 0; 00229 for (unsigned i = 1; i <= RotopeInterface::_numSegments; ++i) { 00230 00231 double rot = 2.*i*M_PI/RotopeInterface::_numSegments; 00232 00233 unsigned cur_index = current_surface[0], 00234 next_index = current_surface[2]; 00235 00236 VecMath::Vector<D> current = VertexData<D>::raw_vertices()[cur_index]; 00237 VecMath::Vector<D> next = VertexData<D>::raw_vertices()[next_index]; 00238 VecMath::Vector<D> rotated_current = rotate_vertex(current, rot, 00239 d, d-2); 00240 00242 VertexData<D>::raw_vertices().push_back(rotated_current); 00243 00245 new_surface.push_back(VertexData<D>::raw_vertices().size()-1); 00246 00248 VertexData<D>::addSurface(old_current, next_index, 00249 VertexData<D>::raw_vertices().size()-1); 00250 00251 old_current = VertexData<D>::raw_vertices().size()-1; 00252 } 00254 VertexData<D>::addSurface(new_surface); 00255 } 00256 00261 template <unsigned D> void rotate_base<D>::rotate_quad( 00262 unsigned d, const VecMath::MultiDimensionalVector<unsigned, 1> ¤t_surface) { 00263 # if DEBUG_ROTOPES 00264 SingletonLog::Instance().log(__PRETTY_FUNCTION__); 00265 # endif 00266 unsigned old_current = current_surface[0]; // saved index to current vertex 00267 unsigned old_next = current_surface[1]; // saved index to next vertex 00268 00269 VecMath::MultiDimensionalVector<unsigned, 1> bottom; // defines the first ("bottom") cap 00271 bottom.push_back(current_surface[0]); 00276 VecMath::MultiDimensionalVector<unsigned, 1> top; // defines the second ("top") cap 00277 top.push_back(current_surface[2]); 00278 00284 for (unsigned i = 1; i <= RotopeInterface::_numSegments; ++i) { 00285 00286 double rot = 2.*i*M_PI/RotopeInterface::_numSegments; 00287 00288 unsigned cur_index = current_surface[0]; 00289 unsigned next_index = current_surface[1]; 00290 00291 VecMath::Vector<D> current = VertexData<D>::raw_vertices()[cur_index]; 00292 VecMath::Vector<D> next = VertexData<D>::raw_vertices()[next_index]; 00293 00295 VecMath::Vector<D> rotated_current = rotate_vertex(current, rot, d, d-1); 00296 VecMath::Vector<D> rotated_next = rotate_vertex(next, rot, d, d-1); 00297 00298 VertexData<D>::raw_vertices().push_back(rotated_current); 00299 VertexData<D>::raw_vertices().push_back(rotated_next); 00300 00302 VertexData<D>::addSurface(old_current, old_next, 00303 VertexData<D>::raw_vertices().size()-1, 00304 VertexData<D>::raw_vertices().size()-2); 00305 00307 old_current = VertexData<D>::raw_vertices().size()-2; 00308 old_next = VertexData<D>::raw_vertices().size()-1; 00309 00311 bottom.push_back(VertexData<D>::raw_vertices().size()-2); 00312 top.push_back(VertexData<D>::raw_vertices().size()-1); 00313 } 00315 VertexData<D>::addSurface(bottom); 00316 VertexData<D>::addSurface(top); 00317 } 00318 00323 template <unsigned D> void rotate_base<D>::rotate_polygon( 00324 unsigned d, const VecMath::MultiDimensionalVector<unsigned, 1> ¤t_surface) { 00325 # if DEBUG_ROTOPES 00326 SingletonLog::Instance().log(__PRETTY_FUNCTION__); 00327 # endif 00328 00329 unsigned offset = 0; 00330 00331 VertexData<D>::raw_vertices().push_back(VertexData<D>::raw_vertices()[current_surface[0]]); 00332 00334 for (unsigned i = 1; i <= (RotopeInterface::_numSegments+1)/2; ++i) { 00335 00336 double rot = 1.*i*M_PI/((RotopeInterface::_numSegments+1)/2); 00337 00338 for (unsigned j = 0; j < current_surface.size(); j++) { 00339 00340 unsigned cur_index = j+offset; 00341 00342 unsigned next_index = j+1+offset; 00343 00344 VecMath::Vector<D> current = VertexData<D>::raw_vertices()[cur_index-offset]; 00345 VecMath::Vector<D> next = VertexData<D>::raw_vertices()[next_index-offset]; 00346 VecMath::Vector<D> rotated_current = rotate_vertex(current, rot, 00347 d, d-1); 00348 VecMath::Vector<D> rotated_next = rotate_vertex(next, rot, d, d-1); 00349 00351 VertexData<D>::raw_vertices().push_back(rotated_next); 00352 # if DEBUG_ROTOPES >= 2 00353 std::cerr << "j: " << j << "offset: " << offset 00354 << " cur_index: " << cur_index << " next_index: " << next_index 00355 << " size: " << VertexData<D>::raw_vertices().size() << "\n"; 00356 # endif 00357 VertexData<D>::addSurface(cur_index, next_index, 00358 VertexData<D>::raw_vertices().size()-1, 00359 VertexData<D>::raw_vertices().size()-2); 00360 00361 } 00363 offset += current_surface.size(); 00364 } 00365 } 00366 00367 #endif