다차원 적분

※ 이 글의 내용은 예전에 썼던 <확률과 조합에서 발견한 자연대수 e>와 <원에 대한 적분 외>의 연장선상에 있다.

1차원 선에서 0부터 1까지의 선분의 길이는 두 말할 나위 없이 1이다.
2차원 공간에서 원점, (1,0), (0,1)을 지나는 이등변삼각형의 넓이는 1의 절반인 1/2이다.
이를 더 확장해서 3차원 공간에서 원점과 (1,0,0), (0,1,0), (0,0,1)을 꼭지점으로 갖는 사면체의 부피는 1/6이다.
이를 일반화해서 n차원 적분을 생각해 보면, 차원이 하나 올라갈 때마다 n차원 축을 한 칸씩만 점유하는 초입방체의 부피는 1/(n!)로 팩토리얼의 역수가 되고,  전체 초면체와의 비는 기하급수적으로 감소한다는 걸 알 수 있다. x^n의 부정적분은 (x^(n+1)) / (n+1) + C이다.

한편, 한 변의 길이가 2인 정사각형의 넓이는 4이고, 그 안에 들어가는 반지름이 1인 원의 넓이는 잘 알다시피 pi이다. 원과 사각형의 넓의 비는 pi/4, 즉 78.5% 정도 된다.
이를 공간으로 확장하면 한 변의 길이가 2인 정육면체의 부피는 8이고, 그 안에 들어가는 반지름이 1인 구의 부피는 4*pi/3이다. 구와 정육면체의 부피 비율은 pi/6 (약 52.3%)으로, 넓이일 때보다 비율이 더 작아진다. 이 비율 역시 차원이 증가할수록 더욱 작아진다는 것은 두 말할 나위가 없을 것이다.

그럼 혹시 4차원, 5차원, n차원 초구의 부피를 구할 수도 있지 않을까? 몰론 있다.
원의 방정식의 핵심이라 할 수 있는 f(x) = sqrt( r^2 - x^2 ) 라는 함수를 먼저 정의하자. 얘는 x가 0에서 r로 갈 때 임의의 구간에서 원의 높이를 나타내는, 즉 '둥긂'을 수학적으로 기술하는 함수이니까 말이다.

반지름이 r인 원의 넓이는 잘 알다시피 int( 2*f(x), x=-r..r) 로 나타내어지며 pi*r^2이라는 유명한 공식이 나온다.

그럼 반지름이 r인 구의 부피는 pi*r^2에서 r 대신 f(x)를 다시 집어넣어서 적분을 하면 된다.
int(pi*f(x)^2, x=-r..r) 가 (4/3)*pi*r^3이 된다.

4차원부터도 동일한 방식으로 적분을 계속하면 된다. 수많은 구들이 4차원에 있는 원 표면의 높이 변화량만치 연속적으로 쌓여 있는 것이므로.. 저 r 대신에 또 f(x)를 집어넣으면
int(4*pi*f(x)^3/3, x=-r..r) 은 드디어 파이까지도 제곱이 되어 4차원 초구의 부피는 (1/2)* pi^2 * r^4가 나온다. 한 변의 길이가 2인 4차원 초정육면체와의 부피 비율은 약 30.8%대로 곤두박질친다.

5차원 초구는? int( pi^2 * f(x)^4 / 2, x=-r..r)의 결과는 (8/15) * pi^2 * r^5 (약 16.4%)
6차원 초구는 pi^3 * r^6 / 6 (약 8%)가 된다. 사면체의 부피만큼이나 이것도 비율이 갈수록 곤두박질친다.
요렇게 비율이 한데 수렴하고 특히 짝수차일 때와 홀수차일 때 번갈아가며 무슨 특성이 발견되는 건 리만 제타 함수의 값하고도 비슷해 보인다. 게다가 리만 제타 함수도 n이 짝수일 때는 나름 pi^n의 유리수배가 되기도 하니, 반지름 길이가 1인 n차원 초구의 부피하고도 비록 수학적 의미는 딴판일지언정 좀 비슷해 보이는 구석이 있다.

수학 전공자 중에는 위의 적분들을 직접 손으로 푸는 용자도 있다. 그나마 짝수 승일 때는 루트가 없어지기 때문에 계산이 더 쉬워지는 편. 난 차마 손으로 풀어 볼 시간이나 자신은 없어서 그냥 수학 패키지를 돌려서 답을 구했다.
딱 보면 알겠지만 식에는 규칙성이 있다. 홀수승일 때와 짝수승일 때를 따로 생각해서 각각 차수가 2씩 증가할 때마다 pi에 붙는 제곱도 1씩 증가하고 계수는 2/n씩 증가한다고 보면 정확하다. 짝수승일 때는 1/2 (4차원), 1/24 (6차원)처럼 상수 계수가 1/n!으로 깔끔하게 증가하는 반면, 홀수승일 때는 계수가 좀 복잡하게 올라간다.

울트라 초천재가 아니고서야 4차원이 넘어가는 초구의 존재를 인간의 머리로 제대로 상상하고 실감하기는 거의 불가능할 것이다. '넘사벽'이라는 말이 괜히 있는 게 아니다~!
눈과 귀로 직감할 수 없는 차원이라는 게 신앙의 영역에 있다면, 이해가 안 되더라도 말 그대로 믿음으로 받아들일 수밖에 없을 것이다. 그러나 수학은 그런 게 아니라 고도의 논리와 이성의 영역에 있다.

아쉬운 대로 고차원 공간을 시뮬레이션 할 수 있는 방법은 프로그램을 작성하는 것이다. 다음 코드는 n차원 공간을 -1부터 1까지 점을 순서대로 마구 찍은 뒤, 원점으로부터 거리가 1 이내인 점의 개수를 세서 부피 비율을 구한다. 깔끔한 재귀호출 대신 사용자 정의 스택으로 구현했다.

double GetVolume(int dim, double delta)
{
    double buf[8], vl; int pos=0, i;
    double initv=-1.0-delta;
    __int64 x=0,y=0; buf[0]=initv;
    while(pos>=0) {
        if(pos==dim) {
            for(vl=0, i=0; i<dim; i++) {
                vl+=buf[i]*buf[i]; if(vl>1.0) break;
            }
            if(i==dim) ++x; ++y; --pos; //1 이내에 들면.
        }
        else {
            buf[pos+1]=initv;
            if( (buf[pos]+=delta) > 1.0) --pos; else pos++;
        }
    }
    return (double)x/y;
}

그래서 이렇게 찍으면 결과는 다음과 같이 나온다.

printf("%f\n", GetVolume(2, 0.01)); //0.785075
printf("%f\n", GetVolume(3, 0.01)); //0.523467
printf("%f\n", GetVolume(4, 0.03)); //0.302340
printf("%f\n", GetVolume(5, 0.05)); //0.164649

처음엔 -1부터 1까지 0.01씩 움직이니까 200등분을 했지만 4차원과 5차원으로 갈수록 66등분, 40등분으로 간격을 늘린 이유는.. 당연히 4승, 5승으로 급격히 증가하는 계산량을 감당할 수 없기 때문이다. 그래서 2차원과 3차원은 값이 상당히 정확히 나온 반면, 4차원과 5차원은 오차가 좀 큰 편이다.
그래도 계산이 워낙 단순무식하고 간단하므로 OpenMP 지시자를 집어넣거나 직접 손으로 코드 차원에서 스레드를 강제 분배하든가 해서 멀티코어+병렬화 최적화로 계산 속도를 몇 배 정도 끌어올릴 여지는 존재한다.

사실은 4차원 이상으로 갈 필요도 없이, 3차원 공간에 구가 여러 개 포개어져 있는 장면을 상상하는 것도 쉽지 않다.
학교 수학 시간에 집합 사이의 bool 관계를 구하는 문제에서 집합의 개수는 3개를 넘어간 적이 없었다. 왜냐하면 2차원 평면에서 집합들의 모든 소속 가짓수를 벤 다이어그램으로 그릴 수 있는 한계가 3개이고 2^3, 총 8가지 가짓수이기 때문이다.

그러나 3차원 공간에서 구를 4개 포개어서 입체 벤 다이어그램을 그리면 16가지 가능성을 모두 표현할 수 있다. 구 3개가 8가지 가짓수를 만들고, 거기에 위에다 4개의 구를 적당히 겹쳐 놓으면 8개에다가 넷째 구와 겹치는 놈 8가지가 또 추가되어서 16개가 되니까 말이다. 이 역시 코드로 작성해서 무식하게 확인하면 다음과 같다.

struct SPHERE { double x,y,z; };
const SPHERE fp[4]={
    {0,0,0},
    {0.4,0,0},
    {0.2,0.4,0},
    {0.2,0.2,1.5}
};
auto Square = [](double x) { return x*x; };
SPHERE d;
bool bitfl[16]={false,};
for(d.x=-1; d.x<=1.5; d.x+=0.02)
    for(d.y=-1; d.y<=1.5; d.y+=0.02)
        for(d.z=-1; d.z<=1.5; d.z+=0.02) {
            int bt=0;
            for(int i=0; i<4; i++)
                if( Square(fp[i].x-d.x)+Square(fp[i].y-d.y)+Square(fp[i].z-d.z) <=1) bt|=(1<<i);
            bitfl[bt] = true;
        }
for each(int n in bitfl)
    printf("%d ", n);

반지름은 모두 1이고, (0,0,0), (0.4,0,0), (0.2,0.4,0), (0.2,0.2,1.5)인 4개의 구를 설정한다. 그리고 -1부터 1.5까지 0.02 간격으로 뺑뺑이를 돌려서.. 각 점별로 자기가 속하는 구의 번호에 해당하는 2진수 비트들(8+4+2+1)의 합을 구한다. 그 뒤 그 합에 해당하는 플래그를 켠다.

나중에 플래그의 값을 출력해 보면 모든 비트들이 1로 바뀌었음을 알 수 있다. 즉, 어느 구에도 속하지 않은 놈, 모든 구에 속한 놈, 1, 3, 4번 구에만 속한 놈, 2, 3번 구에만 속한 놈 등등 16가지 가능성이 실제로 모두 존재한다는 뜻이다. 어찌 보면 당연한 얘기이다. 그 반면 구가 5개를 넘어가면 그 32, 64가지 가능성을 한꺼번에 3차원에서 표현할 수는 없게 된다.

사용자 삽입 이미지

반지름이 수십~수백 정도에 달하는 충분히 큰 구의 복셀의 표면을 보는 느낌은 어떨까 문득 궁금해진다.
수학 패키지 소프트웨어들은 3차원 음함수의 그래프를 아무래도 폴리곤+와이어프레임 형태로 근사해서 보여 줄 것이다. 하지만 곡선/곡면을 폴리곤이 아니라 아예 계단현상을 볼 수 있는 복셀로 근사해서 보면 또 느낌이 굉장히 이색적일 것 같다.

사용자 삽입 이미지

표면에는 역시나 원들 무늬가 그러져 있구나!
앞서 보다시피 5차원~6차원 이상으로 가면 단순무식하게 점을 때려박는 것도 계산이 너무 많아서 도저히 감당할 수 없다.
이럴 때 정확한 초구의 부피를 구할 수 있는 건 역시나 수학 해석적인 방법이라는 것을 알 수 있다.
미분 내지 역함수인 부정적분을 할 때 변수의 차수와 계수가 왜 저렇게 변하는지는 다항함수의 차이 극한값을 구해 보면 알 수 있다. 극한부터 시작해서 미분· 적분이라는 개념을 생각해 낸 건 정말 위대한 발견인 것 같다.

Posted by 사무엘

2015/10/15 08:39 2015/10/15 08:39
, , , ,
Response
No Trackback , 2 Comments
RSS :
http://moogi.new21.org/tc/rss/response/1149

한자어로 '원'이라고 부르는 동그라미라는 도형은 시각적으로나 수학적으로나 아주 신기한 도형이다.
둥글다는 게 무슨 의미인지 기계가 계산으로 표현할 수 있을 정도로 엄밀하게 정의하자면 결국 '어떤 점에서 거리가 같은 점들의 집합'이라는 정의가 등장하게 되고, n차원 직교 좌표에서 거리라는 건 결국 차원을 구성하는 각 축의 거리들의 제곱의 합의 제곱근이라고 정의된다.

원의 지름과 원의 둘레의 비율은 그 이름도 유명한 '파이'이며, 3.141592... 로 시작하는 이 값은 무리수인 동시에 초월수라는 것도 상식이다.

그런데 이 원을 정사각형 격자 모양의 래스터 그래픽 장치에서 어떻게 하면 효율적으로 그릴 수 있을까? 그런 물건의 내부엔 컴퍼스 같은 직관적인 도구가 없는데 말이다.
중심이 x, y이고 반지름이 r인 원을 구성하는 좌표들을 어떤 계산을 통해 얻어 올 수 있을까?
원점이 중심인 원의 방정식은 x^2+y^2=r^2. 따라서 y=sqrt(r^2-x^2) 방정식을 이용하면 사분원 내지 반원을 구성하는 점을 구할 수 있다. 그리고 이 값을 바탕으로 나머지 방향의 점을 그리면 될 것이다.

#include <math.h>
template<typename T>
void Draw_Circle(int x, int y, int r, T f)
{
    double R_2 = r*r;
    for(int i=0;i<r;i++) {
        int v = (int)(sqrt( R_2 - i*i )+0.5);
        f(x-i, y-v); f(x-i, y+v);
        f(x+i, y-v); f(x+i, y+v);
    }
}

for문 자체는 0부터 r까지 사분원의 x좌표만 돌고, 이를 바탕으로 점을 찍는 함수 f를 4개 방향으로 모두 호출한다.
r의 제곱 값은 한 번만 계산하면 되므로 for문 밖에서 별도로 선언해 주는 센스도.
소숫점은 버림이 아니라 반올림이 되도록 0.5를 더한 뒤에 int로 캐스팅하는 게 좋다. 그래야 당장 그려지는 원도 90*n도 부근이 더 탱탱하고 보기 좋아진다.

함수의 사용은 MFC 기준으로 이런 식으로 하면 된다. 함수 안에서 또 다른 함수를 내부적으로 호출할 때 함수 포인터보다 람다가 참 깔끔하긴 하다. (너무 남발한 게 꼬이면 code bloat은 피할 수 없겠지만)

CPaintDC dc(this);
auto x = [&](int x,int y) { dc.SetPixel(x,y,0); };
Draw_Circle(220,220, 200,  x);
Draw_Circle(420,330, 160,  x);

사용자 삽입 이미지

그런데 아뿔싸, 역시 기울기가 1보다 더 커지는 곳에는 점이 듬성듬성 떨어져 있게 된다.
이 틈을 점 찍기가 아니라 선 그리기 같은 다른 함수로 메운다는 건 있을 수 없는 일이고..
결국, 우리의 원 그리기 알고리즘은 언제나 기울기가 1보다 작은 구간에서만 동작하게 loop 구조를 바꿀 필요가 있다.
우리는 원을 4등분했는데, 그렇게 4등분된 조각도 한쪽 끝과 맞은편 끝이 완벽하게 대칭으로 이들을 동시에 그려 보자.

가령, 1사분면에서는 x좌표를 1씩 증가시키면서 r로 근접하고(위의 코드에서 i) y좌표는 r이다가 점점 0으로 작아지는데(위의 코드에서 v),
이와 동시에 반대편에서는 y좌표를 1씩 증가시키면서 r로 근접하고, x좌표는 r에서 0으로 근접시키도록 점을 같이 그리는 것이다.
이제 loop는 변수 i의 값이 r에 도달한 지점에서 끝나는 게 아니라 v와 값이 같아지는 지점에서 끝나면 된다. (정확히는 sqrt(2)*r/2 지점이 됨)

{
    double R_2 = r*r;
    for(int i=0; ;i++) {
        int v = (int)(sqrt( R_2 - i*i )+0.5);
        f(x-i, y-v); f(x-v, y-i);
        f(x-i, y+v); f(x-v, y+i);

        f(x+i, y-v); f(x+v, y-i);
        f(x+i, y+v); f(x+v, y+i);
        if(i>v) break;
    }
}

사용자 삽입 이미지
와, 이로써 굉장히 찰진 모양의 원이 그려졌다. 한 번 루프를 돌 때마다 점이 8개가 그려지는 것이다.
그러나 이런 원 하나 그리는데 부동소숫점에, 곱셈에, 심지어 제곱근까지 꽤 부담스러운 연산이 많이 들어갔다.
이걸 좀 줄일 수는 없을까?

...
    int R_2 = r*r;
    int v = r;
    for(int i=0; ;i++) {
        if(i*i + v*v > R_2) --v;
...

loop의 앞부분을 이렇게 고쳐 보자.
x축에 속하는 i의 값이 1증가할 때마다 y축에 속하는 v의 값은 그대로 유지되거나 1 감소하거나 둘 중 한 변화만을 겪을 것이다.
i가 증가함에 따라 원점에서 i, v까지의 거리가 R보다 확 커지게 됐다면, 이 궤적은 원의 범위를 벗어나는 것이므로 y축에 속하는 v를 1 줄여 준다.

실질적으로 행해지는 연산을 이렇게 최적화해 주면 최소한 부동소숫점과 제곱근 연산은 없어진다.
그러나 최적화의 여지는 그래도 여전히 남아 있다. 저 꼴도 보기 싫은 곱셈을 없애려면 어떡하면 좋을까?

방법이 있다.
결국, i*i는 0, 1, 4, 9, 16 ...의 순열을 생성해 낼 텐데, 얘는 덧셈을 두 번 하는 걸로 대체할 수 있다. 한 번 덧셈을 한 뒤엔 증가치가 2씩 늘어나니까 말이다(1과 4의 차는 3, 4와 9의 차는 5, 9와 16의 차는 7). x^2의 도함수가 괜히 2*x가 아니다.

그리고 v는 초기값이 아예 R_2와 같으니 약분이 가능하다. 그 뒤에 v의 값이 줄어들면서 차이만이 발생할 뿐이다. 그런데 얼마를 빼 줘야 할까?
x^2가 (x-1)^2로 바뀌었을 때 감소하는 값은 잘 알다시피 2*x-1이다. 따라서 이 값만 초기에 계산해 놓은 뒤, v가 1 감소하게 됐을 때 가상의 v_square은 그만치 빼 주고, 그 델타값 자체도 2 감소시키면 된다.

...
    int v = r, i_square = 0, i_delta = 1;
    int v_delta=2*r-1, v_square_delta = 0;
    for(int i=0; ;i++) {
        if(i_square + v_square_delta > 0) {
            --v; v_square_delta-=v_delta, v_delta-=2;
        }

... //점 여덟 군데를 찍어 준 뒤

        if(i>v) break;
        else i_square+=i_delta, i_delta+=2;
    }

이로써 그 부드러운 원을 오로지 정수의 덧셈만으로, 그리고 곱셈이라고는 loop 돌기 전에 *2 단 한 번밖에 안 하는 깔끔한 원 그리기 알고리즘이 완성되었다. 놀랍지 않은가? 게다가 고정적인 두 배 연산은 잘 알다시피 bit shift로도 수행 가능한 아주 가벼운 연산이기도 하고 말이다.

GWBASIC, Windows GDI API, 옛날 볼랜드 BGI 등 모든 그래픽 라이브러리에 들어있는 원 그리기 함수는 기본적으로 이 알고리즘을 이용하여 원을 그린다. 각종 알고리즘 서적에 예제로 실려 있는 소스들도 세부적인 변수 활용이나 계수 계산에 차이가 있을지언정 기본적인 아이디어는 동일하다.

사실, 이건 거의 대학교 학부 수준이고 정보 올림피아드 공부라도 했다면 중· 고등학교 시절에라도 접했을 기초적인 내용이다. 진짜 어려운 건 이걸 응용하여 안티앨리어싱을 적용한다거나 타원을 그리거나, 아예 부채꼴 내지 회전된 원을 그리는 알고리즘이다.

단, Windows GDI가 그리는 원은 왠지 좀 엉성하고 덜 예쁜 것 같다. 비교를 할 때 반올림 보정을 안 하는지 경계가 아주 약간 덜 통통하며, 특히 기울기가 1(45도)에 가까워지는 지점에 점의 배치가 지저분하다.
차이를 보이기 위해 움짤을 만들어 보았다. 파란색 원은 GDI 함수로 그린 것이고, 빨간색 원은 우리가 작성한 함수로 그린 것이다.

사용자 삽입 이미지

Posted by 사무엘

2013/07/28 08:27 2013/07/28 08:27
, , ,
Response
No Trackback , 6 Comments
RSS :
http://moogi.new21.org/tc/rss/response/860

2차 곡선(원뿔 곡선) 이야기

수학에서 함수라는 것은 y=f(x)와 같은 형태로, x에다가 임의의 수를 대입하면 그에 대응하는 y 값이 계산을 통해 딱 하나로 산출되어 나오는 관계를 말한다.

하지만 f(x, y)=0라고 함수를 정의할 수도 있다.
이 식을 만족하는 x, y가 곧 정의역과 치역임이 규정된다.
이런 형태의 함수를 수학 용어로는 음함수(implicit function)라고 일컫는다.
딱 명시적인 함수 형태는 아니지만 함수를 암시적으로 규정하고 있다는 뜻인데, ‘음’이라고 하면 negative가 먼저 떠올라서 한국어로는 뜻이 잘 와 닿지 않는 것 같다.

음함수가 표현력이 더욱 풍부하다. 그도 그럴 것이 y=sqrt(1-x^2)라고만 하면 사분원반원 하나밖에 표현을 못 하지만, x^2+y^2=1이라고 하면 원 전체를 표현할 수 있기 때문이다.
그리고 컴퓨터 상으로 음함수를 처리하는 것도 더욱 까다롭다. x뿐만 아니라 x와 y를 2차원적으로 모두 고려해야 하기 때문이다. 2차원만으로 모자라서 z축도 동원하여 3차원까지 가면 흠..;;;

고등학교 시절에는 이런 음함수 중에서 x, y의 계수가 최대 2차까지 갈 수 있는 녀석을 배운다. 일반화하면 아래와 같은 꼴.

a*x^2+ b*x*y+ c*y^2+ d*x+ e*y+ f = 0

2차식인 a, b, c중 적어도 하나가 0이 아니라면 이 음함수는 아래의 형태 중 하나가 된다.

1. x, y가 실수 범위에서 전혀 존재하지 않기 때문에 빈 그래프. (x^2+y^2=-1 같은 경우)
2. 두 직선 (x^2-y^2=0 같은 경우. 또한, xy=0 이라고 하면 x축과 y축^^)
3. 타원 (x^2+y^2=1)
4. 쌍곡선 (x^2-y^2=1)

원이나 포물선은 굉장한 레어 케이스에서나 존재 가능하다.
또한, a, b, c 계수의 관계에 따라 곡선의 모양이 어떻게 될지 알려주는 판별식도 있다.

2차 곡선인 이들 원, 타원, 포물선, 그리고 쌍곡선은 모습도 인간 세계에서 수학적인 의미를 두기에 충분한 가치를 지니고 있다. 모래시계처럼 ▶◀ 형태로 놓인 원뿔의 단면을 잘랐을 때 나오는 곡선이라고 해서 원뿔곡선(conic section)이라고도 불린다. 신기한 일이 아닐 수 없다.

사용자 삽입 이미지

짤방은.. 초점이 동일한 어느 타원과 쌍곡선의 모습을 자작 프로그램으로 그린 것. 나름 안티 앨리어싱까지 되어 보기에 더욱 아름답다. ㅋ

타원은 “한 초점에서의 거리 + 다른 초점에서의 거리”가 일정한 점들의 집합이다. 두 초점에다가 실을 묶고 팽팽하게 연필을 그으면 비교적 쉽게 그릴 수 있다.
원은 두 초점의 위치가 일치하는 특수한 경우라 하겠다. 타원 모양으로 된 당구대 안에서 그 타원의 한 초점에서 공을 굴리면, 그 공은 다른 초점을 반드시 지나게 될 것이다.

쌍곡선은 “한 초점에서의 거리 - 다른 초점에서의 거리”의 절대값(=차이)이 일정한 점들의 집합이다. 절대값이다 보니 필연적으로 곡선이 둘 존재한다. 초등학교 시절에 배웠던 y=1/x 반비례 그래프가 알고 보니 이 쌍곡선이었다는 사실을 알게 된다.

포물선이야 중학교 시절에 제곱근과 2차식이라는 개념 자체를 처음으로 접할 때 배운다. 그런데 포물선은 단순한 2차식을 넘어서 “한 초점과 한 기준선이 주어졌을 때 초점에서의 거리와 준선까지의 수직 최단 거리가 일치하는 점들의 집합”으로 다른 관점에서 정의가 이루어진다. 사실, 타원과 쌍곡선도 한쪽 초점이 한없이 멀어지면 포물선 모양으로 수렴하게 된다.

포물선은 중력이 존재하는 지구상에서 물건을 던지기만 해도 매우 쉽게 볼 수 있다(단, 공기 저항이 없어야). 포물면은 반사하는 모든 빛을 초점으로 한데 모을 수 있다. 다만, 만들기가 구면보다는 어렵다.

2차 곡선은 이렇듯 세상에서 쉽게 볼 수 있고 실용적이다. 거리와의 제곱에 비례해서 감소하는 만유인력과도 관계가 있다. 제곱의 의미는 2차원, 즉 면적이다.
인공위성은 흔히 지구를 향해 한없이 추락하는 물체라고들 한다. 공중에서 충분한 추진력으로 위성을 가속하지 못하면 그 발사체는 지구로 떨어져 버린다. 그러나 속력이 어느 정도 빨라진 순간부터는 이제 지구로 떨어지지 않고 원 궤도를 그리게 된다.

더 빨라지면 위태위태 타원 궤도를 그리게 되고, 어느 정도 도를 넘어서면 포물선, 그 이후부터는 쌍곡선 궤도를 그리면서 그 발사체는 지구로 다시는 돌아오지 않게 된다. 옛날에 이런 거 시뮬레이션 프로그램을 장난감 삼아 짜면서 놀았던 기억이 있다. ^^;;

그 반면에 음함수의 식이 3차까지 가면, 모양만 변태적으로 복잡하지 쓸모가 없다. 변수의 값이 어떻냐에 따라서 쌍곡선 같은 그런 곡선이 3쌍둥이가 생기기도 하고, -⌒- 이런 모양이나 아니면, 그런 모양에 U자 모양 곡선이 합쳐진 놈 등... 자연에서 볼 일도 없고 의미가 없다는 것이다.

앞서 음함수를 처리하는 건 쉬운 일이 아니라고 언급했는데, 실제로 그렇다.
정확하게 일치하지는 않겠지만 윤곽선 폰트를 래스터라이즈하는 일과 비슷한 과정이 아닐까 하는 생각이 든다.
무식하게 x*y개의 함수값을 일일이 다 구해 보지 않고도 함수값을 구성하는 영역만 매끄러운 경계선을 추출하고 거기에다 안티 앨리어싱까지 하는 건 보통 어려운 일이 아니다.

아래아한글이나 포스트스크립트 같은 다른 폰트 시스템은 잘 모르겠지만, 윈도우 운영체제가 사용하는 트루타입 폰트 래스터라이저는 매 도트에 대해서 윤곽선 안에 있는지의 여부를 판단해서 글자를 찍어 낸다. 그래서 힌팅 정보가 없으면 작은 글씨에서 가는 획이 아예 화면에서 사라지는 일이 생길 수 있다.

본인은 옛날에 너무나 깔끔하게 잘 출력되는 영문 폰트들을 보고서 트루타입 폰트 래스터라이저가 굉장히 똑똑한 줄 알았는데, 알고 보니 다 아주 정교한 수작업으로 만들어진 힌팅 정보 덕분이었다. 힌팅은 획의 굵기를 일관성 있게 보정할 뿐만 아니라 윤곽점을 래스터라이저가 글립 존재 여부를 판단할 때 사용하는 위치로 강제로 옮겨서 획이 사라지지 않게 하는 역할도 한다.
흠, 글 주제가 수학에서 폰트 얘기로 급반전.. 어쨌든 음함수의 렌더링도 그만치 쉬운 일은 아니라는 뜻이다. ^^;;

Posted by 사무엘

2010/10/01 20:23 2010/10/01 20:23
, , , , , , ,
Response
No Trackback , 2 Comments
RSS :
http://moogi.new21.org/tc/rss/response/383


블로그 이미지

그런즉 이제 애호박, 단호박, 늙은호박 이 셋은 항상 있으나, 그 중에 제일은 늙은호박이니라.

- 사무엘

Archives

Authors

  1. 사무엘

Calendar

«   2024/11   »
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30

Site Stats

Total hits:
2955747
Today:
117
Yesterday:
2539