2015-01-03 3 views
3

현재 Bresenham의 원 그리기 알고리즘을 사용하고 있습니다. 원을 그리는 알고리즘을 사용하고 있지만 Bresenham의 방법은 단일 픽셀 두께 만 그리기 때문에 상대적으로 빠르고 효율적인 방법으로 특정 두께의 원을 그리기를 원합니다.). 다른 반지름으로 여러 원을 그릴 수 있다는 것을 알았지 만 매우 비효율적이라고 생각합니다. 효율성이 중요합니다. 왜냐하면 이것이 모든 마이크로 초가 소중한 Arduino에서 실행되기 때문입니다. 나는 현재 다음 코드를 사용하고 있습니다 :두께 그리기 원이있는 원

void circle(byte xc, byte yc, int radius, Colour colour) { 
    int x = -radius, y = 0, err = 2 - 2 * radius; 
    while(x < 0) { 
    setPixel(xc - x, yc + y, colour); 
    setPixel(xc - y, yc - x, colour); 
    setPixel(xc + x, yc - y, colour); 
    setPixel(xc + y, yc + x, colour); 
    radius = err; 
    if(radius <= y) { 
     err += ++y * 2 + 1; 
    } 
    if(radius > x || err > y) { 
     err += ++x * 2 + 1; 
    } 
    } 
} 

어떻게이 원의 두께를 지정할 수 있습니다 수정할 수 있을까? PS 외부 라이브러리를 사용하고 싶지 않습니다. 제발!

+1

일반적인 방법은 2 개의 원 (내부와 외부)을 그리고 적절한 채우기 규칙 (예 : http://en.wikipedia.org/wiki/Even%E2%80%93odd_rule)을 사용하여 간격을 채우는 것입니다. – oakad

+0

예,하지만 그렇게 느리지 않습니까? –

+3

"압축 된"중개자를 사용할 수 있습니다 : 연결 대상 목록을 나타내는 링크 목록을 만들어 각 연결된 목록이 스캔 라인을 나타냅니다. Bresenham의 알고리즘을 사용하여 각 "검은 색"픽셀에 대한 노드를 각 관련 스캔 라인 목록에 넣습니다. 채우기 규칙을 염두에 둔 결과 구조를 탐색하여 대상 표면을 그립니다 (각 목록에 2 ~ 4 개의 노드 만 있음). – oakad

답변

2

Midpoint circle algorithm에 설명 된 것처럼 8 진수를 따라 스캔하면 주요 좌표 y은 항상 1 씩 증가합니다. 주요 좌표가 일치하기 때문에 한 번에 두 개의 원을 그릴 수 있습니다.

픽셀을 배치하는 대신 내부 및 외부 원의 점 사이에 수평선 (그리고 수직선)을 그려야합니다.이 선은 같은 y (또는 x) 좌표를 갖습니다. 바깥 쪽 원이 대각선에 도달 할 때까지 그렇게합니다.

당신은 두 개의 원, 내부 원 i와 외부 원 o에 대한 xerr와 상태를 유지한다. 내부 원이 대각선에 도달하면 내부 점이 대각선에 놓입니다. 즉, 8 개의 인접한 8 개 섹터를 그립니다.

이 아이디어는 의견에서 @oakad가 제안한 것과 매우 유사하지만 목록을 유지할 필요가 없습니다. Midpoint circle 알고리즘은 Bresenham 알고리즘보다 속도가 느릴 수 있으므로 개선의 여지가 있지만 메모리 사용 공간이 적다는 장점이 있습니다.

아래 코드는 지정된 내부 및 외부 반경을 가진 빈 원을 그립니다. 선폭은 ro - ri + 1이므로 동일한 반지름으로도 1 픽셀의 원이 인쇄됩니다. 내부 반경이 외부 반경보다 작 으면 아무 것도 인쇄하지 않습니다.

void xLine(int x1, int x2, int y, int colour) 
{ 
    while (x1 <= x2) setPixel(x1++, y, colour); 
} 

void yLine(int x, int y1, int y2, int colour) 
{ 
    while (y1 <= y2) setPixel(x, y1++, colour); 
} 

void circle2(int xc, int yc, int inner, int outer, int colour) 
{ 
    int xo = outer; 
    int xi = inner; 
    int y = 0; 
    int erro = 1 - xo; 
    int erri = 1 - xi; 

    while(xo >= y) { 
     xLine(xc + xi, xc + xo, yc + y, colour); 
     yLine(xc + y, yc + xi, yc + xo, colour); 
     xLine(xc - xo, xc - xi, yc + y, colour); 
     yLine(xc - y, yc + xi, yc + xo, colour); 
     xLine(xc - xo, xc - xi, yc - y, colour); 
     yLine(xc - y, yc - xo, yc - xi, colour); 
     xLine(xc + xi, xc + xo, yc - y, colour); 
     yLine(xc + y, yc - xo, yc - xi, colour); 

     y++; 

     if (erro < 0) { 
      erro += 2 * y + 1; 
     } else { 
      xo--; 
      erro += 2 * (y - xo + 1); 
     } 

     if (y > inner) { 
      xi = y; 
     } else { 
      if (erri < 0) { 
       erri += 2 * y + 1; 
      } else { 
       xi--; 
       erri += 2 * (y - xi + 1); 
      } 
     } 
    } 
} 
+0

그래서 원의 두께를 지정할 수 있도록 수정 한 다음 그 안쪽과 바깥 쪽 반지름을 파생시킬 수 있습니까? 따라서 "int inner, int outer"를 "int radius, int thickness"로 바꾸고 inner = radius-thickness를 수행합니까? –

+0

@indeed : 물론 가능합니다.이 함수에 프론트 엔드를 작성할 수도 있고 함수 서명을 사용하여 inner를 계산할 수도 있습니다. 이 코드는 동일한 안쪽과 바깥 쪽을 두께가 1 인 것으로 간주하므로 아마도 'inner = outer - thickness + 1'을 원할 것입니다. –

+0

확인. 도움을 주셔서 감사합니다 –

-1

아래의 해결책은 느릴 수 있지만 매우 간단합니다.

먼저 Bresenham의 알고리즘을 사용하여 내부 및 외부 원을 그립니다. 그런 다음 검사 조건 :

if (pow(i - centre, 2) + pow(j - centre, 2) <= pow(outern_radius,2) && 
      pow(i - centre, 2) + pow(j - centre, 2) >= pow(inner_radius,2)) 

만족하면 setPixel (i, j).

+0

내 솔루션에 문제가 있으면 투표하기 전에 먼저 의견을 말하십시오. –