Ignore:
Timestamp:
Aug 20, 2014, 1:04:08 PM (11 years ago)
Author:
Frederik Heber <heber@…>
Children:
23c605
Parents:
260540
git-author:
Frederik Heber <heber@…> (06/29/14 21:20:49)
git-committer:
Frederik Heber <heber@…> (08/20/14 13:04:08)
Message:

Extracted joinPoints() function to make it accessible to tests.

  • added unit test.
  • moved some function definitions around and added documentation.
File:
1 edited

Legend:

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

    r260540 r1ae9aa  
    6262typedef std::vector<double> DistanceArray_t;
    6363
     64// class generator: taken from www.cplusplus.com example std::generate
     65struct c_unique {
     66  int current;
     67  c_unique() {current=0;}
     68  int operator()() {return current++;}
     69} UniqueNumber;
     70
    6471inline
    6572DistanceArray_t calculatePairwiseDistances(
     
    8289}
    8390
    84 // class generator: taken from www.cplusplus.com example std::generate
    85 struct c_unique {
    86   int current;
    87   c_unique() {current=0;}
    88   int operator()() {return current++;}
    89 } UniqueNumber;
    90 
     91/** Calculate the center of a given set of points in \a _positions but only
     92 * for those indicated by \a _indices.
     93 *
     94 */
     95inline
     96Vector calculateCenter(
     97    const SphericalPointDistribution::VectorArray_t &_positions,
     98    const SphericalPointDistribution::IndexList_t &_indices)
     99{
     100  Vector Center;
     101  Center.Zero();
     102  for (SphericalPointDistribution::IndexList_t::const_iterator iter = _indices.begin();
     103      iter != _indices.end(); ++iter)
     104    Center += _positions[*iter];
     105  if (!_indices.empty())
     106    Center *= 1./(double)_indices.size();
     107
     108  return Center;
     109}
     110
     111/** Decides by an orthonormal third vector whether the sign of the rotation
     112 * angle should be negative or positive.
     113 *
     114 * \return -1 or 1
     115 */
     116inline
     117double determineSignOfRotation(
     118    const Vector &_oldPosition,
     119    const Vector &_newPosition,
     120    const Vector &_RotationAxis
     121    )
     122{
     123  Vector dreiBein(_oldPosition);
     124  dreiBein.VectorProduct(_RotationAxis);
     125  dreiBein.Normalize();
     126  const double sign =
     127      (dreiBein.ScalarProduct(_newPosition) < 0.) ? -1. : +1.;
     128  LOG(6, "DEBUG: oldCenter on plane is " << _oldPosition
     129      << ", newCenter in plane is " << _newPosition
     130      << ", and dreiBein is " << dreiBein);
     131  return sign;
     132}
     133
     134/** Convenience function to recalculate old and new center for determining plane
     135 * rotation.
     136 */
     137inline
     138void calculateOldAndNewCenters(
     139    Vector &_oldCenter,
     140    Vector &_newCenter,
     141    const SphericalPointDistribution::VectorArray_t &_referencepositions,
     142    const SphericalPointDistribution::VectorArray_t &_currentpositions,
     143    const SphericalPointDistribution::IndexList_t &_bestmatching)
     144{
     145  const size_t NumberIds = std::min(_bestmatching.size(), (size_t)3);
     146  SphericalPointDistribution::IndexList_t continuousIds(NumberIds, -1);
     147  std::generate(continuousIds.begin(), continuousIds.end(), UniqueNumber);
     148  _oldCenter = calculateCenter(_referencepositions, continuousIds);
     149  // C++11 defines a copy_n function ...
     150  SphericalPointDistribution::IndexList_t::const_iterator enditer = _bestmatching.begin();
     151  std::advance(enditer, NumberIds);
     152  SphericalPointDistribution::IndexList_t firstbestmatchingIds(NumberIds, -1);
     153  std::copy(_bestmatching.begin(), enditer, firstbestmatchingIds.begin());
     154  _newCenter = calculateCenter( _currentpositions, firstbestmatchingIds);
     155}
    91156/** Returns squared L2 error of the given \a _Matching.
    92157 *
     
    218283}
    219284
    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  */
    225 inline
    226 double 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 
    243285/** Finds combinatorially the best matching between points in \a _polygon
    244286 * and \a _newpolygon.
     
    246288 * We find the matching with the smallest L2 error, where we break when we stumble
    247289 * upon a matching with zero error.
     290 *
     291 * As points in \a _polygon may be have a weight greater 1 we have to match it to
     292 * multiple points in \a _newpolygon. Eventually, these multiple points are combined
     293 * for their center of weight, which is the only thing follow-up function see of
     294 * these multiple points. Hence, we actually modify \a _newpolygon in the process
     295 * such that the returned IndexList_t indicates a bijective mapping in the end.
    248296 *
    249297 * \sa recurseMatchings() for going through all matchings
     
    254302 */
    255303SphericalPointDistribution::IndexList_t SphericalPointDistribution::findBestMatching(
    256     const SphericalPointDistribution::WeightedPolygon_t &_polygon,
    257     const SphericalPointDistribution::Polygon_t &_newpolygon
     304    const WeightedPolygon_t &_polygon,
     305    Polygon_t &_newpolygon
    258306    )
    259307{
     
    279327    recurseMatchings(MCS, matching, indices, matchingsize);
    280328  }
    281   return MCS.bestmatching;
    282 }
    283 
    284 inline
    285 Vector calculateCenter(
    286     const SphericalPointDistribution::VectorArray_t &_positions,
    287     const SphericalPointDistribution::IndexList_t &_indices)
    288 {
    289   Vector Center;
    290   Center.Zero();
    291   for (SphericalPointDistribution::IndexList_t::const_iterator iter = _indices.begin();
    292       iter != _indices.end(); ++iter)
    293     Center += _positions[*iter];
    294   if (!_indices.empty())
    295     Center *= 1./(double)_indices.size();
    296 
    297   return Center;
    298 }
    299 
    300 inline
    301 void calculateOldAndNewCenters(
    302     Vector &_oldCenter,
    303     Vector &_newCenter,
    304     const SphericalPointDistribution::VectorArray_t &_referencepositions,
    305     const SphericalPointDistribution::VectorArray_t &_currentpositions,
    306     const SphericalPointDistribution::IndexList_t &_bestmatching)
    307 {
    308   const size_t NumberIds = std::min(_bestmatching.size(), (size_t)3);
    309   SphericalPointDistribution::IndexList_t continuousIds(NumberIds, -1);
    310   std::generate(continuousIds.begin(), continuousIds.end(), UniqueNumber);
    311   _oldCenter = calculateCenter(_referencepositions, continuousIds);
    312   // C++11 defines a copy_n function ...
    313   SphericalPointDistribution::IndexList_t::const_iterator enditer = _bestmatching.begin();
    314   std::advance(enditer, NumberIds);
    315   SphericalPointDistribution::IndexList_t firstbestmatchingIds(NumberIds, -1);
    316   std::copy(_bestmatching.begin(), enditer, firstbestmatchingIds.begin());
    317   _newCenter = calculateCenter( _currentpositions, firstbestmatchingIds);
     329
     330  // combine multiple points and create simple IndexList from IndexTupleList
     331  IndexTupleList_t bestmatching;
     332  for (IndexList_t::const_iterator iter = MCS.bestmatching.begin();
     333      iter != MCS.bestmatching.end(); ++iter)
     334    bestmatching.push_back(IndexList_t(1, *iter));
     335  const SphericalPointDistribution::IndexList_t IndexList =
     336      joinPoints(_newpolygon, MCS.newpoints, bestmatching);
     337
     338  return IndexList;
     339}
     340
     341SphericalPointDistribution::IndexList_t SphericalPointDistribution::joinPoints(
     342    Polygon_t &_newpolygon,
     343    const VectorArray_t &_newpoints,
     344    const IndexTupleList_t &_bestmatching
     345    )
     346{
     347  // combine all multiple points
     348  IndexList_t IndexList;
     349  IndexArray_t removalpoints;
     350  unsigned int UniqueIndex = _newpolygon.size(); // all indices up to size are used right now
     351  VectorArray_t newCenters;
     352  newCenters.reserve(_bestmatching.size());
     353  for (IndexTupleList_t::const_iterator tupleiter = _bestmatching.begin();
     354      tupleiter != _bestmatching.end(); ++tupleiter) {
     355    ASSERT (tupleiter->size() > 0,
     356        "findBestMatching() - encountered tuple in bestmatching with size 0.");
     357    if (tupleiter->size() == 1) {
     358      // add point and index
     359      IndexList.push_back(*tupleiter->begin());
     360    } else {
     361      // combine into weighted and normalized center
     362      Vector Center = calculateCenter(_newpoints, *tupleiter);
     363      Center.Normalize();
     364      _newpolygon.push_back(Center);
     365      LOG(5, "DEBUG: Combining " << tupleiter->size() << "points to weighted center "
     366          << Center << " with new index " << UniqueIndex);
     367      // mark for removal
     368      removalpoints.insert(removalpoints.end(), tupleiter->begin(), tupleiter->end());
     369      // add new index
     370      IndexList.push_back(UniqueIndex++);
     371    }
     372  }
     373  // IndexList is now our new bestmatching (that is bijective)
     374  LOG(4, "DEBUG: Our new bijective IndexList reads as " << IndexList);
     375
     376  // modifying _newpolygon: remove all points in removalpoints, add those in newCenters
     377  Polygon_t allnewpoints = _newpolygon;
     378  {
     379    _newpolygon.clear();
     380    std::sort(removalpoints.begin(), removalpoints.end());
     381    size_t i = 0;
     382    IndexArray_t::const_iterator removeiter = removalpoints.begin();
     383    for (Polygon_t::iterator iter = allnewpoints.begin();
     384        iter != allnewpoints.end(); ++iter, ++i) {
     385      if ((removeiter != removalpoints.end()) && (i == *removeiter)) {
     386        // don't add, go to next remove index
     387        ++removeiter;
     388      } else {
     389        // otherwise add points
     390        _newpolygon.push_back(*iter);
     391      }
     392    }
     393  }
     394  LOG(4, "DEBUG: The polygon with recentered points removed is " << _newpolygon);
     395
     396  // map IndexList to new shrinked _newpolygon
     397  typedef std::set<unsigned int> IndexSet_t;
     398  IndexSet_t SortedIndexList(IndexList.begin(), IndexList.end());
     399  IndexList.clear();
     400  {
     401    size_t offset = 0;
     402    IndexSet_t::const_iterator listiter = SortedIndexList.begin();
     403    IndexArray_t::const_iterator removeiter = removalpoints.begin();
     404    for (size_t i = 0; i < allnewpoints.size(); ++i) {
     405      if ((removeiter != removalpoints.end()) && (i == *removeiter)) {
     406        ++offset;
     407        ++removeiter;
     408      } else if ((listiter != SortedIndexList.end()) && (i == *listiter)) {
     409        IndexList.push_back(*listiter - offset);
     410        ++listiter;
     411      }
     412    }
     413  }
     414  LOG(4, "DEBUG: Our new bijective IndexList corrected for removed points reads as "
     415      << IndexList);
     416
     417  return IndexList;
    318418}
    319419
     
    492592SphericalPointDistribution::matchSphericalPointDistributions(
    493593    const SphericalPointDistribution::WeightedPolygon_t &_polygon,
    494     const SphericalPointDistribution::Polygon_t &_newpolygon
     594    SphericalPointDistribution::Polygon_t &_newpolygon
    495595    )
    496596{
Note: See TracChangeset for help on using the changeset viewer.