계산 기하학
- 컴퓨터 알고리즘의 한 분야
- 기하 물체를 대상으로 하는 문제를 조합론 및 알고리즘적인 해법으로 해결함
- 컴퓨터 그래픽스, 로보틱스, VLSI 디자인, CAD 등에서 응용됨
기본 기하 연산
벡터의 외적
- 두 벡터 p = (px, py)와 q = (qx, qy)에 대해서, p X q = pxqy-pyqx = -q x p
- 외적 p x q는 점 (0,0), p, q, p + q를 꼭지점으로 하는 평행 사변형의 부호화된 면적을 나타냄
- 성질
- p x q > 0: q가 p로부터 반시계 방향으로 180도 이내에 존재
- p x q < 0: q가 p로부터 시계 방향으로 180도 이내에 존재
- p x q = 0: q는 p와 일직선 상에 존재
CCW 함수
- 벡터의 외적을 이용하여 정의
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 원점에서 벡터 q가 벡터 p에 반시계 방향이면 양수, 시계방향이면 음수 반환
// 평행이면 0 반환
typedef struct point { int x; int y; } Point;
// 원점에서 벡터 q가 벡터 p에 반시계 방향이면 양수, 시계방향이면 음수 반환
// 평행이면 0 반환
int ccw(Point p, Point q) {
return p.x * q.y - p.y * q.x;
}
//점 r을 기준으로 벡터 rq가 벡터 rp에 반시계 방향이면 양수, 시계방향이면 음수 반환
// 평행이면 0 반환
int ccw(Point r, Point p, Point q) {
return ccw(p - r, q - r);
}
CCW 활용
세 점 a, b, c의 회전방향
- 위 그림에서 leftTrun은 ccw(a,b,c) > 0, righturn은 ccw(a,b,c) < 0
1
2
3
4
5
6
7
8
9
10
11
12
// 세 점 a, b, c의 회전 방향이 좌회전인지 검사
bool leftTurn(Point a, Point b, Point c) {
return ccw(a, b, c) > 0;
}
// 세 점 a, b, c의 회전 방향이 우회전인지 검사
bool rightTurn(Point a, Point b, Point c) {
return ccw(a, b, c) < 0;
}
// 세 점 a, b, c의 회전 방향이 일직선인지 검사
bool collinear(Point a, Point b, Point c) {
return ccw(a, b, c) == 0;
}
- 선분 교차 검사
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 세 점 a, b, c의 회전 방향 검사에서 좌회전이면 1,
// 우회전이면 -1, 일직선이면 0 반환
int direction(Point a, Point b, Point c) {
if (ccw(a, b, c) < 0) return -1;
if (ccw(a, b, c) > 0) return 1;
return 0;
}
// 선분의 끝점이 교차점이 되는 경우를 제외
bool intersectProp(Point a, Point b, Point c, Point d) {
return direction(a, b, c) * direction(a, b, d) < 0 &&
direction(c, d, a) * direction(c, d, b) < 0;
}
// 선분의 끝점이 교차점이 되는 경우 허용
bool intersect(Point a, Point b, Point c, Point d) {
return direction(a, b, c) * direction(a, b, d) <= 0 &&
direction(c, d, a) * direction(c, d, b) <= 0;
}
- 만약, ccw(a, b, c)*ccw(a, b, d) == 0 (혹은 cda, cdb 연산이 0)이면 a, b, c 혹은 a, b, d가 일직선 상에 있는 것으로 이때는 a, b와 c, d의 상대적 위치를 비교해야 한다.
- 아래코드를 응용하여 검사
1 2 3 4 5 6 7 8 9 10 11
bool between(Point a, Point b, Point c) { if (!collinear(a, b, c)) return false; if (a.x != b.x) { // 선분 ab가 수직선이 아니면 return a.x <= c.x && c.x <= b.x || b.x <= c.x && c.x <= a.x; } else { return a.y <= c.y && c.y <= b.y || b.y <= c.y && c.y <= a.y; } }