| [0d4daf] | 1 | /* | 
|---|
|  | 2 | * Project: MoleCuilder | 
|---|
|  | 3 | * Description: creates and alters molecular systems | 
|---|
|  | 4 | * Copyright (C)  2014 Frederik Heber. All rights reserved. | 
|---|
|  | 5 | * | 
|---|
|  | 6 | * | 
|---|
|  | 7 | *   This file is part of MoleCuilder. | 
|---|
|  | 8 | * | 
|---|
|  | 9 | *    MoleCuilder is free software: you can redistribute it and/or modify | 
|---|
|  | 10 | *    it under the terms of the GNU General Public License as published by | 
|---|
|  | 11 | *    the Free Software Foundation, either version 2 of the License, or | 
|---|
|  | 12 | *    (at your option) any later version. | 
|---|
|  | 13 | * | 
|---|
|  | 14 | *    MoleCuilder is distributed in the hope that it will be useful, | 
|---|
|  | 15 | *    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|---|
|  | 16 | *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|---|
|  | 17 | *    GNU General Public License for more details. | 
|---|
|  | 18 | * | 
|---|
|  | 19 | *    You should have received a copy of the GNU General Public License | 
|---|
|  | 20 | *    along with MoleCuilder.  If not, see <http://www.gnu.org/licenses/>. | 
|---|
|  | 21 | */ | 
|---|
|  | 22 |  | 
|---|
|  | 23 | /* | 
|---|
|  | 24 | * SphericalPointDistribution.cpp | 
|---|
|  | 25 | * | 
|---|
|  | 26 | *  Created on: May 30, 2014 | 
|---|
|  | 27 | *      Author: heber | 
|---|
|  | 28 | */ | 
|---|
|  | 29 |  | 
|---|
|  | 30 | // include config.h | 
|---|
|  | 31 | #ifdef HAVE_CONFIG_H | 
|---|
|  | 32 | #include <config.h> | 
|---|
|  | 33 | #endif | 
|---|
|  | 34 |  | 
|---|
|  | 35 | #include "CodePatterns/MemDebug.hpp" | 
|---|
|  | 36 |  | 
|---|
|  | 37 | #include "SphericalPointDistribution.hpp" | 
|---|
|  | 38 |  | 
|---|
|  | 39 | #include "CodePatterns/Assert.hpp" | 
|---|
|  | 40 | #include "CodePatterns/IteratorAdaptors.hpp" | 
|---|
| [90426a] | 41 | #include "CodePatterns/Log.hpp" | 
|---|
| [0d4daf] | 42 | #include "CodePatterns/toString.hpp" | 
|---|
|  | 43 |  | 
|---|
|  | 44 | #include <algorithm> | 
|---|
|  | 45 | #include <cmath> | 
|---|
| [0d5ca7] | 46 | #include <functional> | 
|---|
|  | 47 | #include <iterator> | 
|---|
| [0d4daf] | 48 | #include <limits> | 
|---|
|  | 49 | #include <list> | 
|---|
|  | 50 | #include <vector> | 
|---|
|  | 51 | #include <map> | 
|---|
|  | 52 |  | 
|---|
|  | 53 | #include "LinearAlgebra/Line.hpp" | 
|---|
|  | 54 | #include "LinearAlgebra/RealSpaceMatrix.hpp" | 
|---|
|  | 55 | #include "LinearAlgebra/Vector.hpp" | 
|---|
|  | 56 |  | 
|---|
|  | 57 | typedef std::list<unsigned int> IndexList_t; | 
|---|
|  | 58 | typedef std::vector<unsigned int> IndexArray_t; | 
|---|
|  | 59 | typedef std::vector<Vector> VectorArray_t; | 
|---|
|  | 60 | typedef std::vector<double> DistanceArray_t; | 
|---|
|  | 61 |  | 
|---|
|  | 62 | DistanceArray_t calculatePairwiseDistances( | 
|---|
|  | 63 | const std::vector<Vector> &_points, | 
|---|
|  | 64 | const IndexList_t &_indices | 
|---|
|  | 65 | ) | 
|---|
|  | 66 | { | 
|---|
|  | 67 | DistanceArray_t result; | 
|---|
|  | 68 | for (IndexList_t::const_iterator firstiter = _indices.begin(); | 
|---|
|  | 69 | firstiter != _indices.end(); ++firstiter) { | 
|---|
|  | 70 | for (IndexList_t::const_iterator seconditer = firstiter; | 
|---|
|  | 71 | seconditer != _indices.end(); ++seconditer) { | 
|---|
|  | 72 | if (firstiter == seconditer) | 
|---|
|  | 73 | continue; | 
|---|
|  | 74 | const double distance = (_points[*firstiter] - _points[*seconditer]).NormSquared(); | 
|---|
|  | 75 | result.push_back(distance); | 
|---|
|  | 76 | } | 
|---|
|  | 77 | } | 
|---|
|  | 78 | return result; | 
|---|
|  | 79 | } | 
|---|
|  | 80 |  | 
|---|
|  | 81 | // class generator: taken from www.cplusplus.com example std::generate | 
|---|
|  | 82 | struct c_unique { | 
|---|
|  | 83 | int current; | 
|---|
|  | 84 | c_unique() {current=0;} | 
|---|
| [0d5ca7] | 85 | int operator()() {return current++;} | 
|---|
| [0d4daf] | 86 | } UniqueNumber; | 
|---|
|  | 87 |  | 
|---|
|  | 88 | /** Returns squared L2 error of the given \a _Matching. | 
|---|
|  | 89 | * | 
|---|
|  | 90 | * We compare the pair-wise distances of each associated matching | 
|---|
|  | 91 | * and check whether these distances each match between \a _old and | 
|---|
|  | 92 | * \a _new. | 
|---|
|  | 93 | * | 
|---|
|  | 94 | * \param _old first set of points (fewer or equal to \a _new) | 
|---|
|  | 95 | * \param _new second set of points | 
|---|
|  | 96 | * \param _Matching matching between the two sets | 
|---|
|  | 97 | * \return pair with L1 and squared L2 error | 
|---|
|  | 98 | */ | 
|---|
|  | 99 | std::pair<double, double> calculateErrorOfMatching( | 
|---|
|  | 100 | const std::vector<Vector> &_old, | 
|---|
|  | 101 | const std::vector<Vector> &_new, | 
|---|
|  | 102 | const IndexList_t &_Matching) | 
|---|
|  | 103 | { | 
|---|
|  | 104 | std::pair<double, double> errors( std::make_pair( 0., 0. ) ); | 
|---|
|  | 105 |  | 
|---|
|  | 106 | if (_Matching.size() > 1) { | 
|---|
| [90426a] | 107 | LOG(3, "INFO: Matching is " << _Matching); | 
|---|
| [0d4daf] | 108 |  | 
|---|
|  | 109 | // calculate all pair-wise distances | 
|---|
|  | 110 | IndexList_t keys(_Matching.size()); | 
|---|
|  | 111 | std::generate (keys.begin(), keys.end(), UniqueNumber); | 
|---|
|  | 112 | const DistanceArray_t firstdistances = calculatePairwiseDistances(_old, keys); | 
|---|
|  | 113 | const DistanceArray_t seconddistances = calculatePairwiseDistances(_new, _Matching); | 
|---|
|  | 114 |  | 
|---|
|  | 115 | ASSERT( firstdistances.size() == seconddistances.size(), | 
|---|
|  | 116 | "calculateL2ErrorOfMatching() - mismatch in pair-wise distance array sizes."); | 
|---|
|  | 117 | DistanceArray_t::const_iterator firstiter = firstdistances.begin(); | 
|---|
|  | 118 | DistanceArray_t::const_iterator seconditer = seconddistances.begin(); | 
|---|
|  | 119 | for (;(firstiter != firstdistances.end()) && (seconditer != seconddistances.end()); | 
|---|
|  | 120 | ++firstiter, ++seconditer) { | 
|---|
|  | 121 | const double gap = *firstiter - *seconditer; | 
|---|
|  | 122 | // L1 error | 
|---|
|  | 123 | if (errors.first < gap) | 
|---|
|  | 124 | errors.first = gap; | 
|---|
|  | 125 | // L2 error | 
|---|
|  | 126 | errors.second += gap*gap; | 
|---|
|  | 127 | } | 
|---|
| [90426a] | 128 | } else | 
|---|
| [0d5ca7] | 129 | ELOG(3, "calculateErrorOfMatching() - Given matching's size is less than 2."); | 
|---|
| [90426a] | 130 | LOG(3, "INFO: Resulting errors for matching (L1, L2): " | 
|---|
|  | 131 | << errors.first << "," << errors.second << "."); | 
|---|
| [0d4daf] | 132 |  | 
|---|
|  | 133 | return errors; | 
|---|
|  | 134 | } | 
|---|
|  | 135 |  | 
|---|
|  | 136 | SphericalPointDistribution::Polygon_t removeMatchingPoints( | 
|---|
|  | 137 | const SphericalPointDistribution::Polygon_t &_points, | 
|---|
|  | 138 | const IndexList_t &_matchingindices | 
|---|
|  | 139 | ) | 
|---|
|  | 140 | { | 
|---|
|  | 141 | SphericalPointDistribution::Polygon_t remainingpoints; | 
|---|
|  | 142 | IndexArray_t indices(_matchingindices.begin(), _matchingindices.end()); | 
|---|
|  | 143 | std::sort(indices.begin(), indices.end()); | 
|---|
| [90426a] | 144 | LOG(4, "DEBUG: sorted matching is " << indices); | 
|---|
| [0d4daf] | 145 | IndexArray_t::const_iterator valueiter = indices.begin(); | 
|---|
|  | 146 | SphericalPointDistribution::Polygon_t::const_iterator pointiter = | 
|---|
|  | 147 | _points.begin(); | 
|---|
|  | 148 | for (unsigned int i=0; i< _points.size(); ++i, ++pointiter) { | 
|---|
|  | 149 | // skip all those in values | 
|---|
|  | 150 | if (*valueiter == i) | 
|---|
|  | 151 | ++valueiter; | 
|---|
|  | 152 | else | 
|---|
|  | 153 | remainingpoints.push_back(*pointiter); | 
|---|
|  | 154 | } | 
|---|
| [90426a] | 155 | LOG(4, "DEBUG: remaining indices are " << remainingpoints); | 
|---|
| [0d4daf] | 156 |  | 
|---|
|  | 157 | return remainingpoints; | 
|---|
|  | 158 | } | 
|---|
|  | 159 |  | 
|---|
|  | 160 | struct MatchingControlStructure { | 
|---|
|  | 161 | bool foundflag; | 
|---|
|  | 162 | double bestL2; | 
|---|
|  | 163 | IndexList_t bestmatching; | 
|---|
|  | 164 | VectorArray_t oldpoints; | 
|---|
|  | 165 | VectorArray_t newpoints; | 
|---|
|  | 166 | }; | 
|---|
|  | 167 |  | 
|---|
|  | 168 | /** Recursive function to go through all possible matchings. | 
|---|
|  | 169 | * | 
|---|
|  | 170 | * \param _MCS structure holding global information to the recursion | 
|---|
|  | 171 | * \param _matching current matching being build up | 
|---|
|  | 172 | * \param _indices contains still available indices | 
|---|
|  | 173 | * \param _matchingsize | 
|---|
|  | 174 | */ | 
|---|
|  | 175 | void recurseMatchings( | 
|---|
|  | 176 | MatchingControlStructure &_MCS, | 
|---|
|  | 177 | IndexList_t &_matching, | 
|---|
|  | 178 | IndexList_t _indices, | 
|---|
|  | 179 | unsigned int _matchingsize) | 
|---|
|  | 180 | { | 
|---|
| [90426a] | 181 | LOG(4, "DEBUG: Recursing with current matching " << _matching | 
|---|
|  | 182 | << ", remaining indices " << _indices | 
|---|
| [0d5ca7] | 183 | << ", and sought size " << _matching.size()+_matchingsize); | 
|---|
| [0d4daf] | 184 | //!> threshold for L1 error below which matching is immediately acceptable | 
|---|
|  | 185 | const double L1THRESHOLD = 1e-2; | 
|---|
|  | 186 | if (!_MCS.foundflag) { | 
|---|
| [0d5ca7] | 187 | LOG(4, "DEBUG: Current matching has size " << _matching.size() << ", places left " << _matchingsize); | 
|---|
|  | 188 | if (_matchingsize > 0) { | 
|---|
| [0d4daf] | 189 | // go through all indices | 
|---|
|  | 190 | for (IndexList_t::iterator iter = _indices.begin(); | 
|---|
| [0d5ca7] | 191 | (iter != _indices.end()) && (!_MCS.foundflag);) { | 
|---|
| [0d4daf] | 192 | // add index to matching | 
|---|
|  | 193 | _matching.push_back(*iter); | 
|---|
| [0d5ca7] | 194 | LOG(5, "DEBUG: Adding " << *iter << " to matching."); | 
|---|
| [0d4daf] | 195 | // remove index but keep iterator to position (is the next to erase element) | 
|---|
|  | 196 | IndexList_t::iterator backupiter = _indices.erase(iter); | 
|---|
|  | 197 | // recurse with decreased _matchingsize | 
|---|
|  | 198 | recurseMatchings(_MCS, _matching, _indices, _matchingsize-1); | 
|---|
|  | 199 | // re-add chosen index and reset index to new position | 
|---|
|  | 200 | _indices.insert(backupiter, _matching.back()); | 
|---|
|  | 201 | iter = backupiter; | 
|---|
|  | 202 | // remove index from _matching to make space for the next one | 
|---|
|  | 203 | _matching.pop_back(); | 
|---|
|  | 204 | } | 
|---|
|  | 205 | // gone through all indices then exit recursion | 
|---|
| [0d5ca7] | 206 | if (_matching.empty()) | 
|---|
|  | 207 | _MCS.foundflag = true; | 
|---|
| [0d4daf] | 208 | } else { | 
|---|
| [90426a] | 209 | LOG(3, "INFO: Found matching " << _matching); | 
|---|
| [0d4daf] | 210 | // calculate errors | 
|---|
|  | 211 | std::pair<double, double> errors = calculateErrorOfMatching( | 
|---|
|  | 212 | _MCS.oldpoints, _MCS.newpoints, _matching); | 
|---|
|  | 213 | if (errors.first < L1THRESHOLD) { | 
|---|
|  | 214 | _MCS.bestmatching = _matching; | 
|---|
|  | 215 | _MCS.foundflag = true; | 
|---|
| [0d5ca7] | 216 | } else if (_MCS.bestL2 > errors.second) { | 
|---|
| [0d4daf] | 217 | _MCS.bestmatching = _matching; | 
|---|
|  | 218 | _MCS.bestL2 = errors.second; | 
|---|
|  | 219 | } | 
|---|
|  | 220 | } | 
|---|
|  | 221 | } | 
|---|
|  | 222 | } | 
|---|
|  | 223 |  | 
|---|
| [0d5ca7] | 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 |  | 
|---|
|  | 280 | /** Rotates a given polygon around x, y, and z axis by the given angles. | 
|---|
|  | 281 | * | 
|---|
|  | 282 | * \param _polygon polygon whose points to rotate | 
|---|
|  | 283 | * \param _angles vector with rotation angles for x,y,z axis | 
|---|
|  | 284 | */ | 
|---|
|  | 285 | SphericalPointDistribution::Polygon_t rotatePolygon( | 
|---|
|  | 286 | const SphericalPointDistribution::Polygon_t &_polygon, | 
|---|
|  | 287 | const std::vector<double> &_angles) | 
|---|
|  | 288 | { | 
|---|
|  | 289 | SphericalPointDistribution::Polygon_t rotated_polygon = _polygon; | 
|---|
|  | 290 | RealSpaceMatrix rotation; | 
|---|
|  | 291 | ASSERT( _angles.size() == 3, | 
|---|
|  | 292 | "rotatePolygon() - not exactly "+toString(3)+" components given."); | 
|---|
|  | 293 |  | 
|---|
|  | 294 | // apply rotation angles | 
|---|
|  | 295 | for (SphericalPointDistribution::Polygon_t::iterator iter = rotated_polygon.begin(); | 
|---|
|  | 296 | 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); | 
|---|
|  | 309 | } | 
|---|
|  | 310 |  | 
|---|
|  | 311 | return rotated_polygon; | 
|---|
|  | 312 | } | 
|---|
|  | 313 |  | 
|---|
|  | 314 |  | 
|---|
| [0d4daf] | 315 | SphericalPointDistribution::Polygon_t | 
|---|
|  | 316 | SphericalPointDistribution::matchSphericalPointDistributions( | 
|---|
|  | 317 | const SphericalPointDistribution::Polygon_t &_polygon, | 
|---|
|  | 318 | const SphericalPointDistribution::Polygon_t &_newpolygon | 
|---|
|  | 319 | ) | 
|---|
|  | 320 | { | 
|---|
|  | 321 | SphericalPointDistribution::Polygon_t remainingpoints; | 
|---|
|  | 322 | VectorArray_t remainingold(_polygon.begin(), _polygon.end()); | 
|---|
|  | 323 | VectorArray_t remainingnew(_newpolygon.begin(), _newpolygon.end()); | 
|---|
| [0d5ca7] | 324 | LOG(2, "INFO: Matching old polygon " << _polygon | 
|---|
| [90426a] | 325 | << " with new polygon " << _newpolygon); | 
|---|
| [0d4daf] | 326 |  | 
|---|
|  | 327 | if (_polygon.size() > 0) { | 
|---|
|  | 328 | MatchingControlStructure MCS; | 
|---|
|  | 329 | MCS.foundflag = false; | 
|---|
|  | 330 | MCS.bestL2 = std::numeric_limits<double>::max(); | 
|---|
|  | 331 | MCS.oldpoints.insert(MCS.oldpoints.begin(), _polygon.begin(),_polygon.end() ); | 
|---|
|  | 332 | MCS.newpoints.insert(MCS.newpoints.begin(), _newpolygon.begin(),_newpolygon.end() ); | 
|---|
|  | 333 |  | 
|---|
|  | 334 | // search for bestmatching combinatorially | 
|---|
|  | 335 | { | 
|---|
|  | 336 | // translate polygon into vector to enable index addressing | 
|---|
|  | 337 | IndexList_t indices(_newpolygon.size()); | 
|---|
|  | 338 | std::generate(indices.begin(), indices.end(), UniqueNumber); | 
|---|
|  | 339 | IndexList_t matching; | 
|---|
|  | 340 |  | 
|---|
|  | 341 | // walk through all matchings | 
|---|
|  | 342 | const unsigned int matchingsize = _polygon.size(); | 
|---|
|  | 343 | ASSERT( matchingsize <= indices.size(), | 
|---|
|  | 344 | "SphericalPointDistribution::matchSphericalPointDistributions() - not enough new points to choose for matching to old ones."); | 
|---|
|  | 345 | recurseMatchings(MCS, matching, indices, matchingsize); | 
|---|
|  | 346 | } | 
|---|
| [0d5ca7] | 347 | LOG(2, "INFO: Best matching is " << MCS.bestmatching); | 
|---|
| [0d4daf] | 348 |  | 
|---|
|  | 349 | // determine rotation angles to align the two point distributions with | 
|---|
|  | 350 | // respect to bestmatching | 
|---|
| [0d5ca7] | 351 | std::vector<double> angles(NDIM); | 
|---|
| [0d4daf] | 352 | Vector newCenter; | 
|---|
| [0d5ca7] | 353 | Vector oldCenter; | 
|---|
| [0d4daf] | 354 | { | 
|---|
|  | 355 | // calculate center of triangle/line/point consisting of first points of matching | 
|---|
|  | 356 | IndexList_t::const_iterator iter = MCS.bestmatching.begin(); | 
|---|
|  | 357 | unsigned int i = 0; | 
|---|
|  | 358 | for (; (i<3) && (i<MCS.bestmatching.size()); ++i, ++iter) { | 
|---|
|  | 359 | oldCenter += remainingold[i]; | 
|---|
|  | 360 | newCenter += remainingnew[*iter]; | 
|---|
|  | 361 | } | 
|---|
|  | 362 | oldCenter *= 1./(double)i; | 
|---|
|  | 363 | newCenter *= 1./(double)i; | 
|---|
| [0d5ca7] | 364 | LOG(4, "DEBUG: oldCenter is " << oldCenter << ", newCenter is " << newCenter); | 
|---|
|  | 365 |  | 
|---|
|  | 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); | 
|---|
| [0d4daf] | 376 | } | 
|---|
| [0d5ca7] | 377 | // rotate _newpolygon | 
|---|
|  | 378 | SphericalPointDistribution::Polygon_t rotated_newpolygon = | 
|---|
|  | 379 | rotatePolygon(_newpolygon, angles); | 
|---|
|  | 380 | LOG(5, "DEBUG: Rotated new polygon is " << rotated_newpolygon); | 
|---|
|  | 381 |  | 
|---|
|  | 382 | const Line RotationAxis(zeroVec, oldCenter); | 
|---|
| [0d4daf] | 383 | const double RotationAngle = | 
|---|
| [0d5ca7] | 384 | oldCenter.Angle(remainingold[0]) | 
|---|
|  | 385 | - oldCenter.Angle(remainingnew[*MCS.bestmatching.begin()]); | 
|---|
|  | 386 | LOG(5, "DEBUG: Rotate around self is " << RotationAngle | 
|---|
| [90426a] | 387 | << " around axis " << RotationAxis); | 
|---|
| [0d4daf] | 388 |  | 
|---|
| [0d5ca7] | 389 | for (SphericalPointDistribution::Polygon_t::iterator iter = rotated_newpolygon.begin(); | 
|---|
|  | 390 | iter != rotated_newpolygon.end(); ++iter) { | 
|---|
|  | 391 | RotationAxis.rotateVector(*iter, RotationAngle); | 
|---|
|  | 392 | } | 
|---|
| [0d4daf] | 393 |  | 
|---|
|  | 394 | // remove all points in matching and return remaining ones | 
|---|
| [0d5ca7] | 395 | SphericalPointDistribution::Polygon_t remainingpoints = | 
|---|
|  | 396 | removeMatchingPoints(rotated_newpolygon, MCS.bestmatching); | 
|---|
|  | 397 | LOG(2, "INFO: Remaining points are " << remainingpoints); | 
|---|
|  | 398 | return remainingpoints; | 
|---|
| [0d4daf] | 399 | } else | 
|---|
|  | 400 | return _newpolygon; | 
|---|
|  | 401 | } | 
|---|
|  | 402 |  | 
|---|
|  | 403 |  | 
|---|