サイトマップ
お知らせ、メモ
案内板
うちのヘッドライン
 




トップ  >  プログラム豆知識  >  アルゴリズム豆知識  >  多角形で選択されたピクセルを取得する

多角形で選択されたピクセルを取得する

多角形で選択されたピクセルを取得する方法はイロイロあるかと思いますが、 ポリゴンのラスタライズの要領で多角形をピクセルに変換し、 塗りつぶされたピクセルを取得するというのがとりあえず思いつきます。

ポリゴンのラスタライズはCG描画の基礎なので、 高速処理のための工夫がイロイロあるそうですが、 この用途ならばそんなに高速でなくてもいいので、とりあえず版です。

以下のコードはとりあえずベタな方法でラスタライズするサンプルです(C++/CLI使用)。 イロイロとおかしなところはあるかと思いますが、とりあえずこれでもラスタライズは出来ます。 ビットマップクラスにDarkBlueで塗りつぶしています。


// 線分クラス

// Line.h

using namespace System::Drawing;

ref class CLine
{
public:
  CLine( Point^ p1, Point^ p2 );
  double GetX( int x );

  double m_dDX;
  double m_dDY;

  Point^ m_pU;
  Point^ m_pL;
}

// Line.cpp

#include "Line.h"
#include <math.h>

CLine::CLine( Point^ p1, Point^ p2 )
{
  if ( p1->Y > p2->Y )
  {
    m_pU = p1;
    m_pL = p2;
  }
  else
  {
    m_pU = p2;
    m_pL = p1;
  }

  m_dDX = m_pU->X - m_pL->X;
  m_dDY = m_pU->Y - m_pL->Y;
}

double CLine::GetX( int y )
{
  if ( y < m_pL->Y || y >= m_pU->Y ) return -1.0;

  return m_pL->X + (y - m_pL->Y) * m_dDX/m_dDY;
}

//////////////////////////////////////////////////////////////////////

// ラスタライズ実行クラス

// CRasterize.h

#include "Line.h"
#include <cliext/vector>

using namespace System::Drawing;

ref class CRasterize
{
public:
  CRasterize( cliext::vector<Point> vPnt );
  System::Void Rasterize( Bitmap^ bmp, double dReso );

private:
  cliext::vector<CLine^> m_vLine;

  int m_nXMin, m_nXMax, m_nYMin, m_nYMax;
}

// CRasterize.cpp

#include "CRasterize.h"
#include <cliext/algorithm>
#include <math.h>


// コンストラクタ
// クリックされた点列を線分クラスに登録する
CRasterize::CRasterize( cliext::vector<Point> vPnt )
{
  int i;
  m_nXMin = m_nYMin = INT_MAX;
  m_nXMax = m_nYMax = INT_MIN;

  for ( i = 0; i < vPnt.size()-1; i++ )
  {
    CLine^ line = gcnew CLine( vPnt[i], vPnt[i+1] );
    m_vLine.push_back( line );
    if ( vPnt[i].X < m_nXMin ) m_nXMin = vPnt[i].X;
    if ( vPnt[i].X > m_nXMax ) m_nXMax = vPnt[i].X;
    if ( vPnt[i].Y < m_nYMin ) m_nYMin = vPnt[i].Y;
    if ( vPnt[i].Y > m_nYMax ) m_nYMax = vPnt[i].Y;
  }
  CLine^ line = gcnew CLine( vPnt[i], vPnt[0] );
  m_vLine.push_back( line );
  if ( vPnt[i].X < m_nXMin ) m_nXMin = vPnt[i].X;
  if ( vPnt[i].X > m_nXMax ) m_nXMax = vPnt[i].X;
  if ( vPnt[i].Y < m_nYMin ) m_nYMin = vPnt[i].Y;
  if ( vPnt[i].Y > m_nYMax ) m_nYMax = vPnt[i].Y;
}

// ラスタライズを実行
// 引数のdResoは画面解像度との比
// 引数bmpは画面解像度*dReso(1以下)のサイズのビットマップクラス
System::Void CRasterize::Rasterize( Bitmap^ bmp, double dReso )
{
  int i, j, k;
  double dEdge;
  cliext::vector<double> vdEdge;

  for ( i = (int)(m_nYMin*dReso); i <= (int)(m_nYMax*dReso); i++ )
  {
    for ( k = 0; k < m_vLine.size(); k++ )
    {
      if ( (dEdge = m_vLine[k]->GetX( i/dReso+1 )) > 0 )
      {
        vdEdge.push_back( dEdge );
      }
    }
    cliext::sort( vdEdge.begin(), vdEdge.end() );

    for ( k = 0; k < vdEdge.size()-1; k += 2 )
    {
      for ( j = (int)floor( vdEdge[k]*dReso ); j < (int)ceil( vdEdge[k+1]*dReso ); j++ )
      {
        bmp->SetPixel( j, i, Color::DarkBlue );
      }
    }

    vdEdge.clear();
  }
}

本当はもっと高速にする方法がいろいろとあるそうです。 詳しくは参考文献で。

参考文献


クリエイティブ・コモンズ・ライセンス
This documents by Yamate,N is licensed under a Creative Commons 表示 - 継承 3.0 非移植 License.
login