Ignore:
Timestamp:
Sep 12, 2016, 11:48:34 PM (8 years ago)
Author:
Frederik Heber <heber@…>
Branches:
Action_Thermostats, Add_AtomRandomPerturbation, Add_FitFragmentPartialChargesAction, Add_RotateAroundBondAction, Add_SelectAtomByNameAction, Adding_Graph_to_ChangeBondActions, Adding_MD_integration_tests, Adding_StructOpt_integration_tests, Automaking_mpqc_open, AutomationFragmentation_failures, Candidate_v1.5.4, Candidate_v1.6.0, Candidate_v1.6.1, ChangeBugEmailaddress, ChangingTestPorts, ChemicalSpaceEvaluator, Combining_Subpackages, Debian_Package_split, Debian_package_split_molecuildergui_only, Disabling_MemDebug, Docu_Python_wait, EmpiricalPotential_contain_HomologyGraph, EmpiricalPotential_contain_HomologyGraph_documentation, Enable_parallel_make_install, Enhance_userguide, Enhanced_StructuralOptimization, Enhanced_StructuralOptimization_continued, Example_ManyWaysToTranslateAtom, Exclude_Hydrogens_annealWithBondGraph, FitPartialCharges_GlobalError, Fix_ChargeSampling_PBC, Fix_ChronosMutex, Fix_FitPartialCharges, Fix_FitPotential_needs_atomicnumbers, Fix_ForceAnnealing, Fix_IndependentFragmentGrids, Fix_ParseParticles, Fix_ParseParticles_split_forward_backward_Actions, Fix_StatusMsg, Fix_StepWorldTime_single_argument, Fix_Verbose_Codepatterns, ForceAnnealing_goodresults, ForceAnnealing_oldresults, ForceAnnealing_tocheck, ForceAnnealing_with_BondGraph, ForceAnnealing_with_BondGraph_continued, ForceAnnealing_with_BondGraph_continued_betteresults, ForceAnnealing_with_BondGraph_contraction-expansion, GeometryObjects, Gui_displays_atomic_force_velocity, IndependentFragmentGrids, IndependentFragmentGrids_IndividualZeroInstances, IndependentFragmentGrids_IntegrationTest, IndependentFragmentGrids_Sole_NN_Calculation, JobMarket_RobustOnKillsSegFaults, JobMarket_StableWorkerPool, JobMarket_unresolvable_hostname_fix, ODR_violation_mpqc_open, PartialCharges_OrthogonalSummation, PythonUI_with_named_parameters, QtGui_reactivate_TimeChanged_changes, Recreated_GuiChecks, RotateToPrincipalAxisSystem_UndoRedo, SaturateAtoms_findBestMatching, StoppableMakroAction, Subpackage_CodePatterns, Subpackage_JobMarket, Subpackage_LinearAlgebra, Subpackage_levmar, Subpackage_mpqc_open, Subpackage_vmg, ThirdParty_MPQC_rebuilt_buildsystem, TrajectoryDependenant_MaxOrder, TremoloParser_IncreasedPrecision, TremoloParser_MultipleTimesteps, Ubuntu_1604_changes, stable
Children:
2199c2
Parents:
158ecb
git-author:
Frederik Heber <heber@…> (06/12/14 07:23:12)
git-committer:
Frederik Heber <heber@…> (09/12/16 23:48:34)
Message:

Using the idea of three points giving a triangle to find rotation axis.

  • we calculate the center of either triangle and rotate the center of the ideal point distribution to match the one from the given points.
  • next we have the triangles normals as axis, take the first matching point and rotate align it.
  • we have to deal with a lot of special cases: What if only zero, one, or two points are given ...
  • in general we assume that the triangle lies relatively flat on the sphere's surface but what if the origin is in the triangle plane or even the calculated center is at the origin ...
  • TESTS: SphericalPointDistributionUnitTest working again, regression tests FragmentMolecule-cylces and StoreSaturatedFragment working.
File:
1 edited

Legend:

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

    r158ecb rb67d89  
    5353
    5454#include "LinearAlgebra/Line.hpp"
     55#include "LinearAlgebra/Plane.hpp"
    5556#include "LinearAlgebra/RealSpaceMatrix.hpp"
    5657#include "LinearAlgebra/Vector.hpp"
    5758
    58 typedef std::list<unsigned int> IndexList_t;
    59 typedef std::vector<unsigned int> IndexArray_t;
    60 typedef std::vector<Vector> VectorArray_t;
     59// static entities
     60const double SphericalPointDistribution::SQRT_3(sqrt(3.0));
     61const double SphericalPointDistribution::warn_amplitude = 1e-2;
     62
    6163typedef std::vector<double> DistanceArray_t;
    6264
    63 // static instances
    64 const double SphericalPointDistribution::SQRT_3(sqrt(3.0));
    65 
     65inline
    6666DistanceArray_t calculatePairwiseDistances(
    67     const std::vector<Vector> &_returnpolygon,
    68     const IndexList_t &_indices
     67    const std::vector<Vector> &_points,
     68    const SphericalPointDistribution::IndexList_t &_indices
    6969    )
    7070{
    7171  DistanceArray_t result;
    72   for (IndexList_t::const_iterator firstiter = _indices.begin();
     72  for (SphericalPointDistribution::IndexList_t::const_iterator firstiter = _indices.begin();
    7373      firstiter != _indices.end(); ++firstiter) {
    74     for (IndexList_t::const_iterator seconditer = firstiter;
     74    for (SphericalPointDistribution::IndexList_t::const_iterator seconditer = firstiter;
    7575        seconditer != _indices.end(); ++seconditer) {
    7676      if (firstiter == seconditer)
    7777        continue;
    78       const double distance = (_returnpolygon[*firstiter] - _returnpolygon[*seconditer]).NormSquared();
     78      const double distance = (_points[*firstiter] - _points[*seconditer]).NormSquared();
    7979      result.push_back(distance);
    8080    }
     
    101101 * \return pair with L1 and squared L2 error
    102102 */
    103 std::pair<double, double> calculateErrorOfMatching(
     103std::pair<double, double> SphericalPointDistribution::calculateErrorOfMatching(
    104104    const std::vector<Vector> &_old,
    105105    const std::vector<Vector> &_new,
     
    138138}
    139139
    140 SphericalPointDistribution::Polygon_t removeMatchingPoints(
     140SphericalPointDistribution::Polygon_t SphericalPointDistribution::removeMatchingPoints(
    141141    const VectorArray_t &_points,
    142142    const IndexList_t &_matchingindices
     
    163163}
    164164
    165 struct MatchingControlStructure {
    166   bool foundflag;
    167   double bestL2;
    168   IndexList_t bestmatching;
    169   VectorArray_t oldreturnpolygon;
    170   VectorArray_t newreturnpolygon;
    171 };
    172 
    173165/** Recursive function to go through all possible matchings.
    174166 *
     
    178170 * \param _matchingsize
    179171 */
    180 void recurseMatchings(
     172void SphericalPointDistribution::recurseMatchings(
    181173    MatchingControlStructure &_MCS,
    182174    IndexList_t &_matching,
     
    215207      // calculate errors
    216208      std::pair<double, double> errors = calculateErrorOfMatching(
    217           _MCS.oldreturnpolygon, _MCS.newreturnpolygon, _matching);
     209          _MCS.oldpoints, _MCS.newpoints, _matching);
    218210      if (errors.first < L1THRESHOLD) {
    219211        _MCS.bestmatching = _matching;
     
    227219}
    228220
    229 /** Rotates a given polygon around x, y, and z axis by the given angles.
    230  *
    231  * \param _polygon polygon whose points to rotate
    232  * \param _q quaternion specifying the rotation of the coordinate system
     221/** Decides by an orthonormal third vector whether the sign of the rotation
     222 * angle should be negative or positive.
     223 *
     224 * \return -1 or 1
    233225 */
    234 SphericalPointDistribution::Polygon_t rotatePolygon(
     226inline
     227double determineSignOfRotation(
     228    const Vector &_oldPosition,
     229    const Vector &_newPosition,
     230    const Vector &_RotationAxis
     231    )
     232{
     233  Vector dreiBein(_oldPosition);
     234  dreiBein.VectorProduct(_RotationAxis);
     235  dreiBein.Normalize();
     236  const double sign =
     237      (dreiBein.ScalarProduct(_newPosition) < 0.) ? -1. : +1.;
     238  LOG(6, "DEBUG: oldCenter on plane is " << _oldPosition
     239      << ", newCenter in plane is " << _newPosition
     240      << ", and dreiBein is " << dreiBein);
     241  return sign;
     242}
     243
     244/** Finds combinatorially the best matching between points in \a _polygon
     245 * and \a _newpolygon.
     246 *
     247 * We find the matching with the smallest L2 error, where we break when we stumble
     248 * upon a matching with zero error.
     249 *
     250 * \sa recurseMatchings() for going through all matchings
     251 *
     252 * \param _polygon here, we have indices 0,1,2,...
     253 * \param _newpolygon and here we need to find the correct indices
     254 * \return list of indices: first in \a _polygon goes to first index for \a _newpolygon
     255 */
     256SphericalPointDistribution::IndexList_t SphericalPointDistribution::findBestMatching(
    235257    const SphericalPointDistribution::Polygon_t &_polygon,
    236     const boost::math::quaternion<double> &_q)
    237 {
    238   SphericalPointDistribution::Polygon_t rotated_polygon = _polygon;
    239   boost::math::quaternion<double> q_inverse =
    240       boost::math::conj(_q)/(boost::math::norm(_q));
    241 
    242   // apply rotation angles
    243   for (SphericalPointDistribution::Polygon_t::iterator iter = rotated_polygon.begin();
    244       iter != rotated_polygon.end(); ++iter) {
    245     Vector &current = *iter;
    246     boost::math::quaternion<double> p(0, current[0], current[1], current[2]);
    247     p = _q * p * q_inverse;
    248     LOG(5, "DEBUG: Rotated point is " << p);
    249     // i have no idea why but first component comes up with wrong sign
    250     current[0] = -p.R_component_2();
    251     current[1] = p.R_component_3();
    252     current[2] = p.R_component_4();
    253   }
    254 
    255   return rotated_polygon;
     258    const SphericalPointDistribution::Polygon_t &_newpolygon
     259    )
     260{
     261  MatchingControlStructure MCS;
     262  MCS.foundflag = false;
     263  MCS.bestL2 = std::numeric_limits<double>::max();
     264  MCS.oldpoints.insert(MCS.oldpoints.begin(), _polygon.begin(),_polygon.end() );
     265  MCS.newpoints.insert(MCS.newpoints.begin(), _newpolygon.begin(),_newpolygon.end() );
     266
     267  // search for bestmatching combinatorially
     268  {
     269    // translate polygon into vector to enable index addressing
     270    IndexList_t indices(_newpolygon.size());
     271    std::generate(indices.begin(), indices.end(), UniqueNumber);
     272    IndexList_t matching;
     273
     274    // walk through all matchings
     275    const unsigned int matchingsize = _polygon.size();
     276    ASSERT( matchingsize <= indices.size(),
     277        "SphericalPointDistribution::matchSphericalPointDistributions() - not enough new points to choose for matching to old ones.");
     278    recurseMatchings(MCS, matching, indices, matchingsize);
     279  }
     280  return MCS.bestmatching;
     281}
     282
     283inline
     284Vector calculateCenter(
     285    const SphericalPointDistribution::VectorArray_t &_positions,
     286    const SphericalPointDistribution::IndexList_t &_indices)
     287{
     288  Vector Center;
     289  Center.Zero();
     290  for (SphericalPointDistribution::IndexList_t::const_iterator iter = _indices.begin();
     291      iter != _indices.end(); ++iter)
     292    Center += _positions[*iter];
     293  if (!_indices.empty())
     294    Center *= 1./(double)_indices.size();
     295
     296  return Center;
     297}
     298
     299inline
     300void calculateOldAndNewCenters(
     301    Vector &_oldCenter,
     302    Vector &_newCenter,
     303    const SphericalPointDistribution::VectorArray_t &_referencepositions,
     304    const SphericalPointDistribution::VectorArray_t &_currentpositions,
     305    const SphericalPointDistribution::IndexList_t &_bestmatching)
     306{
     307  const size_t NumberIds = std::min(_bestmatching.size(), (size_t)3);
     308  SphericalPointDistribution::IndexList_t continuousIds(NumberIds, -1);
     309  std::generate(continuousIds.begin(), continuousIds.end(), UniqueNumber);
     310  _oldCenter = calculateCenter(_referencepositions, continuousIds);
     311  // C++11 defines a copy_n function ...
     312  SphericalPointDistribution::IndexList_t::const_iterator enditer = _bestmatching.begin();
     313  std::advance(enditer, NumberIds);
     314  SphericalPointDistribution::IndexList_t firstbestmatchingIds(NumberIds, -1);
     315  std::copy(_bestmatching.begin(), enditer, firstbestmatchingIds.begin());
     316  _newCenter = calculateCenter( _currentpositions, firstbestmatchingIds);
     317}
     318
     319SphericalPointDistribution::Rotation_t SphericalPointDistribution::findPlaneAligningRotation(
     320    const VectorArray_t &_referencepositions,
     321    const VectorArray_t &_currentpositions,
     322    const IndexList_t &_bestmatching
     323    )
     324{
     325#ifndef NDEBUG
     326  bool dontcheck = false;
     327#endif
     328  // initialize to no rotation
     329  Rotation_t Rotation;
     330  Rotation.first.Zero();
     331  Rotation.first[0] = 1.;
     332  Rotation.second = 0.;
     333
     334  // calculate center of triangle/line/point consisting of first points of matching
     335  Vector oldCenter;
     336  Vector newCenter;
     337  calculateOldAndNewCenters(
     338      oldCenter, newCenter,
     339      _referencepositions, _currentpositions, _bestmatching);
     340
     341  if ((!oldCenter.IsZero()) && (!newCenter.IsZero())) {
     342    LOG(4, "DEBUG: oldCenter is " << oldCenter << ", newCenter is " << newCenter);
     343    oldCenter.Normalize();
     344    newCenter.Normalize();
     345    if (!oldCenter.IsEqualTo(newCenter)) {
     346      // calculate rotation axis and angle
     347      Rotation.first = oldCenter;
     348      Rotation.first.VectorProduct(newCenter);
     349      Rotation.second = oldCenter.Angle(newCenter); // /(M_PI/2.);
     350    } else {
     351      // no rotation required anymore
     352    }
     353  } else {
     354    LOG(4, "DEBUG: oldCenter is " << oldCenter << ", newCenter is " << newCenter);
     355    if ((oldCenter.IsZero()) && (newCenter.IsZero())) {
     356      // either oldCenter or newCenter (or both) is directly at origin
     357      if (_bestmatching.size() == 2) {
     358        // line case
     359        Vector oldPosition = _currentpositions[*_bestmatching.begin()];
     360        Vector newPosition = _referencepositions[0];
     361        // check whether we need to rotate at all
     362        if (!oldPosition.IsEqualTo(newPosition)) {
     363          Rotation.first = oldPosition;
     364          Rotation.first.VectorProduct(newPosition);
     365          // orientation will fix the sign here eventually
     366          Rotation.second = oldPosition.Angle(newPosition);
     367        } else {
     368          // no rotation required anymore
     369        }
     370      } else {
     371        // triangle case
     372        // both triangles/planes have same center, hence get axis by
     373        // VectorProduct of Normals
     374        Plane newplane(_referencepositions[0], _referencepositions[1], _referencepositions[2]);
     375        VectorArray_t vectors;
     376        for (IndexList_t::const_iterator iter = _bestmatching.begin();
     377            iter != _bestmatching.end(); ++iter)
     378          vectors.push_back(_currentpositions[*iter]);
     379        Plane oldplane(vectors[0], vectors[1], vectors[2]);
     380        Vector oldPosition = oldplane.getNormal();
     381        Vector newPosition = newplane.getNormal();
     382        // check whether we need to rotate at all
     383        if (!oldPosition.IsEqualTo(newPosition)) {
     384          Rotation.first = oldPosition;
     385          Rotation.first.VectorProduct(newPosition);
     386          Rotation.first.Normalize();
     387
     388          // construct reference vector to determine direction of rotation
     389          const double sign = determineSignOfRotation(oldPosition, newPosition, Rotation.first);
     390          Rotation.second = sign * oldPosition.Angle(newPosition);
     391          LOG(5, "DEBUG: Rotating plane normals by " << Rotation.second
     392              << " around axis " << Rotation.first);
     393        } else {
     394          // else do nothing
     395        }
     396      }
     397    } else {
     398      // TODO: we can't do anything here, but this case needs to be dealt with when
     399      // we have no ideal geometries anymore
     400      if ((oldCenter-newCenter).Norm() > warn_amplitude)
     401        ELOG(2, "oldCenter is " << oldCenter << ", yet newCenter is " << newCenter);
     402#ifndef NDEBUG
     403      // else they are considered close enough
     404      dontcheck = true;
     405#endif
     406    }
     407  }
     408
     409#ifndef NDEBUG
     410  // check: rotation brings newCenter onto oldCenter position
     411  if (!dontcheck) {
     412    Line Axis(zeroVec, Rotation.first);
     413    Vector test = Axis.rotateVector(newCenter, Rotation.second);
     414    LOG(4, "CHECK: rotated newCenter is " << test
     415        << ", oldCenter is " << oldCenter);
     416    ASSERT( (test - oldCenter).NormSquared() < std::numeric_limits<double>::epsilon()*1e4,
     417        "matchSphericalPointDistributions() - rotation does not work as expected by "
     418        +toString((test - oldCenter).NormSquared())+".");
     419  }
     420#endif
     421
     422  return Rotation;
     423}
     424
     425SphericalPointDistribution::Rotation_t SphericalPointDistribution::findPointAligningRotation(
     426    const VectorArray_t &remainingold,
     427    const VectorArray_t &remainingnew,
     428    const IndexList_t &_bestmatching)
     429{
     430  // initialize rotation to zero
     431  Rotation_t Rotation;
     432  Rotation.first.Zero();
     433  Rotation.first[0] = 1.;
     434  Rotation.second = 0.;
     435
     436  // recalculate center
     437  Vector oldCenter;
     438  Vector newCenter;
     439  calculateOldAndNewCenters(
     440      oldCenter, newCenter,
     441      remainingold, remainingnew, _bestmatching);
     442
     443  Vector oldPosition = remainingnew[*_bestmatching.begin()];
     444  Vector newPosition = remainingold[0];
     445  LOG(6, "DEBUG: oldPosition is " << oldPosition << " and newPosition is " << newPosition);
     446  if (!oldPosition.IsEqualTo(newPosition)) {
     447    if ((!oldCenter.IsZero()) && (!newCenter.IsZero())) {
     448      oldCenter.Normalize();  // note weighted sum of normalized weight is not normalized
     449      Rotation.first = oldCenter;
     450      LOG(6, "DEBUG: Picking normalized oldCenter as Rotation.first " << oldCenter);
     451      oldPosition.ProjectOntoPlane(Rotation.first);
     452      newPosition.ProjectOntoPlane(Rotation.first);
     453      LOG(6, "DEBUG: Positions after projection are " << oldPosition << " and " << newPosition);
     454    } else {
     455      if (_bestmatching.size() == 2) {
     456        // line situation
     457        try {
     458          Plane oldplane(oldPosition, oldCenter, newPosition);
     459          Rotation.first = oldplane.getNormal();
     460          LOG(6, "DEBUG: Plane is " << oldplane << " and normal is " << Rotation.first);
     461        } catch (LinearDependenceException &e) {
     462          LOG(6, "DEBUG: Vectors defining plane are linearly dependent.");
     463          // oldPosition and newPosition are on a line, just flip when not equal
     464          if (!oldPosition.IsEqualTo(newPosition)) {
     465            Rotation.first.Zero();
     466            Rotation.first.GetOneNormalVector(oldPosition);
     467            LOG(6, "DEBUG: For flipping we use Rotation.first " << Rotation.first);
     468            assert( Rotation.first.ScalarProduct(oldPosition) < std::numeric_limits<double>::epsilon()*1e4);
     469  //              Rotation.second = M_PI;
     470          } else {
     471            LOG(6, "DEBUG: oldPosition and newPosition are equivalent.");
     472          }
     473        }
     474      } else {
     475        // triangle situation
     476        Plane oldplane(remainingold[0], remainingold[1], remainingold[2]);
     477        Rotation.first = oldplane.getNormal();
     478        LOG(6, "DEBUG: oldPlane is " << oldplane << " and normal is " << Rotation.first);
     479        oldPosition.ProjectOntoPlane(Rotation.first);
     480        LOG(6, "DEBUG: Positions after projection are " << oldPosition << " and " << newPosition);
     481      }
     482    }
     483    // construct reference vector to determine direction of rotation
     484    const double sign = determineSignOfRotation(oldPosition, newPosition, Rotation.first);
     485    Rotation.second = sign * oldPosition.Angle(newPosition);
     486  } else {
     487    LOG(6, "DEBUG: oldPosition and newPosition are equivalent, hence no orientating rotation.");
     488  }
     489
     490  return Rotation;
    256491}
    257492
     
    269504      << " with new polygon " << _newpolygon);
    270505
     506  if (_polygon.size() == _newpolygon.size()) {
     507    // same number of points desired as are present? Do nothing
     508    LOG(2, "INFO: There are no vacant points to return.");
     509    return remainingreturnpolygon;
     510  }
     511
    271512  if (_polygon.size() > 0) {
    272     MatchingControlStructure MCS;
    273     MCS.foundflag = false;
    274     MCS.bestL2 = std::numeric_limits<double>::max();
    275     MCS.oldreturnpolygon.insert(MCS.oldreturnpolygon.begin(), _polygon.begin(),_polygon.end() );
    276     MCS.newreturnpolygon.insert(MCS.newreturnpolygon.begin(), _newpolygon.begin(),_newpolygon.end() );
    277 
    278     // search for bestmatching combinatorially
     513    IndexList_t bestmatching = findBestMatching(_polygon, _newpolygon);
     514    LOG(2, "INFO: Best matching is " << bestmatching);
     515
     516    // determine rotation angles to align the two point distributions with
     517    // respect to bestmatching:
     518    // we use the center between the three first matching points
     519    /// the first rotation brings these two centers to coincide
     520    VectorArray_t rotated_newpolygon = remainingnew;
    279521    {
    280       // translate polygon into vector to enable index addressing
    281       IndexList_t indices(_newpolygon.size());
    282       std::generate(indices.begin(), indices.end(), UniqueNumber);
    283       IndexList_t matching;
    284 
    285       // walk through all matchings
    286       const unsigned int matchingsize = _polygon.size();
    287       ASSERT( matchingsize <= indices.size(),
    288           "SphericalPointDistribution::matchSphericalPointDistributions() - not enough new returnpolygon to choose for matching to old ones.");
    289       recurseMatchings(MCS, matching, indices, matchingsize);
    290     }
    291     LOG(2, "INFO: Best matching is " << MCS.bestmatching);
    292 
    293     // determine rotation angles to align the two point distributions with
    294     // respect to bestmatching
    295     VectorArray_t rotated_newpolygon = remainingnew;
    296     Vector oldCenter;
    297     {
    298       // calculate center of triangle/line/point consisting of first points of matching
    299       Vector newCenter;
    300       IndexList_t::const_iterator iter = MCS.bestmatching.begin();
    301       unsigned int i = 0;
    302       for (; (i<3) && (i<MCS.bestmatching.size()); ++i, ++iter) {
    303         oldCenter += remainingold[i];
    304         newCenter += remainingnew[*iter];
    305       }
    306       oldCenter *= 1./(double)i;
    307       newCenter *= 1./(double)i;
    308       LOG(4, "DEBUG: oldCenter is " << oldCenter << ", newCenter is " << newCenter);
    309 
    310       if ((oldCenter - newCenter).NormSquared() > std::numeric_limits<double>::epsilon()*1e4) {
    311         // setup quaternion
    312         Vector RotationAxis = oldCenter;
    313         RotationAxis.VectorProduct(newCenter);
    314         Line Axis(zeroVec, RotationAxis);
    315         RotationAxis.Normalize();
    316         const double RotationAngle = oldCenter.Angle(newCenter); // /(M_PI/2.);
    317         LOG(5, "DEBUG: Rotate coordinate system by " << RotationAngle
    318             << " around axis " << RotationAxis);
    319 
    320         // apply rotation angles
    321         for (VectorArray_t::iterator iter = rotated_newpolygon.begin();
    322             iter != rotated_newpolygon.end(); ++iter) {
    323           Vector &current = *iter;
    324           LOG(5, "DEBUG: Original point is " << current);
    325           current =  Axis.rotateVector(current, RotationAngle);
    326           LOG(5, "DEBUG: Rotated point is " << current);
     522      Rotation_t Rotation = findPlaneAligningRotation(
     523          remainingold,
     524          remainingnew,
     525          bestmatching);
     526      LOG(5, "DEBUG: Rotating coordinate system by " << Rotation.second
     527          << " around axis " << Rotation.first);
     528      Line Axis(zeroVec, Rotation.first);
     529
     530      // apply rotation angle to bring newCenter to oldCenter
     531      for (VectorArray_t::iterator iter = rotated_newpolygon.begin();
     532          iter != rotated_newpolygon.end(); ++iter) {
     533        Vector &current = *iter;
     534        LOG(6, "DEBUG: Original point is " << current);
     535        current =  Axis.rotateVector(current, Rotation.second);
     536        LOG(6, "DEBUG: Rotated point is " << current);
     537      }
     538
     539#ifndef NDEBUG
     540      // check: rotated "newCenter" should now equal oldCenter
     541      {
     542        Vector oldCenter;
     543        Vector rotatednewCenter;
     544        calculateOldAndNewCenters(
     545            oldCenter, rotatednewCenter,
     546            remainingold, rotated_newpolygon, bestmatching);
     547        // NOTE: Center must not necessarily lie on the sphere with norm 1, hence, we
     548        // have to normalize it just as before, as oldCenter and newCenter lengths may differ.
     549        if ((!oldCenter.IsZero()) && (!rotatednewCenter.IsZero())) {
     550          oldCenter.Normalize();
     551          rotatednewCenter.Normalize();
     552          LOG(4, "CHECK: rotatednewCenter is " << rotatednewCenter
     553              << ", oldCenter is " << oldCenter);
     554          ASSERT( (rotatednewCenter - oldCenter).NormSquared() < std::numeric_limits<double>::epsilon()*1e4,
     555              "matchSphericalPointDistributions() - rotation does not work as expected by "
     556              +toString((rotatednewCenter - oldCenter).NormSquared())+".");
    327557        }
    328558      }
    329     }
    330     // rotate triangle/line/point around itself to match orientation
    331     if (MCS.bestmatching.size() > 1) {
    332       if (oldCenter.NormSquared() > std::numeric_limits<double>::epsilon()*1e4) {
    333         // construct RotationAxis and two points on its plane, defining the angle
    334         const Line RotationAxis(zeroVec, oldCenter);
    335         Vector oldPosition(rotated_newpolygon[*MCS.bestmatching.begin()]);
    336         oldPosition.ProjectOntoPlane(RotationAxis.getDirection());
    337         Vector newPosition(remainingold[*MCS.bestmatching.begin()]);
    338         newPosition.ProjectOntoPlane(RotationAxis.getDirection());
    339 
    340         // construct reference vector to determine direction of rotation
    341         Vector dreiBein(oldPosition);
    342         dreiBein.VectorProduct(oldCenter);
    343         dreiBein.Normalize();
    344         const double sign =
    345             (dreiBein.ScalarProduct(newPosition) < 0.) ? -1. : +1.;
    346         LOG(6, "DEBUG: oldCenter on plane is " << oldPosition
    347             << ", newCenter in plane is " << newPosition
    348             << ", and dreiBein is " << dreiBein);
    349         const double RotationAngle = sign * oldPosition.Angle(newPosition);
    350         LOG(5, "DEBUG: Rotating around self is " << RotationAngle
    351             << " around axis " << RotationAxis);
     559#endif
     560    }
     561    /// the second (orientation) rotation aligns the planes such that the
     562    /// points themselves coincide
     563    if (bestmatching.size() > 1) {
     564      Rotation_t Rotation = findPointAligningRotation(
     565          remainingold,
     566          rotated_newpolygon,
     567          bestmatching);
     568
     569      // construct RotationAxis and two points on its plane, defining the angle
     570      Rotation.first.Normalize();
     571      const Line RotationAxis(zeroVec, Rotation.first);
     572
     573      LOG(5, "DEBUG: Rotating around self is " << Rotation.second
     574          << " around axis " << RotationAxis);
    352575
    353576#ifndef NDEBUG
    354         // check: first bestmatching in rotated_newpolygon and remainingnew
    355         // should now equal
    356         {
    357           const IndexList_t::const_iterator iter = MCS.bestmatching.begin();
    358           Vector rotatednew = RotationAxis.rotateVector(
    359               rotated_newpolygon[*iter],
    360               RotationAngle);
    361           LOG(4, "CHECK: rotated first new bestmatching is " << rotatednew
    362               << " while old was " << remainingold[*iter]);
    363           ASSERT( (rotatednew - remainingold[*iter]).Norm()
    364               < std::numeric_limits<double>::epsilon()*1e4,
    365               "matchSphericalPointDistributions() - orientation rotation does not work as expected.");
    366         }
     577      // check: first bestmatching in rotated_newpolygon and remainingnew
     578      // should now equal
     579      {
     580        const IndexList_t::const_iterator iter = bestmatching.begin();
     581        Vector rotatednew = RotationAxis.rotateVector(
     582            rotated_newpolygon[*iter],
     583            Rotation.second);
     584        LOG(4, "CHECK: rotated first new bestmatching is " << rotatednew
     585            << " while old was " << remainingold[0]);
     586        ASSERT( (rotatednew - remainingold[0]).Norm() < warn_amplitude,
     587            "matchSphericalPointDistributions() - orientation rotation ends up off by more than "
     588            +toString(warn_amplitude)+".");
     589      }
    367590#endif
    368591
    369         for (VectorArray_t::iterator iter = rotated_newpolygon.begin();
    370             iter != rotated_newpolygon.end(); ++iter) {
    371           Vector &current = *iter;
    372           LOG(6, "DEBUG: Original point is " << current);
    373           current = RotationAxis.rotateVector(current, RotationAngle);
    374           LOG(6, "DEBUG: Rotated point is " << current);
    375         }
     592      for (VectorArray_t::iterator iter = rotated_newpolygon.begin();
     593          iter != rotated_newpolygon.end(); ++iter) {
     594        Vector &current = *iter;
     595        LOG(6, "DEBUG: Original point is " << current);
     596        current = RotationAxis.rotateVector(current, Rotation.second);
     597        LOG(6, "DEBUG: Rotated point is " << current);
    376598      }
    377599    }
     
    379601    // remove all points in matching and return remaining ones
    380602    SphericalPointDistribution::Polygon_t remainingpoints =
    381         removeMatchingPoints(rotated_newpolygon, MCS.bestmatching);
     603        removeMatchingPoints(rotated_newpolygon, bestmatching);
    382604    LOG(2, "INFO: Remaining points are " << remainingpoints);
    383605    return remainingpoints;
Note: See TracChangeset for help on using the changeset viewer.