Angle Sort
Β - Last update: 2024-03-05

Angle Sort

2D μ’Œν‘œκ³„μ—μ„œ μ™ΈνŒμ› 문제λ₯Ό μƒκ°ν•΄λ³΄μž. 정점 P1P_1, P2P_2, ..., PNP_N을 μž„μ˜μ˜ μˆœμ„œλ‘œ μ „λΆ€ μˆœνšŒν•˜κ³  λ‹€μ‹œ μΆœλ°œν•œ μ •μ μœΌλ‘œ λŒμ•„μ˜¨λ‹€κ³  ν•  λ•Œ, ν•΄λ‹Ή 경둜의 νœ΄λ¦¬μŠ€ν‹±μ μΈ μ΅œλ‹¨κ±°λ¦¬λŠ” μ–΄λ–»κ²Œ 될 것인가?

νœ΄λ¦¬μŠ€ν‹±μ μœΌλ‘œλŠ” μ΄λ ‡κ²Œ 생각할 수 μžˆλ‹€. λͺ¨λ“  μ’Œν‘œμ˜ 평균을 λ‚΄μ„œ κ°€μƒμ˜ 점 P0P_0κ°€ μžˆλ‹€κ³  ν•΄λ³΄μž. 그러면 μ£Όλ³€μ˜ 점듀은 이 κ°€μƒμ˜ 점을 λ‘˜λŸ¬μ‹Ό μ›μ˜ ν˜•νƒœλ₯Ό κ°€μ§€κ²Œ 된 κ²ƒμœΌλ‘œ 생각할 수 μžˆλ‹€. 그러면 이 μ’Œν‘œλ“€μ„ 원을 그리듯 μˆœνšŒν•˜λŠ” 방법이 μ΅œλ‹¨κ±°λ¦¬λŠ” μ•„λ‹ˆλ”λΌλ„ μ–΄λŠ 정도 νœ΄λ¦¬μŠ€ν‹±μ  정닡에 μœ νš¨ν•˜λ‹€κ³  μΆ”μΈ‘ν•΄λ³Ό 수 μžˆλ‹€.

이λ₯Ό ꡬ체적으둜 κ΅¬ν˜„ν•˜κΈ° μœ„ν•΄μ„œλŠ” 각도 정렬이 ν•„μš”ν•˜λ‹€. 평균점 P0P_0 λΆ€ν„°μ˜ 각 점의 xx, yy μ’Œν‘œμ˜ 거리 차이λ₯Ό dxdx, dydy라 ν•˜μž. 그러면, μž„μ˜μ˜ 점과 xx좕이 μ΄λ£¨λŠ” 각도λ₯Ό ΞΈ\theta라 ν• λ•Œ, sin⁑\sinν•¨μˆ˜μ˜ μ •μ˜μ— μ˜ν•΄, sin⁑2ΞΈ\sin^2 \thetaλŠ” μ•„λž˜μ™€ 같이 ꡬ할 수 μžˆλ‹€.

  • sin⁑2ΞΈ=dy2dr2=dy2(dx2+dy2)\displaystyle \sin^2 \theta = \frac {dy^2} {dr^2} = \frac {dy^2} {(dx^2 + dy^2)}

λ˜ν•œ 이 ν•¨μˆ˜κ°’μ˜ λ²”μœ„λŠ” sin⁑\sinν•¨μˆ˜ μ •μ˜μ— 따라 μ•„λž˜ λ²”μœ„λ‘œ bound λœλ‹€.

  • 0≀sin⁑2θ≀10 \leq \sin^2 \theta \leq 1

이 μ„±μ§ˆμ„ ν™œμš©ν•˜λ©΄, xμΆ•μœΌλ‘œλΆ€ν„° μ‹œκ³„ λ°˜λŒ€λ°©ν–₯으둜 λŒμ•„κ°€λŠ” μˆœμ„œλ‘œ μ’Œν‘œλ₯Ό μ •λ ¬λ˜κ²Œ ν•˜λ €λ©΄, μ•„λž˜μ²˜λŸΌ λΆ„κΈ°μ‹œν‚¬ 수 μžˆλ‹€.

  • 1사뢄면: dx>0dx > 0, dy>0dy > 0
    • sin⁑2ΞΈ\sin^2 \theta μ‚¬μš©
  • 2사뢄면: dx<0dx < 0, dy>0dy > 0
    • 2βˆ’sin⁑2ΞΈ2 - \sin^2 \theta μ‚¬μš©
  • 3사뢄면: dx<0dx < 0, dy<0dy < 0
    • 2+sin⁑2ΞΈ2 + \sin^2 \theta μ‚¬μš©
  • 4사뢄면: dx>0dx > 0, dy<0dy < 0
    • 4βˆ’sin⁑2ΞΈ4 - \sin^2 \theta μ‚¬μš©

μ΄λŠ” sin⁑\sin ν•¨μˆ˜μ˜ κ°œν˜•κ³Ό, κ·Έ μ΅œλŒ€ / μ΅œμ†Œκ°’μ„ 생각해보면 λͺ…λ°±ν•˜λ‹€. 좕에 μžˆλŠ” μ’Œν‘œλŠ” κ·Έ μ–΄λ–€ μͺ½μ„ 선택해도 값이 κ°™λ‹€.

μ΄λ‘œμ„œ μš°λ¦¬λŠ”, κ·Έ μ–΄λ–€ math libraryλ₯Ό 쓰지 μ•Šκ³ λ„, κ°λ„λ‘œ μ’Œν‘œλ“€μ„ μ •λ ¬ν–ˆλ‹€. μ˜ˆμ‹œ λ™μž‘μ½”λ“œλŠ” μ•„λž˜μ™€ 같이 κ°„λ‹¨νžˆ μž‘μ„±ν•΄λ³΄μ•˜λ‹€.

struct Point {
int x, y;
};
double getKey(Point& a) {
int ret = 0;
int x = a.x, y = a.y;
if (x == 0 && y == 0) return 0;
double sin2 = 1.0 * y * y / (x * x + y * y);
if (x >= 0 && y > 0) {
return sin2;
}
else if (x < 0 && y >= 0) {
return 2 - sin2;
}
else if (x <= 0 && y < 0) {
return 2 + sin2;
}
else {
return 4 - sin2;
}
return ret;
}
void test() {
vector<Point> v;
v.push_back({ 3, 1 });
v.push_back({ 1, 2 });
v.push_back({ 0, 4 });
v.push_back({ -1, 3 });
v.push_back({ -5, 2 });
v.push_back({ -6, 0 });
v.push_back({ -1, -1 });
v.push_back({ 0, -3 });
v.push_back({ 2, -3 });
v.push_back({ 5, -1 });
v.push_back({ 1, 0 });
random_shuffle(v.begin(), v.end()); // 랜덀으둜 μ„žμ–΄μ„œ μœ„ μˆœμ„œλ‘œ λ³΅κ΅¬λ˜λŠ”μ§€ 보자
sort(v.begin(), v.end(), [&](Point& a, Point& b) {
return getKey(a) < getKey(b);
});
for (auto& p : v) {
printf("%d, %d\n", p.x, p.y);
}
}

vector에 λ„£κ³  μžˆλŠ” μˆœμ„œλŒ€λ‘œ 좜λ ₯이 λ‚˜μ˜€λ©΄ μ •μƒμ μœΌλ‘œ μ •λ ¬λœ 것이닀. λ§Œμ•½ 각도와 슀칼라의 크기가 적절히 λ°°λΆ„λ˜λ©΄μ„œ μ •λ ¬λ˜κΈ°λ₯Ό μ›ν•œλ‹€λ©΄, κ·Έ λ˜ν•œ key값을 μ‘°μ ˆν•˜λ©΄ κ°€λŠ₯ν•˜λ‹€.