Circle Drawing
From KBase
Contents |
[edit] Introduction
Azydream 님께서 http://azydream.tistory.com/51 에 PA_Lib 에 있는 원 그리기 함수를 소개해 주셨다. 처음에 이 함수를 보았을 때는 저걸로 어떻게 원을 그리지? 하는 생각이 문득 들었다. 그래서 과연 원을 그려줄 것인지 보려고 간단한 프로그램을 만들어 보았다.
[edit] Writing Test Application
원 소스에 있는 PA_DrawCircle() 은 고치지 않은 채로 결과를 Terminal 에서 확인할 수 있도록 했다.
[edit] Source Code
#include <stdio.h>
#include <stdlib.h>
#define CX_CANVAS 60
#define CY_CANVAS 60
#define DEFAULT_X 30
#define DEFAULT_Y 30
#define DEFAULT_R 10
static int count = 0;
static int occurrences[CY_CANVAS][CY_CANVAS];
void PA_DrawPixel(int x, int y, int color)
{
printf("(%2d,%2d) ", x, y);
if ((++count % 8) == 0) {
printf("\n");
}
if (x >= 0 && x < CX_CANVAS &&
y >= 0 && y < CY_CANVAS)
{
occurrences[y][x]++;
}
}
void PA_DrawCircle(int xCenter, int yCenter, int radius, int color)
{
int x = 0;
int y = radius;
int p = 3 - 2 * radius;
while (x <= y){
PA_DrawPixel(xCenter + x, yCenter + y, color);
PA_DrawPixel(xCenter - x, yCenter + y, color);
PA_DrawPixel(xCenter + x, yCenter - y, color);
PA_DrawPixel(xCenter - x, yCenter - y, color);
PA_DrawPixel(xCenter + y, yCenter + x, color);
PA_DrawPixel(xCenter - y, yCenter + x, color);
PA_DrawPixel(xCenter + y, yCenter - x, color);
PA_DrawPixel(xCenter - y, yCenter - x, color);
if (p < 0) p += 4 * x++ + 6;
else p += 4 * (x++ - y--) + 10;
}
}
void printOccurrences(int w, int h)
{
for (int y = 0; y < w; y++) {
for (int x = 0; x < h; x++) {
if (occurrences[y][x]) {
putchar('0' + occurrences[y][x]);
} else {
putchar(' ');
}
}
printf("\n");
}
}
int main(int argc, char *argv[])
{
int r = DEFAULT_R;
if (argc > 1) {
r = atoi(argv[1]);
}
if (r <= 0 || (r >= CX_CANVAS / 2) || (r >= CY_CANVAS / 2)) {
return 1;
}
PA_DrawCircle(r, r, r, 0);
int maxx = 2 * r + 1;
int maxy = 2 * r + 1;
printOccurrences(maxx, maxy);
return 0;
}
[edit] Explanation
- main()
- 반지름을 인자로 받아 원을 그린 뒤 출력한다
- PA_DrawPixel()
- PA_DrawCircle() 이 이 함수를 이용하므로, 가상으로 만들어 준다. 점을 찍는 위치를 순서대로 표시해 주고, 해당 첨이 몇 번 출력되는지 확인하기 위해 occurrence 라는 이름의 이차원 배열을 사용한다
- printOccurrences()
- 저장해 둔 occurrence 를 출력한다.
[edit] Output
/cygdrive/c/Temp $ ./a.exe
(10,20) (10,20) (10, 0) (10, 0) (20,10) ( 0,10) (20,10) ( 0,10)
(11,20) ( 9,20) (11, 0) ( 9, 0) (20,11) ( 0,11) (20, 9) ( 0, 9)
(12,20) ( 8,20) (12, 0) ( 8, 0) (20,12) ( 0,12) (20, 8) ( 0, 8)
(13,20) ( 7,20) (13, 0) ( 7, 0) (20,13) ( 0,13) (20, 7) ( 0, 7)
(14,19) ( 6,19) (14, 1) ( 6, 1) (19,14) ( 1,14) (19, 6) ( 1, 6)
(15,19) ( 5,19) (15, 1) ( 5, 1) (19,15) ( 1,15) (19, 5) ( 1, 5)
(16,18) ( 4,18) (16, 2) ( 4, 2) (18,16) ( 2,16) (18, 4) ( 2, 4)
(17,17) ( 3,17) (17, 3) ( 3, 3) (17,17) ( 3,17) (17, 3) ( 3, 3)
1112111
11 11
1 1
2 2
1 1
1 1
1 1
1 1
1 1
1 1
2 2
1 1
1 1
1 1
1 1
1 1
1 1
2 2
1 1
11 11
1112111
/cygdrive/c/Temp $ ./a.exe 2 ( 2, 4) ( 2, 4) ( 2, 0) ( 2, 0) ( 4, 2) ( 0, 2) ( 4, 2) ( 0, 2) ( 3, 4) ( 1, 4) ( 3, 0) ( 1, 0) ( 4, 3) ( 0, 3) ( 4, 1) ( 0, 1) 121 1 1 2 2 1 1 121
/cygdrive/c/Temp $ ./a.exe 3 ( 3, 6) ( 3, 6) ( 3, 0) ( 3, 0) ( 6, 3) ( 0, 3) ( 6, 3) ( 0, 3) ( 4, 6) ( 2, 6) ( 4, 0) ( 2, 0) ( 6, 4) ( 0, 4) ( 6, 2) ( 0, 2) ( 5, 5) ( 1, 5) ( 5, 1) ( 1, 1) ( 5, 5) ( 1, 5) ( 5, 1) ( 1, 1) 121 2 2 1 1 2 2 1 1 2 2 121
/cygdrive/c/Temp $ ./a.exe 4 ( 4, 8) ( 4, 8) ( 4, 0) ( 4, 0) ( 8, 4) ( 0, 4) ( 8, 4) ( 0, 4) ( 5, 8) ( 3, 8) ( 5, 0) ( 3, 0) ( 8, 5) ( 0, 5) ( 8, 3) ( 0, 3) ( 6, 7) ( 2, 7) ( 6, 1) ( 2, 1) ( 7, 6) ( 1, 6) ( 7, 2) ( 1, 2) ( 7, 7) ( 1, 7) ( 7, 1) ( 1, 1) ( 7, 7) ( 1, 7) ( 7, 1) ( 1, 1) 121 21 12 1 1 1 1 2 2 1 1 1 1 21 12 121
/cygdrive/c/Temp $ ./a.exe 5 ( 5,10) ( 5,10) ( 5, 0) ( 5, 0) (10, 5) ( 0, 5) (10, 5) ( 0, 5) ( 6,10) ( 4,10) ( 6, 0) ( 4, 0) (10, 6) ( 0, 6) (10, 4) ( 0, 4) ( 7,10) ( 3,10) ( 7, 0) ( 3, 0) (10, 7) ( 0, 7) (10, 3) ( 0, 3) ( 8, 9) ( 2, 9) ( 8, 1) ( 2, 1) ( 9, 8) ( 1, 8) ( 9, 2) ( 1, 2) 11211 1 1 1 1 1 1 1 1 2 2 1 1 1 1 1 1 1 1 11211
/cygdrive/c/Temp $ ./a.exe 6
( 6,12) ( 6,12) ( 6, 0) ( 6, 0) (12, 6) ( 0, 6) (12, 6) ( 0, 6)
( 7,12) ( 5,12) ( 7, 0) ( 5, 0) (12, 7) ( 0, 7) (12, 5) ( 0, 5)
( 8,12) ( 4,12) ( 8, 0) ( 4, 0) (12, 8) ( 0, 8) (12, 4) ( 0, 4)
( 9,11) ( 3,11) ( 9, 1) ( 3, 1) (11, 9) ( 1, 9) (11, 3) ( 1, 3)
(10,10) ( 2,10) (10, 2) ( 2, 2) (10,10) ( 2,10) (10, 2) ( 2, 2)
11211
1 1
2 2
1 1
1 1
1 1
2 2
1 1
1 1
1 1
2 2
1 1
11211
[edit] Analysis
일단 신기하다 ^^ 좀 더 두고 보자. : )
- http://helloktk.tistory.com/archive/20080603 등에서 Circle Drawing Algorithm 을 소개하고 있다.
[edit] Filling a Circle
안을 채우는 것을 간단히 고쳐 보았습니다. 점 여덟 개를 찍는 대신 각각을 가로 선으로 잇기만 하면 되며, 가로 선은 가장 싼 값(cost) 에 그릴 수 있습니다. Clipping 역시 선그리기에서 합니다.
[edit] Source Code
#include <stdio.h>
#include <stdlib.h>
#define CX_CANVAS 24
#define CY_CANVAS 24
#define DEFAULT_X 10
#define DEFAULT_Y 10
#define DEFAULT_R 10
static int occurrences[CY_CANVAS][CY_CANVAS];
void PA_DrawPixel(int x, int y, int color)
{
if (x >= 0 && x < CX_CANVAS &&
y >= 0 && y < CY_CANVAS)
{
occurrences[y][x]++;
}
}
void PA_DrawHorzLine(int x1, int x2, int y, int color)
{
if (y < 0 || y >= CY_CANVAS || x1 >= CX_CANVAS || x2 < 0)
return;
if (x1 < 0) x1 = 0;
if (x2 >= CX_CANVAS) x2 = CX_CANVAS - 1;
for (int x = x1; x <= x2; x++) {
occurrences[y][x]++;
}
}
void PA_DrawCircle(int xCenter, int yCenter, int radius, int color)
{
int x = 0;
int y = radius;
int p = 3 - 2 * radius;
while (x <= y){
PA_DrawHorzLine(xCenter - x, xCenter + x, yCenter + y, color);
PA_DrawHorzLine(xCenter - x, xCenter + x, yCenter - y, color);
PA_DrawHorzLine(xCenter - y, xCenter + y, yCenter + x, color);
PA_DrawHorzLine(xCenter - y, xCenter + y, yCenter - x, color);
if (p < 0) p += 4 * x++ + 6;
else p += 4 * (x++ - y--) + 10;
}
}
void printOccurrences(int w, int h)
{
for (int y = 0; y < w; y++) {
for (int x = 0; x < h; x++) {
if (occurrences[y][x]) {
putchar('0' + occurrences[y][x]);
} else {
putchar(' ');
}
}
printf("\n");
}
}
int main(int argc, char *argv[])
{
int r = DEFAULT_R;
if (argc > 1) {
r = atoi(argv[1]);
}
// if (r <= 0 || (r >= CX_CANVAS / 2) || (r >= CY_CANVAS / 2)) {
// return 1;
// }
PA_DrawCircle(r, r, r, 0);
int maxx = 2 * r + 1;
int maxy = 2 * r + 1;
if (maxx > CX_CANVAS)
maxx = CX_CANVAS;
if (maxy > CY_CANVAS)
maxy = CY_CANVAS;
printOccurrences(maxx, maxy);
return 0;
}
[edit] Output
소스에서 Canvas 크기를 24로 해 두었기 때문에, 반지름을 15 로 하면 clipping 이 일어나는 것을 볼 수 있다.
/cygdrive/c/Temp$ ./a.exe 2 121 11111 22222 11111 121
/cygdrive/c/Temp$ ./a.exe 3 121 22222 1111111 2222222 1111111 22222 121
/cygdrive/c/Temp$ ./a.exe 4 121 2333332 1111111 111111111 222222222 111111111 1111111 2333332 121
/cygdrive/c/Temp$ ./a.exe 10
1234321
12222222221
1111111111111
222222222222222
11111111111111111
1111111111111111111
1111111111111111111
111111111111111111111
111111111111111111111
111111111111111111111
222222222222222222222
111111111111111111111
111111111111111111111
111111111111111111111
1111111111111111111
1111111111111111111
11111111111111111
222222222222222
1111111111111
12222222221
1234321
/cygdrive/c/Temp$ ./a.exe 15
1234321
1233333333321
12222222222222221
111111111111111111
1111111111111111111
11111111111111111111
111111111111111111111
1111111111111111111111
1111111111111111111111
11111111111111111111111
11111111111111111111111
11111111111111111111111
111111111111111111111111
111111111111111111111111
111111111111111111111111
222222222222222222222222
111111111111111111111111
111111111111111111111111
111111111111111111111111
11111111111111111111111
11111111111111111111111
11111111111111111111111
1111111111111111111111
1111111111111111111111

