- Timestamp:
- May 25, 2016, 7:13:57 AM (9 years ago)
- Children:
- 81557e
- Parents:
- 3b6956
- git-author:
- Frederik Heber <heber@…> (05/10/16 18:33:50)
- git-committer:
- Frederik Heber <heber@…> (05/25/16 07:13:57)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/Fragmentation/Exporters/SphericalPointDistribution.cpp
r3b6956 rd468b5 38 38 39 39 #include "CodePatterns/Assert.hpp" 40 #include "CodePatterns/Log.hpp" 40 #include "CodePatterns/IteratorAdaptors.hpp" 41 #include "CodePatterns/toString.hpp" 41 42 42 43 #include <algorithm> 44 #include <cmath> 45 #include <limits> 46 #include <list> 43 47 #include <vector> 48 #include <map> 44 49 45 50 #include "LinearAlgebra/Line.hpp" … … 47 52 #include "LinearAlgebra/Vector.hpp" 48 53 49 void SphericalPointDistribution::initSelf(const int _NumberOfPoints) 50 { 51 switch (_NumberOfPoints) 52 { 53 case 0: 54 points = get<0>(); 55 break; 56 case 1: 57 points = get<1>(); 58 break; 59 case 2: 60 points = get<2>(); 61 break; 62 case 3: 63 points = get<3>(); 64 break; 65 case 4: 66 points = get<4>(); 67 break; 68 case 5: 69 points = get<5>(); 70 break; 71 case 6: 72 points = get<6>(); 73 break; 74 case 7: 75 points = get<7>(); 76 break; 77 case 8: 78 points = get<8>(); 79 break; 80 case 9: 81 points = get<9>(); 82 break; 83 case 10: 84 points = get<10>(); 85 break; 86 case 11: 87 points = get<11>(); 88 break; 89 case 12: 90 points = get<12>(); 91 break; 92 case 14: 93 points = get<14>(); 94 break; 95 default: 96 ASSERT(0, "SphericalPointDistribution::initSelf() - cannot deal with the case " 97 +toString(_NumberOfPoints)+"."); 98 } 99 LOG(3, "DEBUG: Ideal polygon is " << points); 100 } 101 54 typedef std::list<unsigned int> IndexList_t; 55 typedef std::vector<unsigned int> IndexArray_t; 56 typedef std::vector<Vector> VectorArray_t; 57 typedef std::vector<double> DistanceArray_t; 58 59 DistanceArray_t calculatePairwiseDistances( 60 const std::vector<Vector> &_points, 61 const IndexList_t &_indices 62 ) 63 { 64 DistanceArray_t result; 65 for (IndexList_t::const_iterator firstiter = _indices.begin(); 66 firstiter != _indices.end(); ++firstiter) { 67 for (IndexList_t::const_iterator seconditer = firstiter; 68 seconditer != _indices.end(); ++seconditer) { 69 if (firstiter == seconditer) 70 continue; 71 const double distance = (_points[*firstiter] - _points[*seconditer]).NormSquared(); 72 result.push_back(distance); 73 } 74 } 75 return result; 76 } 77 78 // class generator: taken from www.cplusplus.com example std::generate 79 struct c_unique { 80 int current; 81 c_unique() {current=0;} 82 int operator()() {return ++current;} 83 } UniqueNumber; 84 85 /** Returns squared L2 error of the given \a _Matching. 86 * 87 * We compare the pair-wise distances of each associated matching 88 * and check whether these distances each match between \a _old and 89 * \a _new. 90 * 91 * \param _old first set of points (fewer or equal to \a _new) 92 * \param _new second set of points 93 * \param _Matching matching between the two sets 94 * \return pair with L1 and squared L2 error 95 */ 96 std::pair<double, double> calculateErrorOfMatching( 97 const std::vector<Vector> &_old, 98 const std::vector<Vector> &_new, 99 const IndexList_t &_Matching) 100 { 101 std::pair<double, double> errors( std::make_pair( 0., 0. ) ); 102 103 if (_Matching.size() > 1) { 104 // convert matching into two vectors to calculate distance among another 105 106 // calculate all pair-wise distances 107 IndexList_t keys(_Matching.size()); 108 std::generate (keys.begin(), keys.end(), UniqueNumber); 109 const DistanceArray_t firstdistances = calculatePairwiseDistances(_old, keys); 110 const DistanceArray_t seconddistances = calculatePairwiseDistances(_new, _Matching); 111 112 ASSERT( firstdistances.size() == seconddistances.size(), 113 "calculateL2ErrorOfMatching() - mismatch in pair-wise distance array sizes."); 114 DistanceArray_t::const_iterator firstiter = firstdistances.begin(); 115 DistanceArray_t::const_iterator seconditer = seconddistances.begin(); 116 for (;(firstiter != firstdistances.end()) && (seconditer != seconddistances.end()); 117 ++firstiter, ++seconditer) { 118 const double gap = *firstiter - *seconditer; 119 // L1 error 120 if (errors.first < gap) 121 errors.first = gap; 122 // L2 error 123 errors.second += gap*gap; 124 } 125 } 126 127 return errors; 128 } 129 130 SphericalPointDistribution::Polygon_t removeMatchingPoints( 131 const SphericalPointDistribution::Polygon_t &_points, 132 const IndexList_t &_matchingindices 133 ) 134 { 135 SphericalPointDistribution::Polygon_t remainingpoints; 136 IndexArray_t indices(_matchingindices.begin(), _matchingindices.end()); 137 std::sort(indices.begin(), indices.end()); 138 IndexArray_t::const_iterator valueiter = indices.begin(); 139 SphericalPointDistribution::Polygon_t::const_iterator pointiter = 140 _points.begin(); 141 for (unsigned int i=0; i< _points.size(); ++i, ++pointiter) { 142 // skip all those in values 143 if (*valueiter == i) 144 ++valueiter; 145 else 146 remainingpoints.push_back(*pointiter); 147 } 148 149 return remainingpoints; 150 } 151 152 /** Rotates a given polygon around x, y, and z axis by the given angles. 153 * 154 * Essentially, we concentrate on the three points of the polygon to rotate 155 * to the correct position. First, we rotate its center via \a angles, 156 * then we rotate the "triangle" around itself/\a _RotationAxis by 157 * \a _RotationAngle. 158 * 159 * \param _polygon polygon whose points to rotate 160 * \param _angles vector with rotation angles for x,y,z axis 161 * \param _RotationAxis 162 * \param _RotationAngle 163 */ 164 SphericalPointDistribution::Polygon_t rotatePolygon( 165 const SphericalPointDistribution::Polygon_t &_polygon, 166 const std::vector<double> &_angles, 167 const Line &_RotationAxis, 168 const double _RotationAngle) 169 { 170 SphericalPointDistribution::Polygon_t rotated_polygon = _polygon; 171 RealSpaceMatrix rotation; 172 ASSERT( _angles.size() == 3, 173 "rotatePolygon() - not exactly "+toString(3)+" angles given."); 174 rotation.setRotation(_angles[0] * M_PI/180., _angles[1] * M_PI/180., _angles[2] * M_PI/180.); 175 176 // apply rotation angles 177 for (SphericalPointDistribution::Polygon_t::iterator iter = rotated_polygon.begin(); 178 iter != rotated_polygon.end(); ++iter) { 179 *iter = rotation * (*iter); 180 _RotationAxis.rotateVector(*iter, _RotationAngle); 181 } 182 183 return rotated_polygon; 184 } 185 186 struct MatchingControlStructure { 187 bool foundflag; 188 double bestL2; 189 IndexList_t bestmatching; 190 VectorArray_t oldpoints; 191 VectorArray_t newpoints; 192 }; 193 194 /** Recursive function to go through all possible matchings. 195 * 196 * \param _MCS structure holding global information to the recursion 197 * \param _matching current matching being build up 198 * \param _indices contains still available indices 199 * \param _matchingsize 200 */ 201 void recurseMatchings( 202 MatchingControlStructure &_MCS, 203 IndexList_t &_matching, 204 IndexList_t _indices, 205 unsigned int _matchingsize) 206 { 207 //!> threshold for L1 error below which matching is immediately acceptable 208 const double L1THRESHOLD = 1e-2; 209 if (!_MCS.foundflag) { 210 if (_matching.size() < _matchingsize) { 211 // go through all indices 212 for (IndexList_t::iterator iter = _indices.begin(); 213 iter != _indices.end();) { 214 // add index to matching 215 _matching.push_back(*iter); 216 // remove index but keep iterator to position (is the next to erase element) 217 IndexList_t::iterator backupiter = _indices.erase(iter); 218 // recurse with decreased _matchingsize 219 recurseMatchings(_MCS, _matching, _indices, _matchingsize-1); 220 // re-add chosen index and reset index to new position 221 _indices.insert(backupiter, _matching.back()); 222 iter = backupiter; 223 // remove index from _matching to make space for the next one 224 _matching.pop_back(); 225 } 226 // gone through all indices then exit recursion 227 _MCS.foundflag = true; 228 } else { 229 // calculate errors 230 std::pair<double, double> errors = calculateErrorOfMatching( 231 _MCS.oldpoints, _MCS.newpoints, _matching); 232 if (errors.first < L1THRESHOLD) { 233 _MCS.bestmatching = _matching; 234 _MCS.foundflag = true; 235 } 236 if (_MCS.bestL2 > errors.second) { 237 _MCS.bestmatching = _matching; 238 _MCS.bestL2 = errors.second; 239 } 240 } 241 } 242 } 243 244 SphericalPointDistribution::Polygon_t 245 SphericalPointDistribution::matchSphericalPointDistributions( 246 const SphericalPointDistribution::Polygon_t &_polygon, 247 const SphericalPointDistribution::Polygon_t &_newpolygon 248 ) 249 { 250 SphericalPointDistribution::Polygon_t remainingpoints; 251 VectorArray_t remainingold(_polygon.begin(), _polygon.end()); 252 VectorArray_t remainingnew(_newpolygon.begin(), _newpolygon.end()); 253 254 if (_polygon.size() > 0) { 255 MatchingControlStructure MCS; 256 MCS.foundflag = false; 257 MCS.bestL2 = std::numeric_limits<double>::max(); 258 MCS.oldpoints.insert(MCS.oldpoints.begin(), _polygon.begin(),_polygon.end() ); 259 MCS.newpoints.insert(MCS.newpoints.begin(), _newpolygon.begin(),_newpolygon.end() ); 260 261 // search for bestmatching combinatorially 262 { 263 // translate polygon into vector to enable index addressing 264 IndexList_t indices(_newpolygon.size()); 265 std::generate(indices.begin(), indices.end(), UniqueNumber); 266 IndexList_t matching; 267 268 // walk through all matchings 269 const unsigned int matchingsize = _polygon.size(); 270 ASSERT( matchingsize <= indices.size(), 271 "SphericalPointDistribution::matchSphericalPointDistributions() - not enough new points to choose for matching to old ones."); 272 recurseMatchings(MCS, matching, indices, matchingsize); 273 } 274 275 // determine rotation angles to align the two point distributions with 276 // respect to bestmatching 277 std::vector<double> angles(3); 278 Vector newCenter; 279 { 280 // calculate center of triangle/line/point consisting of first points of matching 281 Vector oldCenter; 282 IndexList_t::const_iterator iter = MCS.bestmatching.begin(); 283 unsigned int i = 0; 284 for (; (i<3) && (i<MCS.bestmatching.size()); ++i, ++iter) { 285 oldCenter += remainingold[i]; 286 newCenter += remainingnew[*iter]; 287 } 288 oldCenter *= 1./(double)i; 289 newCenter *= 1./(double)i; 290 291 Vector direction(0.,0.,0.); 292 for(size_t i=0;i<NDIM;++i) { 293 // create new rotation axis 294 direction[i] = 1.; 295 const Line axis (zeroVec, direction); 296 // calculate rotation angle for this axis 297 const double alpha = direction.Angle(oldCenter) - direction.Angle(newCenter); 298 // perform rotation 299 axis.rotateVector(newCenter, alpha); 300 // store angle 301 angles[i] = alpha; 302 // reset direction component for next iteration 303 direction[i] = 0.; 304 } 305 } 306 const Line RotationAxis(zeroVec, newCenter); 307 const double RotationAngle = 308 newCenter.Angle(remainingold[0]) 309 - newCenter.Angle(remainingnew[*MCS.bestmatching.begin()]); 310 311 // rotate _newpolygon 312 SphericalPointDistribution::Polygon_t rotated_newpolygon = 313 rotatePolygon(_newpolygon, angles, RotationAxis, RotationAngle); 314 315 // remove all points in matching and return remaining ones 316 return removeMatchingPoints(rotated_newpolygon, MCS.bestmatching); 317 } else 318 return _newpolygon; 319 } 320 321 322
Note:
See TracChangeset
for help on using the changeset viewer.
