ConvexHull2D.cpp
Go to the documentation of this file.
00001 // ========================================================================================
00002 //  ApproxMVBB
00003 //  Copyright (C) 2014 by Gabriel Nützi <nuetzig (at) imes (d0t) mavt (d0t) ethz (døt) ch>
00004 //
00005 //  This Source Code Form is subject to the terms of the Mozilla Public
00006 //  License, v. 2.0. If a copy of the MPL was not distributed with this
00007 //  file, You can obtain one at http://mozilla.org/MPL/2.0/.
00008 // ========================================================================================
00009 //#include <iterator> // for ostream_iterator
00010 //#include "TestFunctions.hpp"
00011 
00012 
00013 #include "ApproxMVBB/ConvexHull2D.hpp"
00014 namespace ApproxMVBB{
00015 void ConvexHull2D::compute() {
00016     using namespace PointFunctions;
00017     using namespace ContainerFunctions;
00018 
00019     m_indicesCH.clear();
00020 
00021     // Need at least 1 point! m_p.col(0)
00022     if(m_p.cols()==0) {
00023         return;
00024     }
00025 
00026     // Compute min point p0
00027     unsigned int position = minPointYX(m_p);
00028     // std::cout << "min:" << position << std::endl;
00029     Vector2 base = m_p.col(position);
00030 
00031     // Indices into m_p
00032     // first = index into m_p, second =  delete flag!
00033     using PointData = std::pair<unsigned int, bool>;
00034     std::vector< PointData > indices; indices.reserve(m_p.cols());
00035 
00036     //Save p0 as first point in indices list (temporary)
00037     indices.emplace_back(position,false);
00038     //Add all indices of points not almostEqual to position
00039     for(unsigned int i = 0; i<m_p.cols(); ++i) {
00040         if( (i != position) && !almostEqualUlp(base,m_p.col(i))) {
00041             indices.emplace_back(i,false);
00042         }
00043     }
00044 
00045     // Convex hull consists of only 1 or 2 points!
00046     if(indices.size() <= 2  ) {
00047         for(auto & pa : indices){ m_indicesCH.emplace_back(pa.first);}  return;
00048     }
00049 
00050     // Sort by angle
00051     unsigned int deletedPoints = 0;
00052     CompareByAngle comp(m_p,base,position,deletedPoints);
00053     std::sort( indices.begin()+1, indices.end(), comp );
00054 
00055     std::vector<unsigned int> indicesT(indices.size()-deletedPoints);
00056     unsigned int k=0;
00057     for(auto & p: indices){ if(!p.second){indicesT[k++]=p.first;} }
00058 
00059     // Remove almost equal elements
00060     // move to front if not almost equal to first point
00061     // skip all deleted points
00062     auto ifFunc =  [&](const unsigned int & p1, const unsigned int & p2){
00063                         return !almostEqualUlp(this->m_p.col(p1),this->m_p.col(p2));
00064                       };
00065 //    auto skipFunc = [](const unsigned int & p1){ return false; };
00066     auto d2 = ContainerFunctions::moveConsecutiveToFrontIf(indicesT.begin(),indicesT.end(), ifFunc);
00067     indicesT.resize( std::distance(indicesT.begin(),d2) );
00068 
00069     // Convex hull consists of only 1 or 2 points!
00070     if(indicesT.size() <= 2  ) {
00071         for(auto & pa : indicesT){ m_indicesCH.emplace_back(pa);}  return;
00072     }
00073 
00074     //for(auto  a: indicesT){
00075     //    std::cout << a.first<<",";
00076     //}
00077     //std::cout << "Graham Scan points: " << indicesT.size() << std::endl;
00078         unsigned int nPoints  = indicesT.size();
00079         m_indicesCH.reserve(nPoints);
00080         unsigned int lastIdx  = indicesT[0];
00081         unsigned int firstIdx = indicesT[1];
00082         m_indicesCH.push_back( lastIdx  );
00083         m_indicesCH.push_back( firstIdx );
00084 
00085         unsigned int lPtIdx  = lastIdx;
00086         unsigned int mPtIdx  = firstIdx;
00087         unsigned int currIdx ;
00088         unsigned int i = 2; // current point;
00089 
00090     // skip the first non left turns in the sequence!
00091     //    std::cout << "lastIdx point: " <<lastIdx << ","<< m_p.col(lastIdx).transpose() << std::endl;
00092     //    std::cout << "firstIdx point: " <<firstIdx << ","<< m_p.col(firstIdx).transpose() << std::endl;
00093 
00094     while( i<nPoints){
00095             currIdx = indicesT[i];
00096             if(leftTurn(m_p.col(lastIdx), m_p.col(firstIdx), m_p.col(currIdx))){
00097                 break;
00098             }
00099             ++i;
00100     };
00101 
00102 
00103     //    std::cout << "i:"<< i << std::endl;
00104     //    std::cout << "currIdx point: " <<currIdx << std::endl;
00105     //    std::cout << ","<< m_p.col(currIdx).transpose() << std::endl << "===="<<std::endl;
00106     //    std::cout << "0,5,8: :" << orient2d(m_p.col(0), m_p.col(5), m_p.col(8)) << std::endl;
00107     //    std::cout << "1,5,8: :" << orient2d(m_p.col(1), m_p.col(5), m_p.col(8)) << std::endl;
00108     //    std::cout << "5,8,0: :" << orient2d(m_p.col(5), m_p.col(8), m_p.col(0)) << std::endl;
00109 
00110     if ( i < nPoints )
00111     {
00112       m_indicesCH.push_back( currIdx );
00113       decltype(m_indicesCH.rbegin()) revIter;
00114       lPtIdx  = mPtIdx;
00115       mPtIdx  = currIdx;
00116 
00117       for (++i ; i < nPoints; ++i )
00118       {
00119           currIdx = indicesT[i];
00120 
00121           if ( leftTurn(m_p.col(mPtIdx), m_p.col(currIdx), m_p.col(lastIdx)) )
00122           {
00123               while ( !leftTurn(m_p.col(lPtIdx), m_p.col(mPtIdx), m_p.col(currIdx))   )
00124               {
00125                   //std::cout << "right turn: " <<lPtIdx << ","<< mPtIdx << "," << currIdx << std::endl;
00126                   ApproxMVBB_ASSERTMSG(m_indicesCH.size()>2,"");
00127                   m_indicesCH.pop_back();
00128 
00129                   if( m_indicesCH.size() <= 1) { // Degenerate Case if we come back to the beginning
00130                     mPtIdx  = lPtIdx; // such that lPtIdx stays the same , mPtIdx becomes currIdx and we go to next point!
00131                     break;
00132                   }else{
00133                       mPtIdx = lPtIdx;                      // middle point becomes last
00134                       revIter = m_indicesCH.rbegin();
00135                       lPtIdx = *(++revIter);                // previous of .back();
00136                   }
00137               }
00138               //std::cout << "left turn: " <<lPtIdx << ","<< mPtIdx << "," << currIdx << std::endl;
00139               m_indicesCH.push_back( currIdx );
00140               lPtIdx  = mPtIdx;          // last becomes middle
00141               mPtIdx  = currIdx;         // middle becomes currIdx
00142           }/*else{
00143               std::cout << "skip point: " << currIdx << std::endl;
00144           }*/
00145       }
00146 
00147     }
00148 
00149 }
00150 
00151 
00152 bool ConvexHull2D::verifyHull() {
00153     using namespace PointFunctions;
00154     if(m_indicesCH.size()>2) {
00155         unsigned int i = 2;
00156         while( i<m_indicesCH.size()) {
00157             if( ! (orient2d( m_p.col(m_indicesCH[i-2]), m_p.col(m_indicesCH[i-1]), m_p.col(m_indicesCH[i])) >= 0) ) { // if this is not a left turn
00158                 return false;
00159             }
00160             ++i;
00161         }
00162     }
00163     return true;
00164 }
00165 
00166 }


asr_approx_mvbb
Author(s): Gassner Nikolai
autogenerated on Sat Jun 8 2019 20:21:49