BbaDdo :: Bresenham 브레센함 알고리듬 : 원 그리기

 

 

비트맵 형식으로 원을 그리는 알고리듬, 중심점에서 실제의 반지름에 해당하는 지점에서 가장 가까운 픽셀을 찍는 방식이다. 제곱근이나 삼각함수 없이 정수 연산으로 빠르게 처리할 있다.

찾으려는 다음 픽셀은 예를 들어, 시계의 12 지점에서 오른쪽으로 1픽셀 이동 또는 오른쪽 1픽셀이동 아래로 1픽셀 이동한 점이 된다. 쉽게 생각하면, 시계 12 지점에서 시계방향으로 원을 그리는데 있어 연필의 진행방향이 오른쪽 또는 오른쪽 아래가 된다는 . 프로그램 코딩상에서 실제로 식에 의해 그리게 되면 중심각 45도가 되는 지점까지의 원호를 그리게 된다.

 

>>>사용되는 수식 정의<<<

 

방정식 :  x²+ y²- r²= 0 (중심점 x, y 반지름 r)

 

해당 픽셀 : Pk = (xk, yk)

오차     : Ek = xk2 + yk2 - r²

 

Pk 다음 진행 지점 픽셀 : x 1픽셀 더한 지점 : xk + 1, y 1픽셀 지점 yk - 1

P1 = (xk + 1 , yk)

P2 = (xk + 1 , yk - 1)

 

오차  :  E1 = (xk + 1)2 + yk2 - r²   

  E2 = (xk + 1)2 + (yk – 1)2 - r²  

 

(단 E1 > E2)

 

여기서 오차가 0 실제 중심점에서 반지름에 해당하는 정확한 지점이 되는데 오차가 양수 때는 반지름 보다 지점이 되고 음수일 때는 반대가 된다.  

 

개의 다음 진행 픽셀 중에 오차가 작은 픽셀을 선택한다. 하지만 오차의 값이 양수 음수 경우가 생기게 되는데 오차가 양수일 때는 항상E2 E1 보다 작으므로 P2 픽셀을 선택한다. 다시 말해 정확한 반지름 위치에 접근한 픽셀이다.

그리고 음수일 때는 P1 선택한다. 다시 말해 정확한 반지름 위치보다 안쪽으로 들어오게 되므로 음수의 절대치가 쪽을 선택한다.

그러나 E1 양수 E2 음수일 경우(오른쪽 다음 픽셀은 원의 바깥쪽 오른쪽 아래 픽셀은 원의 안쪽에 위치할 ) 에는 오차의 절대치 값이 작은 쪽을 선택하면 된다.

그리고 E1 음수 E2 양수일 수는 없다.

      

E1 > 0, E2  > 0 : P2 선택

E1 < 0, E2  < 0 : P1 선택

E1 > 0 , E2 < 0 : P1, P2 중에 절대치가 작은 쪽을 선택절대치가 같은 경우 어느 쪽을 선택해도 상관없다.

 

결론적으로 수식으로 정의 하면, 오차의 합이 음수일 음수일 경우에는 물론 P1 선택하게 되고 E1양수, E2음수 E2 절대치가 크다는 사실이 되므로 오차가 작은 P1 선택해야 된다.

또한 오차의 합이 양수일 P2 선택, E1양수, E2음수 E1 절대치가 크다는 사실이 되므로 오차가 작은 P2 선택해야 된다.

마지막으로 오차의 합이 0 때는 오차의 절대치가 같다는 경우이므로 어느 쪽을 선택해도 상관없다.  

 

E1 + E2 < 0 : P1 선택

E1 + E2 > 0 : P2 선택

E1 + E2 = 0 : 아무거나 선택(자바 코딩상에서는 P2 선택)

 

판별식 :

F(k) = E1 + E2

       = (xk + 1)2 + yk2 - r² + (xk + 1)2 + (yk – 1)2 - r²     

       = 2(xk2 + 2xk + 1) + yk2 + (yk2 - 2yk + 1) - 2r²

       = 2xk2 + 4xk + 2 + 2yk2 - 2yk + 1 - 2r²

       = 2xk2 + 2yk2 + 4xk - 2yk - 2r² + 3

       = 2(xk2 + yk2 - r²) + 4xk - 2yk + 3

       = 2Ek + 4xk - 2yk + 3

 

 

P 최초 시작점(초기화, 12) : xk = 0, yk = r, p = -2r + 3

F(0) = 2Ek + 4xk - 2yk + 3

       = -2yk + 3

       = -2r + 3

 

 

다음 진행 픽셀 수식:

 

P1 경우 : P1 = (Xk + 1, yk)

     F(k + 1) = 2E1 + 4(xk + 1) - 2yk + 3 

             = 2(xk2 + 2xk + 1 + yk2 - r²) + 4xk + 4 - 2yk + 3

             = 2xk2 + 2yk2 - 2r² + 2 + 4xk + 4xk + 4 - 2yk + 3

             = 2(xk2 + yk2 - r²) + 4xk - 2yk + 3 + 4xk + 6

= 2Ek + 4xk - 2yk + 3 + 4xk + 6

             = F(k) + 4xk + 6

 

P2 경우 : P2 = (Xk + 1, yk – 1)

F(k + 1) = 2E2 + 4(xk + 1) – 2(yk – 1) + 3 

             = 2(xk2 + 2xk + 1 + yk2 - 2yk + 1 - r²) + 4xk + 4 - 2yk + 2 + 3

             = 2xk2 + 2yk2 - 2r² + 4xk + 2 - 4yk + 2  + 4xk + 4 - 2yk + 2 + 3

             = 2(xk2 + yk2 - r²) + 4xk - 2yk + 3 + 4xk - 4yk + 10

= F(k) + 4xk - 4yk + 10

= F(k) + 4(xk - yk) + 10

 

 

 

 

자바 코드안드로이드 SurfaceHoler 사용해 그리는 메서드

* 주의점은 drawRect() 그릴 Y축의 개념은 흔히 쓰는 그래프상의 위치와     

  상반된다는 것. 

   *  8부분으로 나누어 서로 상반되게 x축과 y축을 지정해서 그리게 된다.

 *  기본적으로 x 값을 1 픽셀씩 증가시키면서  판별식을 이용해서 Y 값을     

감소시키는 때를 선택하는 알고리듬이 된다.

 

//Canvas.drawRect() 이용한 원주 그리기, Bresenham 알고리즘

private void circle(Canvas canvas, int x, int y, int radius){

if(radius <= 0) return; //반지름 0 이하일때 실행 안함

             

//값 초기화

     int xK = 0; //x축 해당값 초기화

     int yK = radius;//y축 해당값 반지름 값으로 초기화  

     int pK = 3 - (radius + radius); //3 - 2 * r, 픽셀 초기 시작지점

 

     do{

  //

          paint.setColor(Color.LTGRAY);

//동, 회색          

canvas.drawRect(x + xK, y - yK, x + xK + 4, y - yK + 4, paint);

          paint.setColor(Color.BLUE);

//, 청색

          canvas.drawRect(x - xK, y - yK, x - xK + 4, y - yK + 4, paint); 

                      

          //

          paint.setColor(Color.WHITE);

//, 흰색

          canvas.drawRect(x + xK, y + yK, x + xK + 4, y + yK + 4, paint);

          paint.setColor(Color.RED);

//, 적색

          canvas.drawRect(x - xK, y + yK, x - xK + 4, y + yK + 4, paint);

                      

          //

          paint.setColor(Color.CYAN);

//, 하늘색

          canvas.drawRect(x + yK, y - xK, x + yK + 4, y - xK + 4, paint);

          paint.setColor(Color.MAGENTA);

//, 분홍색

          canvas.drawRect(x + yK, y + xK, x + yK + 4, y + xK + 4, paint);

 

          //

          paint.setColor(Color.YELLOW);

//

          anvas.drawRect(x - yK, y - xK, x - yK + 4, y - xK + 4, paint);

          paint.setColor(Color.GREEN);

//

          canvas.drawRect(x - yK, y + xK, x - yK + 4, y + xK + 4, paint);

 

          xK++; // x 다음 픽셀 1 증가

                      

          //P1 선택 : pK + xK * 4 + 6 판별식

          if(pK < 0) pK += (xK << 2) + 6;  //판별할 pK 갱신

                    /*

                     * 쉬프트 연산자 << : xK << n --> xK * 2 n   

                     * >> : xK >> n --> xK / 2^n(승), 쉬프트연산자가 '*',     

* '/' 연산속도 보다 빠르다.

                     */

                      

          //P2선택 : pK + (xK - yK) * 4 + 10 판별식, yK 감소                 

            

          else {

          --yK; // 다음 픽셀 y 1 감소

               pK += ((xK - yK) << 2) + 10; //판별할 pK 갱신

     }

}while(xK <= yK); //x 증가치가 y 감소치의 합이 반지름과 같을때 까지, 45

}


카운터

Total : / Today : / Yesterday :
get rsstistory!