source: src/Fragmentation/Exporters/SphericalPointDistribution.cpp@ 3da643

Last change on this file since 3da643 was 3da643, checked in by Frederik Heber <heber@…>, 11 years ago

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.
  • Property mode set to 100644
File size: 22.8 KB
Line 
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"
41#include "CodePatterns/Log.hpp"
42#include "CodePatterns/toString.hpp"
43
44#include <algorithm>
45#include <boost/math/quaternion.hpp>
46#include <cmath>
47#include <functional>
48#include <iterator>
49#include <limits>
50#include <list>
51#include <vector>
52#include <map>
53
54#include "LinearAlgebra/Line.hpp"
55#include "LinearAlgebra/Plane.hpp"
56#include "LinearAlgebra/RealSpaceMatrix.hpp"
57#include "LinearAlgebra/Vector.hpp"
58
59// static entities
60const double SphericalPointDistribution::warn_amplitude = 1e-2;
61
62typedef std::vector<double> DistanceArray_t;
63
64inline
65DistanceArray_t calculatePairwiseDistances(
66 const std::vector<Vector> &_points,
67 const SphericalPointDistribution::IndexList_t &_indices
68 )
69{
70 DistanceArray_t result;
71 for (SphericalPointDistribution::IndexList_t::const_iterator firstiter = _indices.begin();
72 firstiter != _indices.end(); ++firstiter) {
73 for (SphericalPointDistribution::IndexList_t::const_iterator seconditer = firstiter;
74 seconditer != _indices.end(); ++seconditer) {
75 if (firstiter == seconditer)
76 continue;
77 const double distance = (_points[*firstiter] - _points[*seconditer]).NormSquared();
78 result.push_back(distance);
79 }
80 }
81 return result;
82}
83
84// class generator: taken from www.cplusplus.com example std::generate
85struct c_unique {
86 int current;
87 c_unique() {current=0;}
88 int operator()() {return current++;}
89} UniqueNumber;
90
91/** Returns squared L2 error of the given \a _Matching.
92 *
93 * We compare the pair-wise distances of each associated matching
94 * and check whether these distances each match between \a _old and
95 * \a _new.
96 *
97 * \param _old first set of points (fewer or equal to \a _new)
98 * \param _new second set of points
99 * \param _Matching matching between the two sets
100 * \return pair with L1 and squared L2 error
101 */
102std::pair<double, double> SphericalPointDistribution::calculateErrorOfMatching(
103 const std::vector<Vector> &_old,
104 const std::vector<Vector> &_new,
105 const IndexList_t &_Matching)
106{
107 std::pair<double, double> errors( std::make_pair( 0., 0. ) );
108
109 if (_Matching.size() > 1) {
110 LOG(3, "INFO: Matching is " << _Matching);
111
112 // calculate all pair-wise distances
113 IndexList_t keys(_Matching.size());
114 std::generate (keys.begin(), keys.end(), UniqueNumber);
115 const DistanceArray_t firstdistances = calculatePairwiseDistances(_old, keys);
116 const DistanceArray_t seconddistances = calculatePairwiseDistances(_new, _Matching);
117
118 ASSERT( firstdistances.size() == seconddistances.size(),
119 "calculateL2ErrorOfMatching() - mismatch in pair-wise distance array sizes.");
120 DistanceArray_t::const_iterator firstiter = firstdistances.begin();
121 DistanceArray_t::const_iterator seconditer = seconddistances.begin();
122 for (;(firstiter != firstdistances.end()) && (seconditer != seconddistances.end());
123 ++firstiter, ++seconditer) {
124 const double gap = *firstiter - *seconditer;
125 // L1 error
126 if (errors.first < gap)
127 errors.first = gap;
128 // L2 error
129 errors.second += gap*gap;
130 }
131 } else
132 ELOG(3, "calculateErrorOfMatching() - Given matching's size is less than 2.");
133 LOG(3, "INFO: Resulting errors for matching (L1, L2): "
134 << errors.first << "," << errors.second << ".");
135
136 return errors;
137}
138
139SphericalPointDistribution::Polygon_t SphericalPointDistribution::removeMatchingPoints(
140 const VectorArray_t &_points,
141 const IndexList_t &_matchingindices
142 )
143{
144 SphericalPointDistribution::Polygon_t remainingpoints;
145 IndexArray_t indices(_matchingindices.begin(), _matchingindices.end());
146 std::sort(indices.begin(), indices.end());
147 LOG(4, "DEBUG: sorted matching is " << indices);
148 IndexArray_t remainingindices(_points.size(), -1);
149 std::generate(remainingindices.begin(), remainingindices.end(), UniqueNumber);
150 IndexArray_t::iterator remainiter = std::set_difference(
151 remainingindices.begin(), remainingindices.end(),
152 indices.begin(), indices.end(),
153 remainingindices.begin());
154 remainingindices.erase(remainiter, remainingindices.end());
155 LOG(4, "DEBUG: remaining indices are " << remainingindices);
156 for (IndexArray_t::const_iterator iter = remainingindices.begin();
157 iter != remainingindices.end(); ++iter) {
158 remainingpoints.push_back(_points[*iter]);
159 }
160
161 return remainingpoints;
162}
163
164/** Recursive function to go through all possible matchings.
165 *
166 * \param _MCS structure holding global information to the recursion
167 * \param _matching current matching being build up
168 * \param _indices contains still available indices
169 * \param _matchingsize
170 */
171void SphericalPointDistribution::recurseMatchings(
172 MatchingControlStructure &_MCS,
173 IndexList_t &_matching,
174 IndexList_t _indices,
175 unsigned int _matchingsize)
176{
177 LOG(4, "DEBUG: Recursing with current matching " << _matching
178 << ", remaining indices " << _indices
179 << ", and sought size " << _matching.size()+_matchingsize);
180 //!> threshold for L1 error below which matching is immediately acceptable
181 const double L1THRESHOLD = 1e-2;
182 if (!_MCS.foundflag) {
183 LOG(4, "DEBUG: Current matching has size " << _matching.size() << ", places left " << _matchingsize);
184 if (_matchingsize > 0) {
185 // go through all indices
186 for (IndexList_t::iterator iter = _indices.begin();
187 (iter != _indices.end()) && (!_MCS.foundflag);) {
188 // add index to matching
189 _matching.push_back(*iter);
190 LOG(5, "DEBUG: Adding " << *iter << " to matching.");
191 // remove index but keep iterator to position (is the next to erase element)
192 IndexList_t::iterator backupiter = _indices.erase(iter);
193 // recurse with decreased _matchingsize
194 recurseMatchings(_MCS, _matching, _indices, _matchingsize-1);
195 // re-add chosen index and reset index to new position
196 _indices.insert(backupiter, _matching.back());
197 iter = backupiter;
198 // remove index from _matching to make space for the next one
199 _matching.pop_back();
200 }
201 // gone through all indices then exit recursion
202 if (_matching.empty())
203 _MCS.foundflag = true;
204 } else {
205 LOG(3, "INFO: Found matching " << _matching);
206 // calculate errors
207 std::pair<double, double> errors = calculateErrorOfMatching(
208 _MCS.oldpoints, _MCS.newpoints, _matching);
209 if (errors.first < L1THRESHOLD) {
210 _MCS.bestmatching = _matching;
211 _MCS.foundflag = true;
212 } else if (_MCS.bestL2 > errors.second) {
213 _MCS.bestmatching = _matching;
214 _MCS.bestL2 = errors.second;
215 }
216 }
217 }
218}
219
220/** Decides by an orthonormal third vector whether the sign of the rotation
221 * angle should be negative or positive.
222 *
223 * \return -1 or 1
224 */
225inline
226double determineSignOfRotation(
227 const Vector &_oldPosition,
228 const Vector &_newPosition,
229 const Vector &_RotationAxis
230 )
231{
232 Vector dreiBein(_oldPosition);
233 dreiBein.VectorProduct(_RotationAxis);
234 dreiBein.Normalize();
235 const double sign =
236 (dreiBein.ScalarProduct(_newPosition) < 0.) ? -1. : +1.;
237 LOG(6, "DEBUG: oldCenter on plane is " << _oldPosition
238 << ", newCenter in plane is " << _newPosition
239 << ", and dreiBein is " << dreiBein);
240 return sign;
241}
242
243/** Finds combinatorially the best matching between points in \a _polygon
244 * and \a _newpolygon.
245 *
246 * We find the matching with the smallest L2 error, where we break when we stumble
247 * upon a matching with zero error.
248 *
249 * \sa recurseMatchings() for going through all matchings
250 *
251 * \param _polygon here, we have indices 0,1,2,...
252 * \param _newpolygon and here we need to find the correct indices
253 * \return list of indices: first in \a _polygon goes to first index for \a _newpolygon
254 */
255SphericalPointDistribution::IndexList_t SphericalPointDistribution::findBestMatching(
256 const SphericalPointDistribution::Polygon_t &_polygon,
257 const SphericalPointDistribution::Polygon_t &_newpolygon
258 )
259{
260 MatchingControlStructure MCS;
261 MCS.foundflag = false;
262 MCS.bestL2 = std::numeric_limits<double>::max();
263 MCS.oldpoints.insert(MCS.oldpoints.begin(), _polygon.begin(),_polygon.end() );
264 MCS.newpoints.insert(MCS.newpoints.begin(), _newpolygon.begin(),_newpolygon.end() );
265
266 // search for bestmatching combinatorially
267 {
268 // translate polygon into vector to enable index addressing
269 IndexList_t indices(_newpolygon.size());
270 std::generate(indices.begin(), indices.end(), UniqueNumber);
271 IndexList_t matching;
272
273 // walk through all matchings
274 const unsigned int matchingsize = _polygon.size();
275 ASSERT( matchingsize <= indices.size(),
276 "SphericalPointDistribution::matchSphericalPointDistributions() - not enough new points to choose for matching to old ones.");
277 recurseMatchings(MCS, matching, indices, matchingsize);
278 }
279 return MCS.bestmatching;
280}
281
282inline
283Vector calculateCenter(
284 const SphericalPointDistribution::VectorArray_t &_positions,
285 const SphericalPointDistribution::IndexList_t &_indices)
286{
287 Vector Center;
288 Center.Zero();
289 for (SphericalPointDistribution::IndexList_t::const_iterator iter = _indices.begin();
290 iter != _indices.end(); ++iter)
291 Center += _positions[*iter];
292 if (!_indices.empty())
293 Center *= 1./(double)_indices.size();
294
295 return Center;
296}
297
298inline
299void calculateOldAndNewCenters(
300 Vector &_oldCenter,
301 Vector &_newCenter,
302 const SphericalPointDistribution::VectorArray_t &_referencepositions,
303 const SphericalPointDistribution::VectorArray_t &_currentpositions,
304 const SphericalPointDistribution::IndexList_t &_bestmatching)
305{
306 const size_t NumberIds = std::min(_bestmatching.size(), (size_t)3);
307 SphericalPointDistribution::IndexList_t continuousIds(NumberIds, -1);
308 std::generate(continuousIds.begin(), continuousIds.end(), UniqueNumber);
309 _oldCenter = calculateCenter(_referencepositions, continuousIds);
310 // C++11 defines a copy_n function ...
311 SphericalPointDistribution::IndexList_t::const_iterator enditer = _bestmatching.begin();
312 std::advance(enditer, NumberIds);
313 SphericalPointDistribution::IndexList_t firstbestmatchingIds(NumberIds, -1);
314 std::copy(_bestmatching.begin(), enditer, firstbestmatchingIds.begin());
315 _newCenter = calculateCenter( _currentpositions, firstbestmatchingIds);
316}
317
318SphericalPointDistribution::Rotation_t SphericalPointDistribution::findPlaneAligningRotation(
319 const VectorArray_t &_referencepositions,
320 const VectorArray_t &_currentpositions,
321 const IndexList_t &_bestmatching
322 )
323{
324 bool dontcheck = false;
325 // initialize to no rotation
326 Rotation_t Rotation;
327 Rotation.first.Zero();
328 Rotation.first[0] = 1.;
329 Rotation.second = 0.;
330
331 // calculate center of triangle/line/point consisting of first points of matching
332 Vector oldCenter;
333 Vector newCenter;
334 calculateOldAndNewCenters(
335 oldCenter, newCenter,
336 _referencepositions, _currentpositions, _bestmatching);
337
338 if ((!oldCenter.IsZero()) && (!newCenter.IsZero())) {
339 LOG(4, "DEBUG: oldCenter is " << oldCenter << ", newCenter is " << newCenter);
340 oldCenter.Normalize();
341 newCenter.Normalize();
342 if (!oldCenter.IsEqualTo(newCenter)) {
343 // calculate rotation axis and angle
344 Rotation.first = oldCenter;
345 Rotation.first.VectorProduct(newCenter);
346 Rotation.second = oldCenter.Angle(newCenter); // /(M_PI/2.);
347 } else {
348 // no rotation required anymore
349 }
350 } else {
351 LOG(4, "DEBUG: oldCenter is " << oldCenter << ", newCenter is " << newCenter);
352 if ((oldCenter.IsZero()) && (newCenter.IsZero())) {
353 // either oldCenter or newCenter (or both) is directly at origin
354 if (_bestmatching.size() == 2) {
355 // line case
356 Vector oldPosition = _currentpositions[*_bestmatching.begin()];
357 Vector newPosition = _referencepositions[0];
358 // check whether we need to rotate at all
359 if (!oldPosition.IsEqualTo(newPosition)) {
360 Rotation.first = oldPosition;
361 Rotation.first.VectorProduct(newPosition);
362 // orientation will fix the sign here eventually
363 Rotation.second = oldPosition.Angle(newPosition);
364 } else {
365 // no rotation required anymore
366 }
367 } else {
368 // triangle case
369 // both triangles/planes have same center, hence get axis by
370 // VectorProduct of Normals
371 Plane newplane(_referencepositions[0], _referencepositions[1], _referencepositions[2]);
372 VectorArray_t vectors;
373 for (IndexList_t::const_iterator iter = _bestmatching.begin();
374 iter != _bestmatching.end(); ++iter)
375 vectors.push_back(_currentpositions[*iter]);
376 Plane oldplane(vectors[0], vectors[1], vectors[2]);
377 Vector oldPosition = oldplane.getNormal();
378 Vector newPosition = newplane.getNormal();
379 // check whether we need to rotate at all
380 if (!oldPosition.IsEqualTo(newPosition)) {
381 Rotation.first = oldPosition;
382 Rotation.first.VectorProduct(newPosition);
383 Rotation.first.Normalize();
384
385 // construct reference vector to determine direction of rotation
386 const double sign = determineSignOfRotation(oldPosition, newPosition, Rotation.first);
387 Rotation.second = sign * oldPosition.Angle(newPosition);
388 LOG(5, "DEBUG: Rotating plane normals by " << Rotation.second
389 << " around axis " << Rotation.first);
390 } else {
391 // else do nothing
392 }
393 }
394 } else {
395 // TODO: we can't do anything here, but this case needs to be dealt with when
396 // we have no ideal geometries anymore
397 if ((oldCenter-newCenter).Norm() > warn_amplitude)
398 ELOG(2, "oldCenter is " << oldCenter << ", yet newCenter is " << newCenter);
399 // else they are considered close enough
400 dontcheck = true;
401 }
402 }
403
404#ifndef NDEBUG
405 // check: rotation brings newCenter onto oldCenter position
406 if (!dontcheck) {
407 Line Axis(zeroVec, Rotation.first);
408 Vector test = Axis.rotateVector(newCenter, Rotation.second);
409 LOG(4, "CHECK: rotated newCenter is " << test
410 << ", oldCenter is " << oldCenter);
411 ASSERT( (test - oldCenter).NormSquared() < std::numeric_limits<double>::epsilon()*1e4,
412 "matchSphericalPointDistributions() - rotation does not work as expected by "
413 +toString((test - oldCenter).NormSquared())+".");
414 }
415#endif
416
417 return Rotation;
418}
419
420SphericalPointDistribution::Rotation_t SphericalPointDistribution::findPointAligningRotation(
421 const VectorArray_t &remainingold,
422 const VectorArray_t &remainingnew,
423 const IndexList_t &_bestmatching)
424{
425 // initialize rotation to zero
426 Rotation_t Rotation;
427 Rotation.first.Zero();
428 Rotation.first[0] = 1.;
429 Rotation.second = 0.;
430
431 // recalculate center
432 Vector oldCenter;
433 Vector newCenter;
434 calculateOldAndNewCenters(
435 oldCenter, newCenter,
436 remainingold, remainingnew, _bestmatching);
437
438 Vector oldPosition = remainingnew[*_bestmatching.begin()];
439 Vector newPosition = remainingold[0];
440 LOG(6, "DEBUG: oldPosition is " << oldPosition << " and newPosition is " << newPosition);
441 if (!oldPosition.IsEqualTo(newPosition)) {
442 if ((!oldCenter.IsZero()) && (!newCenter.IsZero())) {
443 oldCenter.Normalize(); // note weighted sum of normalized weight is not normalized
444 Rotation.first = oldCenter;
445 LOG(6, "DEBUG: Picking normalized oldCenter as Rotation.first " << oldCenter);
446 oldPosition.ProjectOntoPlane(Rotation.first);
447 newPosition.ProjectOntoPlane(Rotation.first);
448 LOG(6, "DEBUG: Positions after projection are " << oldPosition << " and " << newPosition);
449 } else {
450 if (_bestmatching.size() == 2) {
451 // line situation
452 try {
453 Plane oldplane(oldPosition, oldCenter, newPosition);
454 Rotation.first = oldplane.getNormal();
455 LOG(6, "DEBUG: Plane is " << oldplane << " and normal is " << Rotation.first);
456 } catch (LinearDependenceException &e) {
457 LOG(6, "DEBUG: Vectors defining plane are linearly dependent.");
458 // oldPosition and newPosition are on a line, just flip when not equal
459 if (!oldPosition.IsEqualTo(newPosition)) {
460 Rotation.first.Zero();
461 Rotation.first.GetOneNormalVector(oldPosition);
462 LOG(6, "DEBUG: For flipping we use Rotation.first " << Rotation.first);
463 assert( Rotation.first.ScalarProduct(oldPosition) < std::numeric_limits<double>::epsilon()*1e4);
464 // Rotation.second = M_PI;
465 } else {
466 LOG(6, "DEBUG: oldPosition and newPosition are equivalent.");
467 }
468 }
469 } else {
470 // triangle situation
471 Plane oldplane(remainingold[0], remainingold[1], remainingold[2]);
472 Rotation.first = oldplane.getNormal();
473 LOG(6, "DEBUG: oldPlane is " << oldplane << " and normal is " << Rotation.first);
474 oldPosition.ProjectOntoPlane(Rotation.first);
475 LOG(6, "DEBUG: Positions after projection are " << oldPosition << " and " << newPosition);
476 }
477 }
478 // construct reference vector to determine direction of rotation
479 const double sign = determineSignOfRotation(oldPosition, newPosition, Rotation.first);
480 Rotation.second = sign * oldPosition.Angle(newPosition);
481 } else {
482 LOG(6, "DEBUG: oldPosition and newPosition are equivalent, hence no orientating rotation.");
483 }
484
485 return Rotation;
486}
487
488
489SphericalPointDistribution::Polygon_t
490SphericalPointDistribution::matchSphericalPointDistributions(
491 const SphericalPointDistribution::Polygon_t &_polygon,
492 const SphericalPointDistribution::Polygon_t &_newpolygon
493 )
494{
495 SphericalPointDistribution::Polygon_t remainingpoints;
496 VectorArray_t remainingold(_polygon.begin(), _polygon.end());
497 VectorArray_t remainingnew(_newpolygon.begin(), _newpolygon.end());
498 LOG(2, "INFO: Matching old polygon " << _polygon
499 << " with new polygon " << _newpolygon);
500
501 if (_polygon.size() == _newpolygon.size()) {
502 // same number of points desired as are present? Do nothing
503 LOG(2, "INFO: There are no vacant points to return.");
504 return remainingpoints;
505 }
506
507 if (_polygon.size() > 0) {
508 IndexList_t bestmatching = findBestMatching(_polygon, _newpolygon);
509 LOG(2, "INFO: Best matching is " << bestmatching);
510
511 // determine rotation angles to align the two point distributions with
512 // respect to bestmatching:
513 // we use the center between the three first matching points
514 /// the first rotation brings these two centers to coincide
515 VectorArray_t rotated_newpolygon = remainingnew;
516 {
517 Rotation_t Rotation = findPlaneAligningRotation(
518 remainingold,
519 remainingnew,
520 bestmatching);
521 LOG(5, "DEBUG: Rotating coordinate system by " << Rotation.second
522 << " around axis " << Rotation.first);
523 Line Axis(zeroVec, Rotation.first);
524
525 // apply rotation angle to bring newCenter to oldCenter
526 for (VectorArray_t::iterator iter = rotated_newpolygon.begin();
527 iter != rotated_newpolygon.end(); ++iter) {
528 Vector &current = *iter;
529 LOG(6, "DEBUG: Original point is " << current);
530 current = Axis.rotateVector(current, Rotation.second);
531 LOG(6, "DEBUG: Rotated point is " << current);
532 }
533
534#ifndef NDEBUG
535 // check: rotated "newCenter" should now equal oldCenter
536 {
537 Vector oldCenter;
538 Vector rotatednewCenter;
539 calculateOldAndNewCenters(
540 oldCenter, rotatednewCenter,
541 remainingold, rotated_newpolygon, bestmatching);
542 // NOTE: Center must not necessarily lie on the sphere with norm 1, hence, we
543 // have to normalize it just as before, as oldCenter and newCenter lengths may differ.
544 if ((!oldCenter.IsZero()) && (!rotatednewCenter.IsZero())) {
545 oldCenter.Normalize();
546 rotatednewCenter.Normalize();
547 LOG(4, "CHECK: rotatednewCenter is " << rotatednewCenter
548 << ", oldCenter is " << oldCenter);
549 ASSERT( (rotatednewCenter - oldCenter).NormSquared() < std::numeric_limits<double>::epsilon()*1e4,
550 "matchSphericalPointDistributions() - rotation does not work as expected by "
551 +toString((rotatednewCenter - oldCenter).NormSquared())+".");
552 }
553 }
554#endif
555 }
556 /// the second (orientation) rotation aligns the planes such that the
557 /// points themselves coincide
558 if (bestmatching.size() > 1) {
559 Rotation_t Rotation = findPointAligningRotation(
560 remainingold,
561 rotated_newpolygon,
562 bestmatching);
563
564 // construct RotationAxis and two points on its plane, defining the angle
565 Rotation.first.Normalize();
566 const Line RotationAxis(zeroVec, Rotation.first);
567
568 LOG(5, "DEBUG: Rotating around self is " << Rotation.second
569 << " around axis " << RotationAxis);
570
571#ifndef NDEBUG
572 // check: first bestmatching in rotated_newpolygon and remainingnew
573 // should now equal
574 {
575 const IndexList_t::const_iterator iter = bestmatching.begin();
576 Vector rotatednew = RotationAxis.rotateVector(
577 rotated_newpolygon[*iter],
578 Rotation.second);
579 LOG(4, "CHECK: rotated first new bestmatching is " << rotatednew
580 << " while old was " << remainingold[0]);
581 ASSERT( (rotatednew - remainingold[0]).Norm() < warn_amplitude,
582 "matchSphericalPointDistributions() - orientation rotation ends up off by more than "
583 +toString(warn_amplitude)+".");
584 }
585#endif
586
587 for (VectorArray_t::iterator iter = rotated_newpolygon.begin();
588 iter != rotated_newpolygon.end(); ++iter) {
589 Vector &current = *iter;
590 LOG(6, "DEBUG: Original point is " << current);
591 current = RotationAxis.rotateVector(current, Rotation.second);
592 LOG(6, "DEBUG: Rotated point is " << current);
593 }
594 }
595
596 // remove all points in matching and return remaining ones
597 SphericalPointDistribution::Polygon_t remainingpoints =
598 removeMatchingPoints(rotated_newpolygon, bestmatching);
599 LOG(2, "INFO: Remaining points are " << remainingpoints);
600 return remainingpoints;
601 } else
602 return _newpolygon;
603}
604
605
Note: See TracBrowser for help on using the repository browser.