본문으로 건너뛰기
김신건의 로그

도형 불 연산 (Geometric Boolean Operations)

· 수정 · 📖 약 4분 · 1,225자/단어 #algorithm #geometry #geometric-boolean-operations
geometric boolean operations, polygon clipping, Sutherland-Hodgman, Weiler-Atherton, 도형 불 연산, 폴리곤 클리핑

정의

도형 불 연산 (Geometric Boolean Operations) 은 두 다각형(또는 임의의 폐곡선)에 대해 합집합(union), 교집합(intersection), 차집합(difference)을 계산하는 기하 알고리즘. 대표적으로 Sutherland-Hodgman (convex clipping) 과 Weiler-Atherton (general polygon clipping) 이 알려져 있음.

문제 상황과 동기

두 다각형 A, B 가 주어졌을 때 A ∪ B, A ∩ B, A - B (또는 B - A) 를 구해야 함.

  • Naive 접근: 각 변을 무한 직선으로 확장 후 교차점을 찾고 폐곡선을 재구성. O(NM) 이지만 self-intersection / 구멍 처리 까다로움.
  • 핵심 통찰: 한 다각형의 각 변을 clipping edge 로 삼아 반대 다각형을 잘라내면 출력 폴리곤이 자연스럽게 생성. Weiler-Atherton 은 교차점 리스트를 따라가며 출력 링을 구성.
  • PS 위치: convex polygon clipping 은 Sutherland-Hodgman 으로 O(N+M). 일반 polygon 은 Weiler-Atherton 필요.

시각화

핵심 아이디어

Sutherland-Hodgman: convex clipping window 의 각 edge 에 대해, subject polygon 의 점들을 inside/outside 판정. 출력 리스트를 누적.

for each clip edge (from clip polygon):
    for each edge (S->E) of subject:
        if S inside, E inside  -> output E
        if S inside, E outside -> output intersection
        if S outside, E inside -> output intersection, then E
        if S outside, E outside -> output nothing

Weiler-Atherton: 교차점을 표시한 후, entering/leaving 에 따라 출력 링크를 순회.

알고리즘

Sutherland-Hodgman(subject, clip):
    output = subject
    for each edge of clip:
        input = output; output = []
        for each edge S->E in input:
            if inside(E, clipEdge):
                if not inside(S, clipEdge):
                    output.push(intersect(S,E, clipEdge))
                output.push(E)
            else if inside(S, clipEdge):
                output.push(intersect(S,E, clipEdge))
    return output

구현

// Sutherland-Hodgman convex polygon clipping
#include <bits/stdc++.h>
using namespace std;
using ld = long double;
struct Pt { ld x, y; };
ld cross(Pt a, Pt b) { return a.x*b.y - a.y*b.x; }
Pt sub(Pt a, Pt b) { return {a.x-b.x, a.y-b.y}; }
Pt add(Pt a, Pt b) { return {a.x+b.x, a.y+b.y}; }
Pt mul(Pt a, ld t) { return {a.x*t, a.y*t}; }
ld dot(Pt a, Pt b) { return a.x*b.x + a.y*b.y; }
bool inside(Pt p, Pt a, Pt b) {
  return cross(sub(b,a), sub(p,a)) >= 0; // clockwise
}
Pt intersect(Pt p1, Pt p2, Pt a, Pt b) {
  Pt v1 = sub(p2,p1), v2 = sub(b,a), v3 = sub(a,p1);
  ld t = cross(v2,v3) / cross(v1,v2);
  return add(p1, mul(v1, t));
}
vector<Pt> clip(vector<Pt> subj, vector<Pt> clip) {
  vector<Pt> out = subj;
  int m = clip.size();
  for (int i = 0; i < m; i++) {
      Pt a = clip[i], b = clip[(i+1)%m];
      vector<Pt> in = out; out.clear();
      int n = in.size();
      for (int j = 0; j < n; j++) {
          Pt cur = in[j], prv = in[(j+n-1)%n];
          bool curIn = inside(cur, a, b);
          bool prvIn = inside(prv, a, b);
          if (curIn) {
              if (!prvIn) out.push_back(intersect(prv, cur, a, b));
              out.push_back(cur);
          } else if (prvIn) {
              out.push_back(intersect(prv, cur, a, b));
          }
      }
  }
  return out;
}
int main() {
  int n; cin >> n;
  vector<Pt> subj(n);
  for (auto& p : subj) cin >> p.x >> p.y;
  int m; cin >> m;
  vector<Pt> clipPoly(m);
  for (auto& p : clipPoly) cin >> p.x >> p.y;
  auto res = clip(subj, clipPoly);
  cout << res.size() << "\n";
  for (auto& p : res) cout << p.x << " " << p.y << "\n";
}
stdin
4
0 0
10 0
10 10
0 10
4
5 5
15 5
15 15
5 15
결과
4
5 5
10 5
10 10
5 10

복잡도

항목
Sutherland-HodgmanO(N * M) (각 clip edge 마다 전체 순회)
Weiler-AthertonO(N + M + K) (K = 교차점 개수)
공간O(N + M)

N, M 은 각각 subject, clip polygon 의 꼭짓점 개수.

변형 / 활용

  • Union (합집합): A, B 의 outside 부분을 취합.
  • Intersection (교집합): Sutherland-Hodgman 직접 적용.
  • Difference (차집합): A - B 는 B 의 반대 방향 edge 로 clipping.
  • CAD/CAM: 솔리드 모델링의 CSG (Constructive Solid Geometry).
  • GIS: 지도 영역 중첩 분석.

함정

1. 수치 오차

부동소수점 교차점 계산에서 epsilon (1e-9) 처리 필요. inside 판정이 epsilon 범위에서 일관되어야 함.

2. Degenerate case

edge 위에 점이 정확히 놓인 경우 (collinear). inside/boundary 판정을 일관된 규칙으로.

3. Self-intersecting polygon

Sutherland-Hodgman 은 convex window 에만 동작. 일반 polygon 은 Weiler-Atherton 필요.

BOJ 연습 문제

번호제목정답률링크
BOJ 5212지구 온난화-kokoa-lab
BOJ 3392화성 지도-kokoa-lab
BOJ 2671잠수함 식별-kokoa-lab

참고

💬 댓글

사이트 검색 / 명령어

검색

스크롤 = 확대/축소 · 드래그 = 이동 · 0 = 원래 크기 · ESC = 닫기