사라진 교점들은 어디로 갔을까?
화면 위 두 이차곡선을 끌어보라. 어떤 때는 교점이 네 개, 어떤 때는 둘, 하나, 없음. 충돌을 계산하는 물리 엔진, 패스를 잘라내는 벡터 도구, 외곽선을 다듬는 폰트 래스터라이저, 픽을 처리하는 레이 트레이서 — 모두 “몇 개?”라는 물음에 흔들리지 않는 답이 필요하다. 화면 위의 수는 깜빡거린다. 그 아래 수학은 깜빡이지 않는다.
베주 정리는 두 이차곡선의 교점이 늘 4개라고 말한다 — 올바른 수 체계, 올바른 평면, 올바른 중복도로 셀 때. 아래 위젯은 베주 모듈에 실린 위젯과 같은 것이다. 다만 여기서 답하는 질문이 다르다: 그 4개 중에서 화면이 실제로 보여주는 건 어느 것인가?
화면이 보는 것 vs 거기 있는 것
2D 평면 위의 두 실수 곡선. 눈에 보이는 셈이란 같은 픽셀에서 두 곡선이 만나는 점의 개수 — 좌표가 실수이고 양쪽 모두 유한한 경우다. 래스터 샘플링으로 답을 내는 단순 충돌 검출기, 근사 근-찾기로 답을 내는 CAD 엔진이 모두 이 셈을 내놓는다. 곡선이 지금 어디쯤 떠 있느냐에 따라 달라지고, 작은 섭동에도 쉽게 흔들린다.
위젯에서 확인해 보자. 일반 프리셋은 실수 교점 4개 — 보이는 셈과 베주의 셈이 맞아떨어진다. 접 프리셋에서는 3개로 보이지만, 중복도 표시를 켜면 그중 하나에 가 붙는다. 분리 프리셋에서는 0개로 보이지만, 복소 보기를 켜면 옆 패널에 빈 동그라미 네 개가 떠오른다. 사라진 교점들은 잃어버린 것이 아니다. 단지 실-아핀 평면을 떠났을 뿐.
세 가지 숨는 곳
베주의 보정(베주 모듈에서 자세히 다룬다)은 사라진 교점이 어디로 갔는지 정확히 짚어준다. 보정은 셋, 들여다볼 자리도 셋이다.
- 접점. 두 교점이 한 기하점으로 포개진 경우 — 대수는 여전히 둘이라고 말하지만 렌더러 눈에는 한 점만 보인다. 이걸 장부에 적는 방식이
다. 접 교점은 2로 센다.교차 중복도 - 보이는 평면 바깥. 교점의 좌표가 복소수인 경우 — 대수의 해로는 분명히 존재하지만 실수 격자 위에는 찍을 자리가 없다. 떨어져 있는 두 단위원조차 에서 만난다. 화면에는 이 점을 놓을 곳이 없다.
- 무한 멀리. 어떤 교점은 무한원선 위에 자리 잡는다. 서로 다른 두 원은 어디에 놓여 있든 늘 두 원형점 과 을 공유한다 — 베주의 4개 중 2개는 이미 화면 밖, 복소수, 좋든 싫든 장부에 적힌 셈이다. 이 보정의 무대가
이다.사영평면
그래픽 엔진이 *흔들리지 않는 수*를 챙기는 이유
“보이는 셈”만 좇는 엔진은 깨지기 쉽다. 거의 접하는 두 원의 보이는 셈은 서브픽셀 떨림에 따라 0이 되었다 1이 되었다 2가 된다. 한 프레임에 “교점 없음”, 다음 프레임에 “교점 둘”이라 보고하는 렌더러는 결국 수치 잡음을 물리로 둔갑시키고 있는 것이다. 답은 대수적 셈 — 베주가 보장해 주는 바로 그 셈 — 을 먼저 구하고, 각 근을 분류하는 데 있다.
실제 절차는 이렇다. y-종결식(x에 대한 4차)을 푼다. 중복도까지 포함해 복소근 4개를 모두 찾는다. 각각을 실-아핀(보임), 복소(평면 밖), 무한원(점근) 중 하나로 분류한다. 첫 번째 부류의 개수가 곧 보이는 셈이다. 접점은 “우연히 매우 가까운 두 근”이 아니라 중복근으로 표시된다. 중복도 2인 실수 근 하나와 서로 ε 안에 있는 서로 다른 실수 근 둘은 화면 위에서는 똑같아 보이지만, _기하적으로는 전혀 다른 상황_이다 — 대수 분류가 이 둘을 갈라놓는다.
엔진이 실제로 계산하는 것
파이프라인은 짧다. (1) 두 이차곡선 식에서
# Engine pipeline: solve, classify, render. Bezout count = 4 always
# for two conics; the picture only shows the real-affine subset.
import numpy as np
def conic_resultant(c1, c2):
"""y-resultant of two conics → quartic in x. (Same as bezout module.)"""
a1, b1, cc1, d1, e1, k1 = c1
a2, b2, cc2, d2, e2, k2 = c2
P = np.polynomial.Polynomial
A1, A2 = cc1, cc2
B1, B2 = P([e1, b1]), P([e2, b2])
C1, C2 = P([k1, d1, a1]), P([k2, d2, a2])
return (A1*C2 - A2*C1)**2 - (A1*B2 - A2*B1)*(B1*C2 - B2*C1)
def classify(roots, eps=1e-6):
"""Group complex roots into 'real-affine' (visible) and 'complex' (off-plane)."""
visible, off_plane = [], []
for r in roots:
if abs(r.imag) < eps:
visible.append(r.real)
else:
off_plane.append(r)
return visible, off_plane
# Two ellipses, perpendicular major axes — the "general" preset.
c1 = (1/4, 0, 1, 0, 0, -1)
c2 = (1, 0, 1/4, 0, 0, -1)
roots = conic_resultant(c1, c2).roots()
visible, hidden = classify(roots)
len(visible), len(hidden) # → (4, 0) four visible crossings
# Two disjoint ellipses — the "disjoint" preset.
c2_far = (9, 0, 1, 0, -10, 24)
roots2 = conic_resultant(c1, c2_far).roots()
v2, h2 = classify(roots2)
len(v2), len(h2) # → (0, 4) nothing on screen, all complex
# Bezout 4 = 0 visible + 4 hidden. The "disjoint" pair never lost the count;
# the renderer just had no place to draw the imaginary parts.그래픽 스택 안의 자리
같은 베주 + 분류 로직이 모양만 바꿔서 곳곳에서 돌아간다.
- 충돌 검출. 두 볼록 도형(원·타원·캡슐)이 몇 번 만나는가? 베주가 상한을 잡아 주고, 접 + 중복도가 스치는 접촉을 잡아내며, “실수 0 + 복소 4”는 곡선이 깔끔히 떨어져 있다는 뜻이 된다.
- 벡터 클리핑. Illustrator나 Figma에서 두 경로의 교차를 구할 때, 도구는 3차 베지에 곡선 사이의 대수 교점을 계산한다 — 차수 3 × 차수 3 = 최대 9개를 보임 / 구간 밖 / 접으로 나눈다.
- 레이-곡선 픽. 직선(차수 1)과 이차곡선(차수 2)은 대수적으로 2개의 점에서 만난다. 마우스 클릭은 레이를 따라 처음 만나는 실-아핀 교점을 고른다. 둘 다 복소수면 클릭은 그대로 빗나간다.
- 폰트 외곽선 래스터화. 수평 스캔라인(차수 1)이 글리프 외곽선(최대 3차의 베지에)을 d·1 = d개의 점에서 가로지른다. 중복도까지 함께 세면 짝-홀 채움 규칙이 덤으로 따라온다.
겉 이야기는 어디서나 “세고 분류한다”이고, 그 밑의 이야기는 베주 정리와 근 분류기다. 입는 옷은 달라지지만, 셈의 규약은 변하지 않는다.
실수 교점은 들고 난다. 베주의 셈은 그러지 않는다. 화면에 비치는 것은 변하지 않는 그 셈의 실-아핀 부분집합이다. 그래픽 엔진은 셈 전체를 손에 쥔 채 원소 하나하나에 꼬리표를 달고, 그림은 그중 한 부류일 뿐이다.
직선 는 단위원 과 베주 셈으로 몇 점에서 만나는가? 어떤 의 범위에서 그 점들이 모두 보이고(실-아핀), 어떤 범위에서 일부가 복소수로 숨는가? 각 경우의 예를 하나씩 그려 보라.
서로 다른 두 원을 잡자. 베주는 4번 만난다고 한다. 그런데 화면 위 그림에서는 실-아핀 교점이 늘 2개를 넘지 않는다. 나머지 2개는 언제나 어디에 있는가? (힌트: 원의
엔진에 매개변수가 둘 있다고 하자. 각도 와 허용오차 . 가 접 배치를 통과할 때, 보이는 셈은 2 → 1 → 0 → 1 → 2로 변한다. 접 순간은 하나의 배치, 그 양옆의 거의-접 순간은 또 다른 배치다. 그 차이를 대수적으로 진술하고(중복도 2인 근 하나 vs ε 안에 놓인 서로 다른 두 근), 견고한 엔진이 단순한 -거리만으로 중복 제거를 해서는 안 되는 이유를 설명하라.
수평 직선 과 3차 곡선 의 교점을 구해 보자. 베주 예측은 1·3 = 3. 실-아핀은 몇 개이고, 나머지는 어디에 있는가? (보이는 점에는 가 필요 없고, 나머지에는 각각 하나씩 들어간다.)