2017-02-19 9 views
1

円の中心からピクセルごとに(時計回りに)1行ずつ円を描きたい。しかし、ピクセルを再描画するのは避けてください(これは遅いです)。C++の中心からピクセルを塗りつぶして描画しますか?

これは、各ターンに1回だけ更新される「レーダー」のようなものだと想像してください。

すべての塗りつぶしピクセル(前の最大ラインポイント)とGPUまたはハイレベルライブラリ(DrawPoint(x、y)関数による描画)の配列を保持するRAMはありません。

私はラインとポイント描画する機能を持っている:

void DrawLineFromCenterXYToAngle(int centerX, int centerY, float angle) 
{ 
.... instead of angle it is possible to find points of the circle and iterate it 
.... find line points by Bresenham's line algorithm 
{ 
    DrawPoint(int x, int y); 
} 
} 

void DrawPoint(int x, int y) 
{ 
    PixelDraw_Slow(x,y)=GetColor_VerySlow(x,y); 
} 

は今、私は角度を反復処理し、非常にゆっくりので何回も再描画中央のピクセルの円を得ました。そして、最適化が必要です。

これは速くなると形状が真円にならない場合があります。

+0

標準の 'C++ 'にはGUIの概念がないので、いくつかのライブラリを使用しなければなりません。どのライブラリを使用しているのかわからないので、私たちが手助けするのは難しいでしょう。 – drescherjm

+1

私たちがあなたの実装を手助けできるように、どのように反復しているかを示すべきでしょう。 – drescherjm

+0

これは役に立たないマイクロコントローラのルーティンです。例えばボイドAdafruit_GFX_AS :: drawLine(X0 int16_t、int16_tのY0、 \t \t \t int16_tのX1、int16_tのY1、 \t \t \t uint16_t色){ 急= ABS(Y1 - Y0)int16_t> ABS(X1 - X0)。 if(steep){ swap(x0、y0); swap(x1、y1); } if(x0> x1){ swap(x0、x1); スワップ(y0、y1); } int16_t dx、dy;dx = x1-x0; dy = abs(y1-y0); int16_t err = dx/2; int16_t ystep; if(y0 user1329019

答えて

0

円にはBresenham描画アルゴリズムがあります。

Example with code

int r = 200, ymax, x, y, yp, xp, d; 
ymax = r/sqrt(2); 
x = r; /* start at the bottom of the first octant */ 
/* d measures whether the midpoint of two pixel locations 
is inside or outside the ideal circle. positive means outside */ 
d = -1*r; /* to be precise, this should be r^2 - (r - 0.5)^2 */ 
xp = r; yp = -1; /* these hold the old values across iterations */ 
for(y=0; y<=ymax; y++) { 
    plot_8_ways(x,y); 
    if (d > 0) { /* midpoint is outside circle, go NW */ 
    x--; 
    d += (2*yp - 2*xp + 3); 
    } 
    else { /* midpoint is inside circle, go N */ 
    d += (2*yp + 1); 
    } 
    yp = y; 
    xp = x; 
} 
0

が全て満たされた画素(最大前ライン・ポイント)と無GPUまたはHiレベルライブラリのアレイを保持するために何のRAMがありません(関数DrawPoint(X、Y)によって描画) 。

ポイントを1行保存できる場合、効率的に表現すると、すべての塗りつぶしピクセルを追跡するのに十分なメモリがあります。

レーダースイープが12時または6時の位置から始まると仮定すると(時計回りまたは反時計回りにスイープするかどうかは関係ありません)、円の描画中はいつでも、垂直行は塗りつぶされたピクセルのブロックと一度だけ交差します(つまり、一度入力して一度終了します)。したがって、ピクセルの各列に対して垂直方向の最小および最大のピクセルのy座標を格納するだけで、それらを追跡することができます。 3時または9時の位置から開始する場合は、各行の最小値と最大値xを保存できます。

あなただけの配列のカップルでそれを行うことができます。

int minY[X_RANGE]; 
int maxY[X_RANGE]; 

X_RANGEは、画素の列数の最大値です。これは、円の境界ボックスの左のXに基づいてオフセットすることができるため、画面全体ではなく、サークルと同じ大きさでなければなりません。同様に、Y_RANGEは最大行数です。

あなたがレンダリングを開始すると、空の列を表すために配列を初期化:

void InitColumnArrays() 
{ 
    for(int x = 0; x < X_RANGE; x++) 
    { 
     minY[x] = Y_RANGE - 1; 
     maxY[x] = 0; 
    } 
} 

その後、あなたはピクセルをレンダリングするとき、それはすでに配列をチェックすることにより、レンダリングされた場合だけチェック:

void DrawPointCheckingRanges(int x, int y) 
{ 
    // TODO: range check values 

    // check if point has already been drawn and draw it and extend ranges if not: 
    if((y < minY[x]) || (y > maxY[x])) 
    { 
     DrawPoint(x + offsetX, y + offsetX); 
     if(y < minY[x]) 
      minY[x] = y; 
     if(y > maxY[x]) 
      maxY[x] = y; 
    } 
} 

offsetXとoffsetYは、前述のオプションのオフセットです。

これを他の回答からBresenhamサークル描画アルゴリズムと組み合わせて使用​​すると、効率的にラインの終点を与えることができます。

上記のコードでは、これらの境界チェックや配列の読み込みと書き込みに比べてDrawPointが遅いことを前提としています。

関連する問題