Ignore:
Timestamp:
Aug 20, 2014, 1:04:08 PM (11 years ago)
Author:
Frederik Heber <heber@…>
Children:
0ae114
Parents:
d734ff
git-author:
Frederik Heber <heber@…> (06/05/14 17:16:26)
git-committer:
Frederik Heber <heber@…> (08/20/14 13:04:08)
Message:

Implemented rotations via boost::quaternions.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/Fragmentation/Exporters/SphericalPointDistribution.cpp

    rd734ff r2d50a2  
    4343
    4444#include <algorithm>
     45#include <boost/math/quaternion.hpp>
    4546#include <cmath>
    4647#include <functional>
     
    222223}
    223224
    224 /** Convert cartesian to polar coordinates.
    225  *
    226  * \param _cartesian vector in cartesian coordinates
    227  * \return vector containing \f$ (r,\theta, \varphi \f$ tuple for polar coordinates
    228  */
    229 std::vector<double> getPolarCoordinates(const Vector &_cartesian)
    230 {
    231   std::vector<double> polar(3,0.);
    232   const double xsqr = _cartesian[0] * _cartesian[0];
    233   const double ysqr = _cartesian[1] * _cartesian[1];
    234   polar[0] = sqrt(xsqr + ysqr + _cartesian[2]*_cartesian[2]);
    235   if (fabs(_cartesian[2]) < std::numeric_limits<double>::epsilon()*1e4) {
    236     if (fabs(xsqr + ysqr) < std::numeric_limits<double>::epsilon()*1e4) {
    237       polar[1] = 0.;
    238     } else {
    239       // xsqr + ysqr is always non-negative
    240       polar[1] = M_PI/2.;
    241     }
    242   } else {
    243     polar[1] = atan( sqrt(xsqr + ysqr)/_cartesian[2]);
    244     if (_cartesian[2] <= -std::numeric_limits<double>::epsilon()*1e4)
    245       polar[1] += M_PI;
    246   }
    247 
    248   if (fabs(_cartesian[0]) < std::numeric_limits<double>::epsilon()*1e4) {
    249     if (fabs(_cartesian[1]) < std::numeric_limits<double>::epsilon()*1e4) {
    250       polar[2] = 0.;
    251     } else if (_cartesian[1] > std::numeric_limits<double>::epsilon()*1e4) {
    252       polar[2] = M_PI/2.;
    253     } else {
    254       polar[2] = -M_PI/2.;
    255     }
    256   } else {
    257     polar[2] = atan ( _cartesian[1]/_cartesian[0] );
    258     if (_cartesian[0] <= -std::numeric_limits<double>::epsilon()*1e4)
    259       polar[2] += M_PI;
    260   }
    261   return polar;
    262 }
    263 
    264 /** Calculate cartesian coordinates from given polar ones.
    265  *
    266  * \param _polar vector with polar coordinates
    267  * \return cartesian coordinates
    268  */
    269 Vector getCartesianCoordinates(const std::vector<double> &_polar)
    270 {
    271   Vector cartesian;
    272   ASSERT( _polar.size() == 3,
    273       "convertToCartesianCoordinates() - tuples has insufficient components.");
    274   cartesian[0] = _polar[0] * sin(_polar[1]) * cos(_polar[2]);
    275   cartesian[1] = _polar[0] * sin(_polar[1]) * sin(_polar[2]);
    276   cartesian[2] = _polar[0] * cos(_polar[1]);
    277   return cartesian;
    278 }
    279 
    280225/** Rotates a given polygon around x, y, and z axis by the given angles.
    281226 *
    282227 * \param _polygon polygon whose points to rotate
    283  * \param _angles vector with rotation angles for x,y,z axis
     228 * \param _q quaternion specifying the rotation of the coordinate system
    284229 */
    285230SphericalPointDistribution::Polygon_t rotatePolygon(
    286231    const SphericalPointDistribution::Polygon_t &_polygon,
    287     const std::vector<double> &_angles)
     232    const boost::math::quaternion<double> &_q)
    288233{
    289234  SphericalPointDistribution::Polygon_t rotated_polygon = _polygon;
    290   RealSpaceMatrix rotation;
    291   ASSERT( _angles.size() == 3,
    292       "rotatePolygon() - not exactly "+toString(3)+" components given.");
     235  boost::math::quaternion<double> q_inverse =
     236      boost::math::conj(_q)/(boost::math::norm(_q));
    293237
    294238  // apply rotation angles
    295239  for (SphericalPointDistribution::Polygon_t::iterator iter = rotated_polygon.begin();
    296240      iter != rotated_polygon.end(); ++iter) {
    297     // transform to polar
    298     std::vector<double> polar = getPolarCoordinates(*iter);
    299     LOG(5, "DEBUG: Converting " << *iter << " to " << polar);
    300     // sum up difference
    301     std::transform(
    302         _angles.begin(), _angles.end(),
    303         polar.begin(),
    304         polar.begin(),
    305         std::plus<double>());
    306     // convert back
    307     *iter = getCartesianCoordinates(polar);
    308     LOG(5, "DEBUG: Converting modified " << polar << " to " << *iter);
     241    Vector &current = *iter;
     242    boost::math::quaternion<double> p(0, current[0], current[1], current[2]);
     243    p = _q * p * q_inverse;
     244    LOG(5, "DEBUG: Rotated point is " << p);
     245    // i have no idea why but first component comes up with wrong sign
     246    current[0] = -p.R_component_2();
     247    current[1] = p.R_component_3();
     248    current[2] = p.R_component_4();
    309249  }
    310250
     
    349289    // determine rotation angles to align the two point distributions with
    350290    // respect to bestmatching
    351     std::vector<double> angles(NDIM);
    352     Vector newCenter;
     291    SphericalPointDistribution::Polygon_t rotated_newpolygon;
    353292    Vector oldCenter;
    354293    {
    355294      // calculate center of triangle/line/point consisting of first points of matching
     295      Vector newCenter;
    356296      IndexList_t::const_iterator iter = MCS.bestmatching.begin();
    357297      unsigned int i = 0;
     
    364304      LOG(4, "DEBUG: oldCenter is " << oldCenter << ", newCenter is " << newCenter);
    365305
    366       // transform to polar coordinates and note difference in angular parts
    367       std::vector<double> oldpolar = getPolarCoordinates(oldCenter);
    368       std::vector<double> newpolar = getPolarCoordinates(newCenter);
    369       std::vector<double> differencepolar;
    370       std::transform(
    371           oldpolar.begin(), oldpolar.end(),
    372           newpolar.begin(),
    373           std::back_inserter(differencepolar),
    374           std::minus<double>());
    375       LOG(3, "INFO: (r,theta,phi) angles are" << differencepolar);
    376     }
    377     // rotate _newpolygon
    378     SphericalPointDistribution::Polygon_t rotated_newpolygon =
    379         rotatePolygon(_newpolygon, angles);
    380     LOG(5, "DEBUG: Rotated new polygon is " << rotated_newpolygon);
    381 
     306      if ((oldCenter - newCenter).NormSquared() > std::numeric_limits<double>::epsilon()*1e4) {
     307        // setup quaternion
     308        Vector RotationAxis = newCenter;
     309        RotationAxis.VectorProduct(oldCenter);
     310        RotationAxis.Normalize();
     311        const double RotationAngle = oldCenter.Angle(newCenter)/(M_PI/2.);
     312//            RotationAxis.Angle(oldCenter) - RotationAxis.Angle(newCenter);
     313        boost::math::quaternion<double> q
     314            (RotationAngle, RotationAxis[0], RotationAxis[1], RotationAxis[2]);
     315        LOG(5, "DEBUG: RotationAxis is " << RotationAxis
     316            << ", RotationAngle is " << RotationAngle);
     317        LOG(5, "DEBUG: Quaternion describing rotation is " << q);
     318#ifndef NDEBUG
     319        {
     320        // check that rotation works in DEBUG mode
     321        boost::math::quaternion<double> p(0., newCenter[0], newCenter[1], newCenter[2]);
     322        boost::math::quaternion<double> q_inverse =
     323            boost::math::conj(q)/(boost::math::norm(q));
     324        p = q * p * q_inverse;
     325        boost::math::quaternion<double> identity(1,0,0,0);
     326        ASSERT( boost::math::norm(q*q_inverse - identity) < std::numeric_limits<double>::epsilon()*1e4,
     327            "matchSphericalPointDistributions() - quaternion does not rotate newCenter "
     328            +toString(q*q_inverse)+" into oldCenter "+toString(identity)+".");
     329        boost::math::quaternion<double> comparison(0., -oldCenter[0], oldCenter[1], oldCenter[2]);
     330        ASSERT( boost::math::norm(p - comparison) < std::numeric_limits<double>::epsilon()*1e4,
     331            "matchSphericalPointDistributions() - quaternion does not rotate newCenter "
     332            +toString(p)+" into oldCenter "+toString(comparison)+".");
     333        }
     334#endif
     335
     336        // rotate spherical distribution
     337        rotated_newpolygon = rotatePolygon(_newpolygon, q);
     338        LOG(5, "DEBUG: Rotated new polygon is " << rotated_newpolygon);
     339      } else {
     340        rotated_newpolygon = _newpolygon;
     341      }
     342    }
     343    // rotate triangle/line/point around itself to match orientation
    382344    const Line RotationAxis(zeroVec, oldCenter);
    383345    const double RotationAngle =
Note: See TracChangeset for help on using the changeset viewer.