ViennaGrid - The Vienna Grid Library  2.1.0
viennagrid/point.hpp
Go to the documentation of this file.
00001 #ifndef VIENNAGRID_POINT_HPP
00002 #define VIENNAGRID_POINT_HPP
00003 
00004 /* =======================================================================
00005    Copyright (c) 2011-2014, Institute for Microelectronics,
00006                             Institute for Analysis and Scientific Computing,
00007                             TU Wien.
00008 
00009                             -----------------
00010                      ViennaGrid - The Vienna Grid Library
00011                             -----------------
00012 
00013    License:      MIT (X11), see file LICENSE in the base directory
00014 ======================================================================= */
00015 
00016 
00017 #include <cmath>
00018 #include <assert.h>
00019 #include <stdexcept>
00020 #include <cstddef>
00021 #include <sstream>
00022 
00023 #include "viennagrid/forwards.hpp"
00024 
00025 #include "viennagrid/storage/static_array.hpp"
00026 
00031 namespace viennagrid
00032 {
00033   namespace result_of
00034   {
00036     template <typename PointType>
00037     struct dimension;
00038 
00040     template <typename CoordType, typename CoordinateSystem>
00041     struct dimension< spatial_point<CoordType, CoordinateSystem> >
00042     {
00043       static const int value = CoordinateSystem::dim;
00044     };
00045 
00046 
00048     template <typename PointType>
00049     struct coordinate_system
00050     {
00051       //by default, we don't know anything about the point type, so let's complain at compile time
00052       typedef typename PointType::ERROR_UNKNOWN_COORDINATE_SYSTEM_FOR_POINT_TYPE    type;
00053     };
00054 
00056     template <typename CoordType, typename CoordinateSystem>
00057     struct coordinate_system< spatial_point<CoordType, CoordinateSystem> >
00058     {
00059       typedef CoordinateSystem    type;
00060     };
00061 
00062 
00064     template <typename PointType>
00065     struct static_size;
00066 
00068     template <typename CoordType, typename CoordinateSystem>
00069     struct static_size< spatial_point<CoordType, CoordinateSystem> >
00070     {
00071       static const int value = CoordinateSystem::dim;
00072     };
00073 
00074   }
00075 
00077   template <typename PointType>
00078   std::size_t dynamic_size(PointType const & p)
00079   {
00080     return p.size();
00081   }
00082 
00083   template <int d>
00084   struct dim_dispatcher;
00085 
00091   template <typename FromPointType,
00092             typename ToPointType,
00093             typename FromCoordinateSystem = typename result_of::coordinate_system<FromPointType>::type,
00094             typename ToCoordinateSystem = typename result_of::coordinate_system<ToPointType>::type
00095            >
00096   class coordinate_converter
00097   {
00098   public:
00100     ToPointType operator()(FromPointType const &)
00101     {
00102       typename FromPointType::ERROR_COORDINATE_SYSTEM_UNKNOWN   error_object;
00103       (void)error_object;
00104     }
00105   };
00106 
00107 
00109   template <typename FromPointType,
00110             typename ToPointType>
00111   class coordinate_converter<FromPointType, ToPointType, cartesian_cs<2>, polar_cs>
00112   {
00113   public:
00114     ToPointType operator()(FromPointType const & p_in)
00115     {
00116       ToPointType ret;
00117       ret[0] = sqrt(p_in[0] * p_in[0] + p_in[1] * p_in[1]);
00118       ret[1] = atan2(p_in[1], p_in[0]);
00119       return ret;
00120     }
00121   };
00122 
00124   template <typename FromPointType,
00125             typename ToPointType>
00126   class coordinate_converter<FromPointType, ToPointType, cartesian_cs<3>, spherical_cs>
00127   {
00128   public:
00129     ToPointType operator()(FromPointType const & p_in)
00130     {
00131       ToPointType ret;
00132       ret[0] = sqrt(p_in[0] * p_in[0] + p_in[1] * p_in[1] + p_in[2] * p_in[2]);
00133       ret[1] = (std::fabs(ret[0]) > 0) ? acos(p_in[2] / ret[0]) : 0;
00134       ret[2] = atan2(p_in[1], p_in[0]);
00135       return ret;
00136     }
00137   };
00138 
00140   template <typename FromPointType,
00141             typename ToPointType>
00142   class coordinate_converter<FromPointType, ToPointType, cartesian_cs<3>, cylindrical_cs>
00143   {
00144   public:
00145     ToPointType operator()(FromPointType const & p_in)
00146     {
00147       ToPointType ret;
00148       ret[0] = sqrt(p_in[0] * p_in[0] + p_in[1] * p_in[1]);
00149       ret[1] = atan2(p_in[1], p_in[0]);
00150       ret[2] = p_in[2];
00151       return ret;
00152     }
00153   };
00154 
00155   namespace result_of
00156   {
00158     template <typename PointType>
00159     struct cartesian_point
00160     {
00161       typedef viennagrid::spatial_point<typename result_of::coord<PointType>::type,
00162                                   viennagrid::cartesian_cs<viennagrid::result_of::static_size<PointType>::value>
00163                                  >                    type;
00164     };
00165 
00166   }
00167 
00169   template <typename PointType, typename CoordinateSystem>
00170   typename result_of::cartesian_point<PointType>::type
00171   to_cartesian_impl(PointType const & p, CoordinateSystem const &)
00172   {
00173     typedef typename result_of::cartesian_point<PointType>::type CartesianPointType;
00174 
00175     return coordinate_converter<PointType, CartesianPointType>()(p);
00176   }
00177 
00178 
00180   template <typename FromPointType,
00181             typename ToPointType>
00182   class coordinate_converter<FromPointType, ToPointType, polar_cs, cartesian_cs<2> >
00183   {
00184   public:
00185     ToPointType operator()(FromPointType const & p_in)
00186     {
00187       ToPointType ret;
00188       ret[0] = p_in[0] * cos(p_in[1]);
00189       ret[1] = p_in[0] * sin(p_in[1]);
00190       return ret;
00191     }
00192   };
00193 
00194 
00196   template <typename FromPointType,
00197             typename ToPointType>
00198   class coordinate_converter<FromPointType, ToPointType, spherical_cs, cartesian_cs<3> >
00199   {
00200   public:
00201     ToPointType operator()(FromPointType const & p_in)
00202     {
00203       ToPointType ret;
00204       ret[0] = p_in[0] * sin(p_in[1]) * cos(p_in[2]);
00205       ret[1] = p_in[0] * sin(p_in[1]) * sin(p_in[2]);
00206       ret[2] = p_in[0] * cos(p_in[1]);
00207       return ret;
00208     }
00209   };
00210 
00212   template <typename FromPointType,
00213             typename ToPointType>
00214   class coordinate_converter<FromPointType, ToPointType, spherical_cs, cylindrical_cs>
00215   {
00216   public:
00217     ToPointType operator()(FromPointType const & p_in)
00218     {
00219       ToPointType ret;
00220       ret[0] = p_in[0] * sin(p_in[1]);                 //rho
00221       ret[1] = p_in[2];                                //phi
00222       ret[2] = p_in[0] * cos(p_in[1]);                 //z
00223       return ret;
00224     }
00225   };
00226 
00227 
00229   template <typename FromPointType,
00230             typename ToPointType>
00231   class coordinate_converter<FromPointType, ToPointType, cylindrical_cs, cartesian_cs<3> >
00232   {
00233   public:
00234     ToPointType operator()(FromPointType const & p_in)
00235     {
00236       ToPointType ret;
00237       ret[0] = p_in[0] * cos(p_in[1]);
00238       ret[1] = p_in[0] * sin(p_in[1]);
00239       ret[2] = p_in[2];
00240       return ret;
00241     }
00242   };
00243 
00245   template <typename FromPointType,
00246             typename ToPointType>
00247   class coordinate_converter<FromPointType, ToPointType, cylindrical_cs, spherical_cs>
00248   {
00249   public:
00250     ToPointType operator()(FromPointType const & p_in)
00251     {
00252       ToPointType ret;
00253       ret[0] = sqrt(p_in[0] * p_in[0] + p_in[2] * p_in[2]);
00254       ret[1] = (std::fabs(ret[0]) > 0) ? acos(p_in[2] / ret[0]) : 0;
00255       ret[2] = p_in[1];
00256       return ret;
00257     }
00258   };
00259 
00260   /********************* CoordinateSystem *****************/
00261 
00263   template <int d>
00264   struct cartesian_cs
00265   {
00266     static const int dim = d;
00267 
00269     template <typename PointType>
00270     static PointType add(PointType const & p1, PointType const & p2)
00271     {
00272       assert(p1.size() == p2.size());
00273 
00274       PointType ret;
00275       typedef typename PointType::size_type      size_type;
00276       for (size_type i=0; i<ret.size(); ++i)
00277         ret[i] = p1[i] + p2[i];
00278       return ret;
00279     }
00280 
00282     template <typename PointType>
00283     static void inplace_add(PointType & p1, PointType const & p2)
00284     {
00285       assert(p1.size() == p2.size());
00286 
00287       typedef typename PointType::size_type      size_type;
00288       for (size_type i=0; i<p1.size(); ++i)
00289         p1[i] += p2[i];
00290     }
00291 
00293     template <typename PointType>
00294     static PointType subtract(PointType const & p1, PointType const & p2)
00295     {
00296       typedef typename PointType::size_type      size_type;
00297       assert(p1.size() == p2.size());
00298 
00299       PointType ret;
00300       for (size_type i=0; i<ret.size(); ++i)
00301         ret[i] = p1[i] - p2[i];
00302       return ret;
00303     }
00304 
00306     template <typename PointType>
00307     static void inplace_subtract(PointType & p1, PointType const & p2)
00308     {
00309       typedef typename PointType::size_type      size_type;
00310       assert(p1.size() == p2.size());
00311 
00312       for (size_type i=0; i<p1.size(); ++i)
00313         p1[i] -= p2[i];
00314     }
00315 
00317     template <typename PointType>
00318     static PointType & inplace_stretch(PointType & p1, typename result_of::coord<PointType>::type factor)
00319     {
00320       typedef typename PointType::size_type      size_type;
00321       for (size_type i=0; i<p1.size(); ++i)
00322         p1[i] *= factor;
00323       return p1;
00324     }
00325 
00326   };
00327 
00329   template <typename PointType, int d>
00330   PointType const &
00331   to_cartesian_impl(PointType const & p, cartesian_cs<d>)
00332   {
00333     return p;
00334   }
00335 
00337   template <typename PointType, int d>
00338   PointType &
00339   to_cartesian_impl(PointType & p, cartesian_cs<d>)
00340   {
00341     return p;
00342   }
00343 
00344 
00345   //public interface
00349   template <typename PointType>
00350   typename result_of::cartesian_point<PointType>::type
00351   to_cartesian(PointType const & p)
00352   {
00353     return to_cartesian_impl(p, typename result_of::coordinate_system<PointType>::type());
00354   }
00355 
00356 
00357 
00359   template <typename CSystem>
00360   struct cs_base
00361   {
00363     template <typename PointType>
00364     static PointType add(PointType const & p1, PointType const & p2)
00365     {
00366       static const int DIM = viennagrid::result_of::static_size<PointType>::value;
00367 
00368       typedef spatial_point<typename PointType::value_type,
00369                       cartesian_cs<DIM>
00370                      >      CartesianPointType;
00371 
00372       assert(p1.size() == p2.size());
00373 
00374       coordinate_converter<PointType, CartesianPointType,
00375                           CSystem, cartesian_cs<DIM> >  cs_to_cartesian;
00376       coordinate_converter<CartesianPointType, PointType,
00377                            cartesian_cs<DIM>, CSystem>  cartesian_to_cs;
00378 
00379       CartesianPointType cs1 = cs_to_cartesian(p1);
00380       CartesianPointType cs2 = cs_to_cartesian(p2);
00381       CartesianPointType cs_ret = cartesian_cs<DIM>::add(cs1, cs2);
00382       PointType ret = cartesian_to_cs(cs_ret);
00383 
00384       return ret;
00385     }
00386 
00388     template <typename PointType>
00389     static void inplace_add(PointType & p1, PointType const & p2)
00390     {
00391       static const int DIM = viennagrid::result_of::static_size<PointType>::value;
00392 
00393       typedef spatial_point<typename PointType::value_type,
00394                       cartesian_cs<DIM>
00395                      >      CartesianPointType;
00396 
00397       assert(p1.size() == p2.size());
00398 
00399       coordinate_converter<PointType, CartesianPointType, CSystem, cartesian_cs<DIM> >  cs_to_cartesian;
00400       coordinate_converter<CartesianPointType, PointType, cartesian_cs<DIM>, CSystem>  cartesian_to_cs;
00401 
00402       CartesianPointType cs1 = cs_to_cartesian(p1);
00403       CartesianPointType cs2 = cs_to_cartesian(p2);
00404       cartesian_cs<DIM>::inplace_add(cs1, cs2);
00405       p1 = cartesian_to_cs(cs1);
00406     }
00407 
00409     template <typename PointType>
00410     static PointType subtract(PointType const & p1, PointType const & p2)
00411     {
00412       static const int DIM = viennagrid::result_of::static_size<PointType>::value;
00413 
00414       typedef spatial_point<typename PointType::value_type,
00415                       cartesian_cs<DIM>
00416                      >      CartesianPointType;
00417 
00418       assert(p1.size() == p2.size());
00419 
00420       coordinate_converter<PointType, CartesianPointType, CSystem, cartesian_cs<DIM> >  cs_to_cartesian;
00421       coordinate_converter<CartesianPointType, PointType, cartesian_cs<DIM>, CSystem>  cartesian_to_cs;
00422 
00423       CartesianPointType cs1 = cs_to_cartesian(p1);
00424       CartesianPointType cs2 = cs_to_cartesian(p2);
00425       CartesianPointType cs_ret = cartesian_cs<DIM>::subtract(cs1, cs2);
00426       PointType ret = cartesian_to_cs(cs_ret);
00427 
00428       return ret;
00429     }
00430 
00432     template <typename PointType>
00433     static void inplace_subtract(PointType & p1, PointType const & p2)
00434     {
00435       static const int DIM = viennagrid::result_of::static_size<PointType>::value;
00436 
00437       typedef spatial_point<typename PointType::value_type,
00438                       cartesian_cs<DIM>
00439                      >      CartesianPointType;
00440 
00441       assert(p1.size() == p2.size());
00442 
00443       coordinate_converter<PointType, CartesianPointType, CSystem, cartesian_cs<DIM> >  cs_to_cartesian;
00444       coordinate_converter<CartesianPointType, PointType, cartesian_cs<DIM>, CSystem>  cartesian_to_cs;
00445 
00446       CartesianPointType cs1 = cs_to_cartesian(p1);
00447       CartesianPointType cs2 = cs_to_cartesian(p2);
00448       cartesian_cs<DIM>::inplace_subtract(cs1, cs2);
00449       p1 = cartesian_to_cs(cs1);
00450     }
00451   };
00452 
00454   struct polar_cs : public cs_base<polar_cs>
00455   {
00456     static const int dim = 2;
00457 
00458     template <typename PointType>
00459     static PointType & inplace_stretch(PointType & p1, typename result_of::coord<PointType>::type factor)
00460     {
00461       p1[0] *= factor;
00462       return p1;
00463     }
00464   };
00465 
00467   struct spherical_cs : public cs_base<spherical_cs>
00468   {
00469     static const int dim = 3;
00470 
00471     template <typename PointType>
00472     static PointType & inplace_stretch(PointType & p1, typename result_of::coord<PointType>::type factor)
00473     {
00474       p1[0] *= factor;
00475       return p1;
00476     }
00477   };
00478 
00480   struct cylindrical_cs : public cs_base<cylindrical_cs>
00481   {
00482     static const int dim = 3;
00483 
00485     template <typename PointType>
00486     static PointType & inplace_stretch(PointType & p1, typename result_of::coord<PointType>::type factor)
00487     {
00488       static const int DIM = viennagrid::result_of::static_size<PointType>::value;
00489 
00490       typedef spatial_point<typename PointType::value_type,
00491                       cartesian_cs<DIM>
00492                      >      CartesianPointType;
00493 
00494       coordinate_converter<PointType, CartesianPointType, cylindrical_cs, cartesian_cs<DIM> >  cs_to_cartesian;
00495       coordinate_converter<CartesianPointType, PointType, cartesian_cs<DIM>, cylindrical_cs>  cartesian_to_cs;
00496 
00497       CartesianPointType cs1 = cs_to_cartesian(p1);
00498       cartesian_cs<DIM>::inplace_stretch(cs1, factor);
00499       p1 = cartesian_to_cs(cs1);
00500       return p1;
00501     }
00502   };
00503 
00504 
00505 
00506 
00507   /***************************** Point Type ************************/
00508 
00510   class point_index_out_of_bounds_exception : public std::exception
00511   {
00512   public:
00513     point_index_out_of_bounds_exception(std::size_t i) : i_(i) {}
00514 
00515     virtual const char* what() const throw()
00516     {
00517       std::stringstream ss;
00518       ss << "Point index " << i_ << " out of bounds!";
00519       return ss.str().c_str();
00520     }
00521 
00522   private:
00523     std::size_t i_;
00524   };
00525 
00526 
00528   template <typename CoordType, int d>
00529   struct point_filler
00530   {
00531     static void apply(CoordType * coords, CoordType x, CoordType y, CoordType z)
00532     {
00533       coords[0] = x;
00534       coords[1] = y;
00535       coords[2] = z;
00536       for (int i=3; i<d; ++i)
00537         coords[i] = 0;
00538     }
00539   };
00540 
00542   template <typename CoordType>
00543   struct point_filler<CoordType, 1>
00544   {
00545     static void apply(CoordType * coords, CoordType x, CoordType, CoordType)
00546     {
00547       coords[0] = x;
00548     }
00549   };
00550 
00552   template <typename CoordType>
00553   struct point_filler<CoordType, 2>
00554   {
00555     static void apply(CoordType * coords, CoordType x, CoordType y, CoordType)
00556     {
00557       coords[0] = x;
00558       coords[1] = y;
00559     }
00560   };
00561 
00563   template <typename CoordType>
00564   struct point_filler<CoordType, 3>
00565   {
00566     static void apply(CoordType * coords, CoordType x, CoordType y, CoordType z)
00567     {
00568       coords[0] = x;
00569       coords[1] = y;
00570       coords[2] = z;
00571     }
00572   };
00573 
00574 
00575 
00581   template <typename CoordType, typename CoordinateSystem>
00582   class spatial_point : public static_array<CoordType, CoordinateSystem::dim>
00583   {
00584   public:
00586     typedef CoordType       value_type;
00588     typedef dim_type        size_type;
00589 
00590 
00592     static const int dim = CoordinateSystem::dim;
00593 
00595     spatial_point()
00596     {
00597       point_filler<CoordType, dim>::apply( &(*this)[0], 0, 0, 0);  //make sure that there is no bogus in the coords-array
00598     }
00599 
00601     spatial_point(CoordType x, CoordType y = 0, CoordType z = 0)
00602     {
00603       point_filler<CoordType, dim>::apply( &(*this)[0], x, y, z);
00604     }
00605 
00607     template <typename CoordType2, typename CoordinateSystem2>
00608     spatial_point(spatial_point<CoordType2, CoordinateSystem2> const & p2)
00609     {
00610       *this = coordinate_converter<spatial_point<CoordType2, CoordinateSystem2>, spatial_point>()(p2);
00611     }
00612 
00613 
00615     template <typename CoordType2, typename CoordinateSystem2>
00616     spatial_point & operator=(spatial_point<CoordType2, CoordinateSystem2> const & p2)
00617     {
00618       *this = coordinate_converter<spatial_point<CoordType2, CoordinateSystem2>, spatial_point>()(p2);
00619       return *this;
00620     }
00621 
00622     //
00623     // operators:
00624     //
00625 
00627     spatial_point operator-() const
00628     {
00629       return spatial_point() - *this;
00630     }
00631 
00632     //with point:
00634     spatial_point operator+(spatial_point const & other) const
00635     {
00636       return CoordinateSystem::add(*this, other);
00637     }
00638 
00640     spatial_point & operator+=(spatial_point const & other)
00641     {
00642       CoordinateSystem::inplace_add(*this, other);
00643       return *this;
00644     }
00645 
00647     spatial_point operator-(spatial_point const & other) const
00648     {
00649       return CoordinateSystem::subtract(*this, other);
00650     }
00651 
00653     spatial_point & operator-=(spatial_point const & other)
00654     {
00655       CoordinateSystem::inplace_subtract(*this, other);
00656       return *this;
00657     }
00658 
00659 
00660     //with CoordType
00662     spatial_point & operator*=(CoordType factor)
00663     {
00664       CoordinateSystem::inplace_stretch(*this, factor);
00665       return *this;
00666     }
00667 
00669     spatial_point & operator/=(CoordType factor)
00670     {
00671       CoordinateSystem::inplace_stretch(*this, 1.0 / factor);
00672       return *this;
00673     }
00674 
00676     spatial_point operator*(CoordType factor) const
00677     {
00678       spatial_point ret(*this);
00679       return CoordinateSystem::inplace_stretch(ret, factor);
00680     }
00681 
00683     spatial_point operator/(CoordType factor) const
00684     {
00685       spatial_point ret(*this);
00686       return CoordinateSystem::inplace_stretch(ret, 1.0 / factor);
00687     }
00688 
00689   };
00690 
00691 
00693   template<typename CoordType, typename CoordinateSystem>
00694   spatial_point<CoordType, CoordinateSystem> min(const spatial_point<CoordType, CoordinateSystem> & p1, const spatial_point<CoordType, CoordinateSystem> & p2)
00695   {
00696     spatial_point<CoordType, CoordinateSystem> tmp;
00697     for (std::size_t i = 0; i < spatial_point<CoordType, CoordinateSystem>::dim; ++i)
00698       tmp[i] = std::min(p1[i], p2[i]);
00699     return tmp;
00700   }
00701 
00703   template<typename CoordType, typename CoordinateSystem>
00704   spatial_point<CoordType, CoordinateSystem> max(const spatial_point<CoordType, CoordinateSystem> & p1, const spatial_point<CoordType, CoordinateSystem> & p2)
00705   {
00706     spatial_point<CoordType, CoordinateSystem> tmp;
00707     for (std::size_t i = 0; i < spatial_point<CoordType, CoordinateSystem>::dim; ++i)
00708       tmp[i] = std::max(p1[i], p2[i]);
00709     return tmp;
00710   }
00711 
00712 
00714   template <typename CoordType, typename CoordinateSystem>
00715   spatial_point<CoordType, CoordinateSystem>
00716   operator*(double val, spatial_point<CoordType, CoordinateSystem> const & p)
00717   {
00718     return p * val;
00719   }
00720 
00722   template <typename CoordType, typename CoordinateSystem>
00723   std::ostream& operator << (std::ostream & os, spatial_point<CoordType, CoordinateSystem> const & p)
00724   {
00725     typedef typename spatial_point<CoordType, CoordinateSystem>::size_type      size_type;
00726     os << "(";
00727     for (size_type i=0; i<static_cast<size_type>(CoordinateSystem::dim); ++i)
00728       os << p[i] << (i == static_cast<size_type>(CoordinateSystem::dim)-1 ? "" :" ");
00729     os << ")";
00730     return os;
00731   }
00732 
00733 
00735   struct point_less
00736   {
00737     template <typename PointType>
00738     bool operator()(PointType const & p1, PointType const & p2) const
00739     {
00740       for (std::size_t i=0; i<p1.size(); ++i)
00741       {
00742         if (p1[i] < p2[i])
00743           return true;
00744         else if (p1[i] > p2[i])
00745           return false;
00746       }
00747       return false;
00748     }
00749   };
00750 
00751   namespace result_of
00752   {
00754     template<typename CoordType, typename CoordinateSystem>
00755     struct point< spatial_point<CoordType, CoordinateSystem> >
00756     {
00757       typedef spatial_point<CoordType, CoordinateSystem> type;
00758     };
00759 
00760     template<typename CoordType, typename CoordinateSystem>
00761     struct coord< spatial_point<CoordType, CoordinateSystem> >
00762     {
00763       typedef CoordType type;
00764     };
00765 
00766     template<typename CoordType, typename CoordinateSystem>
00767     struct geometric_dimension< spatial_point<CoordType, CoordinateSystem> >
00768     {
00769       static const int value = spatial_point<CoordType, CoordinateSystem>::dim;
00770     };
00772   }
00773 
00774 }
00775 #endif