LCOV - code coverage report
Current view: top level - include/sigproc - fourierModes.hpp (source / functions) Coverage Total Hit
Test: mxlib Lines: 24.6 % 130 32
Test Date: 2026-08-30 22:23:37 Functions: 37.5 % 8 3

            Line data    Source code
       1              : /** \file fourierModes.hpp
       2              :  * \author Jared R. Males
       3              :  * \brief Functions for generating 2D Fourier modes
       4              :  * \ingroup signal_processing_files
       5              :  *
       6              :  */
       7              : 
       8              : //***********************************************************************//
       9              : // Copyright 2015, 2016, 2017 Jared R. Males (jaredmales@gmail.com)
      10              : //
      11              : // This file is part of mxlib.
      12              : //
      13              : // mxlib is free software: you can redistribute it and/or modify
      14              : // it under the terms of the GNU General Public License as published by
      15              : // the Free Software Foundation, either version 3 of the License, or
      16              : // (at your option) any later version.
      17              : //
      18              : // mxlib is distributed in the hope that it will be useful,
      19              : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      20              : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      21              : // GNU General Public License for more details.
      22              : //
      23              : // You should have received a copy of the GNU General Public License
      24              : // along with mxlib.  If not, see <http://www.gnu.org/licenses/>.
      25              : //***********************************************************************//
      26              : 
      27              : #ifndef fourierModes_hpp
      28              : #define fourierModes_hpp
      29              : 
      30              : #include <vector>
      31              : #include <algorithm>
      32              : 
      33              : #include "../mxlib.hpp"
      34              : 
      35              : #include "../math/constants.hpp"
      36              : #include "../math/geo.hpp"
      37              : 
      38              : namespace mx
      39              : {
      40              : 
      41              : namespace sigproc
      42              : {
      43              : 
      44              : /**
      45              :  * \ingroup fourier_basis
      46              :  *
      47              :  * \todo need to handle references and r-values so this works directly with Eigen arrays.
      48              :  *
      49              :  * @{
      50              :  */
      51              : 
      52              : /** \def MX_FOURIER_BASIC
      53              :  * \brief Signifies the basic sine/cosine Fourier basis.
      54              :  */
      55              : #define MX_FOURIER_BASIC 0
      56              : 
      57              : /** \def MX_FOURIER_MODIFIED
      58              :  * \brief Signifies the modified Fourier basis.
      59              :  */
      60              : #define MX_FOURIER_MODIFIED 1
      61              : 
      62              : /// Populate a single cosine mode
      63              : /** Makes a 2D image of the cosine mode:
      64              :     \f[
      65              :     M_c(\vec{q}) = \cos\left( 2\pi\frac{m}{D}u + 2\pi\frac{n}{D}v \right)
      66              :     \f]
      67              :   * where
      68              :     \f[
      69              :     \vec{q} = u \hat{u} + v \hat{v}
      70              :     \f]
      71              :   * and  \f$ D \f$ is taken to be the maximum of the number of columns and rows in the image.
      72              :   *
      73              :   * \retval 0 on success
      74              :   *
      75              :   * \tparam typeN is an Eigen-like reference type.
      76              :   */
      77              : template <class typeN>
      78              : int makeFourierModeC( typeN im,                 ///<  [out] is an Eigen-like image
      79              :                       typename typeN::Scalar m, ///<  [in] specifies the spatial frequency in the u direction
      80              :                       typename typeN::Scalar n  ///<  [in] n specifies the spatial frequency in the v direction
      81              : )
      82              : {
      83              :     typedef typename typeN::Scalar realT;
      84              : 
      85              :     int dim1 = im.cols();
      86              :     int dim2 = im.rows();
      87              : 
      88              :     realT uc, vc, u, v, D;
      89              : 
      90              :     uc = 0.5 * ( dim1 - 1.0 );
      91              :     vc = 0.5 * ( dim2 - 1.0 );
      92              : 
      93              :     D = std::max( dim1, dim2 );
      94              : 
      95              :     for( int i = 0; i < dim1; ++i )
      96              :     {
      97              :         u = i - uc;
      98              :         for( int j = 0; j < dim2; ++j )
      99              :         {
     100              :             v = j - vc;
     101              : 
     102              :             im( i, j ) = cos( math::two_pi<realT>() / D * ( m * u + n * v ) );
     103              :         }
     104              :     }
     105              : 
     106              :     return 0;
     107              : }
     108              : 
     109              : /// Populate a single sine mode
     110              : /** Makes a 2D image of the cosine mode:
     111              :     \f[
     112              :     M_s(\vec{q}) = \sin\left( 2\pi\frac{m}{D}u + 2\pi\frac{n}{D}v \right)
     113              :     \f]
     114              :   * where
     115              :     \f[
     116              :     \vec{q} = u \hat{u} + v \hat{v}
     117              :     \f]
     118              :   * and  \f$ D \f$ is taken to be the maximum of the number of columns and rows in the image.
     119              :   * \param [out] im is an Eigen-like image
     120              :   * \param [in] m specifies the spatial frequency in the u direction
     121              :   * \param [in] n specifies the spatial frequency in the v direction
     122              :   *
     123              :   * \retval 0 on success
     124              :   *
     125              :   * \tparam typeN is an Eigen-like reference type.
     126              :   */
     127              : template <class typeN>
     128              : int makeFourierModeS( typeN im, typename typeN::Scalar m, typename typeN::Scalar n )
     129              : {
     130              :     typedef typename typeN::Scalar realT;
     131              : 
     132              :     int dim1 = im.cols();
     133              :     int dim2 = im.rows();
     134              : 
     135              :     realT uc, vc, u, v, D;
     136              : 
     137              :     uc = 0.5 * ( dim1 - 1.0 );
     138              :     vc = 0.5 * ( dim2 - 1.0 );
     139              : 
     140              :     D = std::max( dim1, dim2 );
     141              : 
     142              :     for( int i = 0; i < dim1; ++i )
     143              :     {
     144              :         u = i - uc;
     145              :         for( int j = 0; j < dim2; ++j )
     146              :         {
     147              :             v = j - vc;
     148              : 
     149              :             im( i, j ) = sin( math::two_pi<realT>() / D * ( m * u + n * v ) );
     150              :         }
     151              :     }
     152              : 
     153              :     return 0;
     154              : }
     155              : 
     156              : /// Populate a single basic Fourier mode
     157              : /** Makes a 2D image of the basic sine or cosine mode.  Calls \ref makeFourierModeC and \ref makeFourierModeS.
     158              :  *
     159              :  * \param [out] im is an Eigen-like image
     160              :  * \param [in] m specifies the spatial frequency in the u direction
     161              :  * \param [in] n specifies the spatial frequency in the v direction
     162              :  * \param [in] p species sine (-1) or cosine (+1)
     163              :  *
     164              :  * \retval 0 on success
     165              :  *
     166              :  * \tparam typeN is an Eigen-like reference type.
     167              :  */
     168              : template <class typeN>
     169              : int makeFourierMode( typeN im, typename typeN::Scalar m, typename typeN::Scalar n, int p )
     170              : {
     171              :     if( p == -1 )
     172              :         return makeFourierModeS( im, m, n );
     173              : 
     174              :     if( p == 1 )
     175              :         return makeFourierModeC( im, m, n );
     176              : 
     177              :     internal::mxlib_error_report( error_t::invalidarg, "p must be +1 (cosine) or -1 (sine)." );
     178              : 
     179              :     return -1;
     180              : }
     181              : 
     182              : /// Populate a single modified Fourier mode
     183              : /** Makes a 2D image of the modified fourier mode:
     184              :     \f[
     185              :     M_p(\vec{q}) = \cos\left( 2\pi \frac{m}{D}u + 2\pi\frac{n}{D}v \right) + p  \sin\left( 2\pi\frac{m}{D}u +
     186              :   2\pi\frac{n}{D}v \right) \f]
     187              :   * where \f$ p = \pm 1 \f$, \f$ \vec{q} = u \hat{u} + v \hat{v} \f$,
     188              :   * and  \f$ D \f$ is taken to be the maximum of the number of columns in the image.
     189              :   *
     190              :   * \param [out] im is an Eigen-like image
     191              :   * \param [in] m specifies the spatial frequency in the u direction
     192              :   * \param [in] n specifies the spatial frequency in the v direction
     193              :   * \param [in] p is +/- 1 specifying which modified Fourier mode
     194              :   *
     195              :   * \retval 0 on success
     196              :   *
     197              :   * \tparam typeN is an Eigen-like reference type.
     198              :   */
     199              : template <class typeN>
     200              : int makeModifiedFourierMode(
     201              :     typeN im, typename typeN::Scalar m, typename typeN::Scalar n, int p, typename typeN::Scalar ang = 0 )
     202              : {
     203              :     typedef typename typeN::Scalar realT;
     204              : 
     205              :     if( p != 1 && p != -1 )
     206              :     {
     207              :         internal::mxlib_error_report( error_t::invalidarg, "p must be +1 or -1." );
     208              :         return -1;
     209              :     }
     210              : 
     211              :     int dim1 = im.cols();
     212              :     int dim2 = im.rows();
     213              : 
     214              :     realT xc, yc, x, y, arg, D;
     215              : 
     216              :     xc = 0.5 * ( dim1 - 1.0 );
     217              :     yc = 0.5 * ( dim2 - 1.0 );
     218              : 
     219              :     D = std::max( dim1, dim2 );
     220              : 
     221              :     realT c_ang, s_ang;
     222              :     if( ang != 0 )
     223              :     {
     224              :         c_ang = cos( math::dtor( ang ) );
     225              :         s_ang = sin( math::dtor( ang ) );
     226              :     }
     227              : 
     228              :     for( int i = 0; i < dim1; ++i )
     229              :     {
     230              : 
     231              :         for( int j = 0; j < dim2; ++j )
     232              :         {
     233              :             x = i - xc;
     234              :             y = j - yc;
     235              : 
     236              :             if( ang != 0 )
     237              :             {
     238              :                 realT x0 = x * c_ang - y * s_ang;
     239              :                 realT y0 = x * s_ang + y * c_ang;
     240              : 
     241              :                 x = x0;
     242              :                 y = y0;
     243              :             }
     244              : 
     245              :             arg = math::two_pi<realT>() / D * ( m * x + n * y );
     246              : 
     247              :             im( i, j ) = cos( arg ) + p * sin( arg );
     248              :         }
     249              :     }
     250              : 
     251              :     return 0;
     252              : }
     253              : 
     254              : /// Populate a single modified Fourier +1 mode
     255              : /** See \ref makeModifiedFourierMode.
     256              :  *
     257              :  * \param [out] im is an Eigen-like image
     258              :  * \param [in] m specifies the spatial frequency in the u direction
     259              :  * \param [in] n specifies the spatial frequency in the v direction
     260              :  *
     261              :  * \tparam typeN is an Eigen-like reference type.
     262              :  */
     263              : template <class typeN>
     264              : int makeModifiedFourierModeP( typeN im,
     265              :                               typename typeN::Scalar m,
     266              :                               typename typeN::Scalar n,
     267              :                               typename typeN::Scalar ang = 0 )
     268              : {
     269              :     return makeModifiedFourierMode( im, m, n, 1, ang );
     270              : }
     271              : 
     272              : /// Populate a single modified Fourier -1 mode
     273              : /** See \ref makeModifiedFourierMode.
     274              :  *
     275              :  * \param [out] im is an Eigen-like image
     276              :  * \param [in] m specifies the spatial frequency in the u direction
     277              :  * \param [in] n specifies the spatial frequency in the v direction
     278              :  *
     279              :  * \tparam typeN is an Eigen-like reference type.
     280              :  */
     281              : template <class typeN>
     282              : int makeModifiedFourierModeM( typeN im,
     283              :                               typename typeN::Scalar m,
     284              :                               typename typeN::Scalar n,
     285              :                               typename typeN::Scalar ang = 0 )
     286              : {
     287              :     return makeModifiedFourierMode( im, m, n, -1, ang );
     288              : }
     289              : 
     290              : /// Structure to contain the parameters of a Fourier mode.
     291              : struct fourierModeDef
     292              : {
     293              :     int m; ///< Spatial frequency m index
     294              :     int n; ///< Spatial frequency n index
     295              :     int p; ///< +/- 1 for modified Fourier modes, -1==>sine, +1==>cosine for basic Fourier modes.
     296              : 
     297              :     /// Constructor
     298           16 :     fourierModeDef()
     299           16 :     {
     300           16 :         m = 0;
     301           16 :         n = 0;
     302           16 :         p = 0;
     303           16 :     }
     304              : };
     305              : 
     306              : /// Sorting functor for modes according to the Poyner and Veran (2005) standard.
     307              : /** Follows the conventions of  Poyneer & Veran (2005) \cite poyneer_and_veran_2005
     308              :  *
     309              :  * \param[in] spf1 is an object of type \ref fourierModeDef to compare with spf2
     310              :  * \param[in] spf2 is an object of type \ref fourierModeDef to compare with spf1
     311              :  *
     312              :  * \returns the result of (spf1 < spf2) according to the above rules.
     313              :  */
     314            0 : bool comp_fourierModeDef_PandV( const fourierModeDef &spf1, const fourierModeDef &spf2 )
     315              : {
     316            0 :     double fr1 = spf1.m * spf1.m + spf1.n * spf1.n;
     317            0 :     double fr2 = spf2.m * spf2.m + spf2.n * spf2.n;
     318              : 
     319            0 :     if( fr1 == fr2 )
     320              :     {
     321            0 :         if( spf1.n == spf2.n )
     322              :         {
     323            0 :             if( spf1.m == spf2.m )
     324            0 :                 return ( spf1.p < spf2.p );
     325              :             else
     326            0 :                 return ( spf1.m < spf2.m );
     327              :         }
     328            0 :         return ( spf1.n < spf2.n );
     329              :     }
     330              : 
     331              :     // Otherwise sort by lowest absolute value
     332            0 :     return ( fr1 < fr2 );
     333              : }
     334              : 
     335              : /// Generate a Poyneer and Veran spatial frequency grid.
     336              : /** Follows the convention of Poyneer and Veran (2005) \cite poyneer_and_veran_2005
     337              :  * \todo use push_back instead of resize
     338              :  * \param spf
     339              :  * \param N is the linear number of degrees of freedom.
     340              :  */
     341            0 : int makeFourierModeFreqs_PandV( std::vector<fourierModeDef> &spf, int N )
     342              : {
     343            0 :     int Nmodes = N * N;
     344              : 
     345            0 :     spf.resize( Nmodes );
     346              : 
     347              :     int _k, _l;
     348            0 :     int modeCount = 0;
     349            0 :     for( int ll = 0; ll <= N; ++ll )
     350              :     {
     351            0 :         for( int l = ll, k = 0; l >= 0; --l, ++k )
     352              :         {
     353            0 :             if( modeCount >= Nmodes )
     354              :             {
     355            0 :                 internal::mxlib_error_report( error_t::sizeerr, "mode count exceeded expected number of modes" );
     356            0 :                 return -1;
     357              :             }
     358              : 
     359            0 :             if( k == 0 && l > .5 * N )
     360            0 :                 continue;
     361              : 
     362            0 :             if( k > .5 * N && ( l == 0 || l >= N - k ) )
     363            0 :                 continue;
     364              : 
     365            0 :             if( k > 0.5 * N )
     366            0 :                 _k = k - N;
     367              :             else
     368            0 :                 _k = k;
     369              : 
     370            0 :             if( l > 0.5 * N )
     371            0 :                 _l = l - N;
     372              :             else
     373            0 :                 _l = l;
     374              : 
     375              :             // There is always a cosine mode
     376            0 :             spf[modeCount].m = _k;
     377            0 :             spf[modeCount].n = _l;
     378            0 :             spf[modeCount].p = 1;
     379              : 
     380            0 :             ++modeCount;
     381              : 
     382              :             // Make sure it isn't one of the corners, then populate the sine mode
     383            0 :             if( !( ( k == 0 && l == 0 ) || ( k == 0.5 * N && l == 0 ) || ( k == 0 && l == 0.5 * N ) ||
     384            0 :                    ( k == 0.5 * N && l == 0.5 * N ) ) )
     385              :             {
     386            0 :                 spf[modeCount].m = _k;
     387            0 :                 spf[modeCount].n = _l;
     388            0 :                 spf[modeCount].p = -1;
     389            0 :                 ++modeCount;
     390              :             }
     391              :         }
     392              :     }
     393              : 
     394            0 :     std::sort( spf.begin(), spf.end(), comp_fourierModeDef_PandV );
     395              : 
     396            0 :     return 0;
     397              : }
     398              : 
     399              : /// Sorting functor for modes according to the mx::AO standard.
     400              : /** Given a spatial frequency vector \f$ \vec{k} = k_u \hat{u} + k_v \hat{v} \f$, sorts first by
     401              :  * \f$ | \vec{k} | \f$, then by the angle from the u axis.  Results in mode numbers increasing radially
     402              :  * and counter-clockwise from the \f$ u \f$ axis.
     403              :  *
     404              :  * \param[in] spf1 is an object of type \ref fourierModeDef to compare with spf2
     405              :  * \param[in] spf2 is an object of type \ref fourierModeDef to compare with spf1
     406              :  *
     407              :  * \returns the result of (spf1 < spf2) according to the above rules.
     408              :  */
     409            0 : bool comp_fourierModeDef( const fourierModeDef &spf1, const fourierModeDef &spf2 )
     410              : {
     411            0 :     double k1 = spf1.m * spf1.m + spf1.n * spf1.n;
     412            0 :     double k2 = spf2.m * spf2.m + spf2.n * spf2.n;
     413              : 
     414            0 :     if( k1 == k2 )
     415              :     {
     416              :         // Now compare by angle
     417            0 :         double a1 = atan2( spf1.n, spf1.m );
     418            0 :         if( a1 < 0 )
     419            0 :             a1 += math::two_pi<double>();
     420              : 
     421            0 :         double a2 = atan2( spf2.n, spf2.m );
     422            0 :         if( a2 < 0 )
     423            0 :             a2 += math::two_pi<double>();
     424              : 
     425            0 :         if( a1 == a2 )
     426            0 :             return ( spf1.p < spf2.p );
     427              : 
     428            0 :         return ( a1 < a2 );
     429              :     }
     430              : 
     431              :     // Otherwise sort by lowest absolute value
     432            0 :     return ( k1 < k2 );
     433              : }
     434              : 
     435              : /// Generate a circular spatial frequency grid.
     436              : /** \todo use push_back instead of resize
     437              :  *
     438              :  * \param spf
     439              :  * \param N is the linear number of degrees of freedom.  The number of modes is ((N+1)(N+1) - 1).
     440              :  */
     441            0 : int makeFourierModeFreqs_Circ( std::vector<fourierModeDef> &spf, int N )
     442              : {
     443              :     int krad;
     444              :     int Nmodes;
     445              : 
     446            0 :     krad = floor( 0.5 * N );
     447              : 
     448            0 :     Nmodes = 0.25 * math::pi<double>() * N * N * 1.1; // The 1.1 is a buffer
     449              : 
     450            0 :     spf.resize( Nmodes );
     451              : 
     452            0 :     int modeCount = 0;
     453              : 
     454            0 :     for( int m = -krad; m <= krad; ++m )
     455              :     {
     456            0 :         int nmax = sqrt( krad * krad - m * m );
     457              : 
     458            0 :         for( int n = 0; n <= nmax; ++n )
     459              :         {
     460            0 :             if( n == 0 && m <= 0 )
     461            0 :                 continue;
     462              : 
     463            0 :             for( int p = -1; p <= 1; p += 2 )
     464              :             {
     465            0 :                 if( modeCount >= Nmodes )
     466              :                 {
     467            0 :                     internal::mxlib_error_report( error_t::sizeerr, "mode count exceeded expected number of modes" );
     468            0 :                     return -1;
     469              :                 }
     470              : 
     471            0 :                 spf[modeCount].m = m;
     472            0 :                 spf[modeCount].n = n;
     473            0 :                 spf[modeCount].p = p;
     474            0 :                 ++modeCount;
     475              :             }
     476              :         }
     477              :     }
     478              : 
     479              :     // Erase any extra modes (there will bedue to the buffer).
     480            0 :     spf.erase( spf.begin() + modeCount, spf.end() );
     481              : 
     482              :     // And now sort it
     483            0 :     std::sort( spf.begin(), spf.end(), comp_fourierModeDef );
     484              : 
     485            0 :     return 0;
     486              : }
     487              : 
     488              : /// Calculate the index of a Fourier mode given its (m,n,p) coordinates.
     489              : /** The index increases counter-clockwise from the m axis in squares, with p==-1 being even and p==1 being odd.
     490              :  *
     491              :  * \param [in] m is the m spatial frequency coordinate
     492              :  * \param [in] n is the n spatial frequency coordinage
     493              :  * \param [in] p is the parity, +/-1, for sine or cosine or specifiying the modified Fourier mode.
     494              :  *
     495              :  * \returns the index of the Fourier mode on success
     496              :  * \returns -1 on an error.
     497              :  */
     498            0 : int fourierModeNumber( int m, int n, int p )
     499              : {
     500              : 
     501            0 :     if( p != -1 && p != 1 )
     502              :     {
     503            0 :         internal::mxlib_error_report( error_t::invalidarg, "p must +/-1" );
     504            0 :         return -1;
     505              :     }
     506              : 
     507            0 :     if( m == 0 && n == 0 )
     508              :     {
     509            0 :         internal::mxlib_error_report( error_t::invalidarg, "piston is ignored" );
     510            0 :         return -1;
     511              :     }
     512              : 
     513            0 :     int m0 = std::max( abs( m ), abs( n ) );
     514              : 
     515            0 :     int i0 = 2 * ( m0 * m0 - m0 );
     516              : 
     517              :     // int di0= 4*m0;
     518              : 
     519              :     int di;
     520              : 
     521            0 :     if( m == m0 )
     522              :     {
     523            0 :         di = n;
     524              :     }
     525            0 :     else if( m == -m0 )
     526              :     {
     527            0 :         di = 4 * m0 - n;
     528              :     }
     529              :     else
     530              :     {
     531            0 :         di = 2 * m0 - m;
     532              :     }
     533              : 
     534            0 :     return 2 * ( i0 + di ) + ( 1 + p ) / 2;
     535              : }
     536              : 
     537              : /// Calculate the (m,n,p) coordinates of a Fourier mode given its index.
     538              : /** The index increases counter-clockwise from the m axis in squares, with p==-1 being even and p==1 being odd.
     539              :  *
     540              :  * \returns 0 on success, a negative number otherwise
     541              :  */
     542           16 : int fourierModeCoordinates(
     543              :     int &m, ///< [out] is the m spatial frequency coordinate
     544              :     int &n, ///< [out] is the n spatial frequency coordinage
     545              :     int &p, ///< [out] is the parity, +/-1, for sine or cosine or specifiying the modified Fourier mode.
     546              :     int i ) ///< [in] is the mode index.
     547              : {
     548           16 :     if( i < 0 )
     549              :     {
     550            0 :         internal::mxlib_error_report( error_t::invalidarg, "i must be >= 0" );
     551            0 :         m = 0;
     552            0 :         n = 0;
     553            0 :         p = 0;
     554            0 :         return -1; /// \retval -1 if i < 0
     555              :     }
     556              : 
     557           16 :     int ii = ( i ) / 2;
     558              : 
     559           16 :     int m0 = 1;
     560              : 
     561           32 :     while( 2 * ( m0 * m0 - m0 ) <= ii )
     562           16 :         ++m0;
     563           16 :     --m0;
     564              : 
     565           16 :     int di = ii - 2 * ( m0 * m0 - m0 );
     566              : 
     567           16 :     if( di <= m0 )
     568              :     {
     569            8 :         m = m0;
     570            8 :         n = di;
     571              :     }
     572            8 :     else if( di <= 3 * m0 )
     573              :     {
     574            8 :         m = 2 * m0 - di;
     575            8 :         n = m0;
     576              :     }
     577              :     else
     578              :     {
     579            0 :         m = -m0;
     580            0 :         n = 4 * m0 - di;
     581              :     }
     582              : 
     583           16 :     p = -1 + 2 * ( i % 2 );
     584              : 
     585           16 :     return 0;
     586              : }
     587              : 
     588              : /// Generate a rectangular spatial frequency grid.
     589              : /**
     590              :  * \param spf is a vector of fourierModeDef structures, which will be resized and populated.
     591              :  * \param N is the linear number of degrees of freedom.  The number of modes is ((N+1)(N+1) - 1).
     592              :  */
     593            2 : int makeFourierModeFreqs_Rect( std::vector<fourierModeDef> &spf, int N )
     594              : {
     595            2 :     int Ndx = floor( 0.5 * ( N ) );
     596              : 
     597            2 :     int Nmodes = 2 * ( ( 2 * Ndx + 1 ) * ( Ndx + 1 ) - ( Ndx + 1 ) );
     598              : 
     599            2 :     spf.resize( Nmodes );
     600              : 
     601              :     int m, n, p;
     602              : 
     603           18 :     for( int i = 0; i < Nmodes; ++i )
     604              :     {
     605           16 :         fourierModeCoordinates( m, n, p, i );
     606              : 
     607           16 :         spf[i].m = m;
     608           16 :         spf[i].n = n;
     609           16 :         spf[i].p = p;
     610              :     }
     611              : 
     612            2 :     return 0;
     613              : }
     614              : 
     615              : /// Fill in a cube with a Fourier basis.
     616              : /** Fills the cube with either the basic or modified Fourier basis for the modes specified.
     617              :  *
     618              :  *
     619              :  * \tparam cubeT is an eigen-like cube, e.g. \ref mx::improc::eigenCube.
     620              :  */
     621              : template <typename cubeT>
     622              : int fillFourierBasis( cubeT &cube,                     /**< [out] will be allocated to hold and
     623              :                                                                   will be filled with the modes*/
     624              :                       int dim,                         /**< [in] is the linear size of the maps*/
     625              :                       std::vector<fourierModeDef> spf, /**< [in] is a vector of mode definitions
     626              :                                                                  to use for each mode*/
     627              :                       int basisType,                   /**< [in] is either MX_FOURIER_MODIFIED or MX_FOURIER_BASIC*/
     628              :                       typename cubeT::Scalar ang = 0   /**< [in] */
     629              : )
     630              : {
     631              :     int Nmodes = spf.size();
     632              : 
     633              :     cube.resize( dim, dim, Nmodes );
     634              : 
     635              :     for( int j = 0; j < Nmodes; ++j )
     636              :     {
     637              :         if( basisType == MX_FOURIER_MODIFIED )
     638              :         {
     639              :             if( makeModifiedFourierMode( cube.image( j ), spf[j].m, spf[j].n, spf[j].p, ang ) < 0 )
     640              :                 return -1;
     641              :         }
     642              :         else
     643              :         {
     644              :             if( makeFourierMode( cube.image( j ), spf[j].m, spf[j].n, spf[j].p ) < 0 )
     645              :                 return -1;
     646              :         }
     647              :     }
     648              : 
     649              :     return 0;
     650              : }
     651              : 
     652              : /// Generate a rectangular modified Fourier basis with the Poyneer and Veran ordering.
     653              : /** Fills the cube with modes generated by \ref makeFourierMode or \ref makeModifiedFourierMode using the mode grid
     654              :  * generated by \ref makeFourierModeFreqs_PandV. This follows the convention of Poyneer and Veran (2005)
     655              :  * \cite poyneer_and_veran_2005 for mode numbering.
     656              :  *
     657              :  * \param[out] cube will be allocated to hold and will be filled with the modes
     658              :  * \param[in] dim is the linear size of the maps, each is
     659              :  * \param[in] N is the linear number of degrees of freedom.  The number of modes is ((N+1)(N+1) - 1).
     660              :  * \param[in] basisType is either MX_FOURIER_MODIFIED or MX_FOURIER_BASIC
     661              :  *
     662              :  * \tparam cubeT is an eigen-like cube, e.g. \ref mx::improc::eigenCube.
     663              :  */
     664              : template <typename cubeT>
     665              : int makeFourierBasis_PandV( cubeT &cube, int dim, int N, int basisType )
     666              : {
     667              :     std::vector<fourierModeDef> spf;
     668              : 
     669              :     if( makeFourierModeFreqs_PandV( spf, N ) < 0 )
     670              :     {
     671              :         return -1;
     672              :     }
     673              : 
     674              :     return fillFourierBasis( cube, dim, spf, basisType );
     675              : }
     676              : 
     677              : /// Generate a circular Fourier basis.
     678              : /** Fills the cube with modes generated by \ref makeFourierMode or \ref makeModifiedFourierMode using the mode grid
     679              :  * generated by \ref makeFourierModeFreqs_Circ.
     680              :  *
     681              :  * \param[out] cube will be allocated to hold and will be filled with the modes
     682              :  * \param[in] dim is the linear size of the maps, each is
     683              :  * \param[in] N is the linear number of degrees of freedom.  The number of modes is ((N+1)(N+1) - 1).
     684              :  * \param[in] basisType is either MX_FOURIER_MODIFIED or MX_FOURIER_BASIC
     685              :  *
     686              :  * \tparam cubeT is an eigen-like cube, e.g. \ref mx::improc::eigenCube.
     687              :  */
     688              : template <typename cubeT>
     689              : int makeFourierBasis_Circ( cubeT &cube, int dim, int N, int basisType )
     690              : {
     691              :     std::vector<fourierModeDef> spf;
     692              : 
     693              :     if( makeFourierModeFreqs_Circ( spf, N ) < 0 )
     694              :     {
     695              :         return -1;
     696              :     }
     697              : 
     698              :     return fillFourierBasis( cube, dim, spf, basisType );
     699              : }
     700              : 
     701              : /// Generate a rectangular Fourier basis.
     702              : /** Fills the cube with modes generated by \ref makeFourierMode or \ref makeModifiedFourierMode using the mode grid
     703              :  * generated by \ref makeFourierModeFreqs_Rect.
     704              :  *
     705              :  * \param[out] cube will be allocated to hold and will be filled with the modes
     706              :  * \param[in] dim is the linear size of the maps, each is
     707              :  * \param[in] N is the linear number of degrees of freedom.  The number of modes is ((N+1)(N+1) - 1).
     708              :  * \param[in] basisType is either MX_FOURIER_MODIFIED or MX_FOURIER_BASIC
     709              :  *
     710              :  * \tparam cubeT is an eigen-like cube, e.g. \ref mx::improc::eigenCube.
     711              :  */
     712              : template <typename cubeT>
     713              : int makeFourierBasis_Rect( cubeT &cube, int dim, int N, int basisType, typename cubeT::Scalar ang = 0 )
     714              : {
     715              :     std::vector<fourierModeDef> spf;
     716              : 
     717              :     if( makeFourierModeFreqs_Rect( spf, N ) < 0 )
     718              :     {
     719              :         return -1;
     720              :     }
     721              : 
     722              :     return fillFourierBasis( cube, dim, spf, basisType, ang );
     723              : }
     724              : 
     725              : ///@}
     726              : 
     727              : } // namespace sigproc
     728              : } // namespace mx
     729              : 
     730              : #endif // fourierModes_hpp
        

Generated by: LCOV version 2.0-1