動径ループを手軽に実装できる便利ホストテンプレート

プログラムで円や球を作る場合の、動径ループを書くのは面倒だ。記述すべき内容が陳腐でわかりきっている割には、M_PIの有無で悩んだり、ラジアンに直したり、分割角度を一次変数に用意したりなどうんざりだ。
そこで動径ループをやってくれるための便利テンプレートを作成したよ。

これは開始、終了、ステップ角度と、動径ループ内部の処理ファンクタさえ指定してやれば、適切に角度を更新してそのつど指定ファンクタを呼び出すようなループが回ってくれるというスグレモノだ。コードは以下のようになったよ。VS2008SP1でのみ動作確認済みだよ。

#define _USE_MATH_DEFINES // ←M_PIのため
#include <cmath> // ←M_PIのため

template < class Fnc >
class  RadialLoopHost_t
{
public:
  // concept void Fnc::operator()( const double& irad )
  RadialLoopHost_t( 
    const double start, 
    const double end,  
    const double step,
    Fnc fnc )
  : _start( start ), _end( end ), _step( step ), _fnc( fnc )
  {
    for( double irad=_start; irad<_end; irad+=_step ){
      _fnc( irad*M_PI/180.0 );
    }// irad
  }
  double _start;
  double _end;
  double _step;
  Fnc _fnc;
};
template< class Fnc > 
RadialLoopHost_t< Fnc > RadialLoopHost( 
                                       const double start, 
                                       const double end,  
                                       const double step,
                                       Fnc fnc ){
  return RadialLoopHost_t< Fnc >( start, end, step, fnc ); 
}

これを使って、例えば半径5の円の輪郭をプロットするコードは以下のように書けるよ。

  struct RadialLoopCircle{
    RadialLoopCircle( const double radi ):_radi(radi){}
    void operator()( const double irad ){
      PLOT( _radi*cos( irad ), _radi*sin( irad ) ); 
      // あるいはglVertex2fとかをここで呼ぶ
    }
    double _radi;
  };
  //★↓本ホストテンプレート呼び出し
  RadialLoopHost( 0, 361, 45, RadialLoopCircle( 5.0 ) );

さらに単位球の座標プロットはRadialLoopHostをネスト利用して、以下のように書ける。

  struct RadialLoopSphere{
    struct RadialLoopBelt{
      RadialLoopBelt( const double tht ):_tht(tht){};
      void operator()( const double phi ){
        cout.precision(2);
        cout 
          << sin( _tht)*cos(phi )<< ","
          << sin( _tht)*sin(phi )<< ","
          << cos( _tht )<<endl;
        // あるいはglVertex3fとかをここで呼という使い方も
      }
      double _tht;
    };
    void operator()( const double tht ){
      RadialLoopHost( 0, 361, 45, RadialLoopBelt( tht ) );
    }
  };
  //★↓本ホストテンプレート呼び出し
  RadialLoopHost( 1, 180, 45, RadialLoopSphere() );