Bài 63: Góc & Phép Quay¶
Tác giả: FPTOJ Team
Nội dung tham khảo từ: CP-Algorithms, VNOI Wiki
0. Tại sao phải học?¶
Bài toán mở đầu: Cho điểm \(P(1, 0)\). Quay \(P\) quanh gốc tọa độ \(90°\) ngược chiều kim đồng hồ được điểm nào? Bằng trực giác: \((0, 1)\). Nhưng quay \(P(3, 2)\) đi \(37°\) thì sao — không thể vẽ tay. Công thức quay cho đáp án ngay, và nó chỉ là tổ hợp tuyến tính của 2 vector cơ sở: trục \(x\) \((1,0)\) quay thành \((\cos\theta, \sin\theta)\), trục \(y\) \((0,1)\) quay thành \((-\sin\theta, \cos\theta)\). Mọi điểm \(P = x \cdot e_1 + y \cdot e_2\) sau quay vẫn là tổ hợp với cùng hệ số \(x, y\) — đó chính là ma trận quay ở §2.
1. Góc giữa hai vector¶
1.1 Dùng atan2¶
Hàm atan2(y, x) trả về góc (radian) từ trục \(x\) dương đến vector \((x, y)\), trong khoảng \((-\pi, \pi]\).
1.2 Dùng dot product¶
2. Phép quay điểm¶
2.1 Quay quanh gốc tọa độ¶
Quay điểm \((x, y)\) một góc \(\theta\) (ngược chiều kim đồng hồ, đơn vị radian):
Đọc công thức bằng lời: tọa độ mới \(x'\) = (hình chiếu của \(P\) lên trục \(x\) đã quay) \(-\) (hình chiếu lên trục \(y\) đã quay). Khi \(\theta = 90°\): \(\cos = 0, \sin = 1\) → \((x,y) \to (-y, x)\) — khớp trực giác (điểm \((1,0)\) thành \((0,1)\) ✓).
Minh họa trực quan (Phép quay điểm quanh gốc tọa độ):

2.2 Quay quanh điểm bất kỳ¶
Quay điểm \(P\) quanh tâm \(O\) góc \(\theta\):
3. Phép quay 90°¶
3.1 Quay 90° ngược chiều kim đồng hồ (CCW)¶
\((x, y) \to (-y, x)\)
3.2 Quay 90° theo chiều kim đồng hồ (CW)¶
\((x, y) \to (y, -x)\)
4. Ứng dụng: Điểm đối xứng qua trục¶
4.1 Đối xứng qua trục tung \(Oy\)¶
\((x, y) \to (-x, y)\)
4.2 Đối xứng qua trục hoành \(Ox\)¶
\((x, y) \to (x, -y)\)
4.3 Đối xứng qua đường thẳng bất kỳ¶
Xem Bài 61 - phần reflectPoint.
5. Kiểm tra điểm nằm trong góc¶
5.1 Bài toán¶
Cho 3 điểm \(O, A, B\). Kiểm tra điểm \(P\) có nằm trong góc \(\angle AOB\) không.
5.2 Ý tưởng¶
Sử dụng cross product để kiểm tra \(P\) nằm cùng phía \(A\) và \(B\) so với \(O\).
6. Xoay hình học¶
6.1 Xoay đa giác¶
Xoay toàn bộ đa giác quanh tâm \(O\) góc \(\theta\):
6.2 Ứng dụng: Bài toán minimum bounding rectangle¶
Xoay đa giác các góc khác nhau để tìm hình chữ nhật bao nhỏ nhất.
7. Lỗi thường gặp¶
- Nhầm chiều quay: công thức trên là CCW (ngược kim đồng hồ). Muốn quay CW (thuận kim đồng hồ) góc \(\theta\) thì truyền \(-\theta\).
M_PIkhông có trên MSVC: thêm#define _USE_MATH_DEFINEStrước#include <bits/stdc++.h>, hoặc tự định nghĩaconst double PI = acos(-1);.- So sánh
==với số thực: sau quay, tọa độ là số thực — kiểm tra bằng nhau phải dùngabs(a - b) < 1e-9, không dùng==. - Quên tịnh tiến khi quay quanh điểm bất kỳ:
rotate(P, theta)luôn quay quanh gốc tọa độ. Muốn quay quanh \(O\) phải dùngrotateAround(tịnh tiến → quay → tịnh tiến ngược). acosnhận giá trị ngoài \([-1, 1]\): do sai số làm tròn,dot/(|A||B|)có thể ra \(1.0000000002\) →acostrả NaN. Luôn clamp như code §1.2.
8. Bài tập luyện tập (FPTOJ)¶
| Bài | Nền tảng | Độ khó | Kiểu bài tập (Bản chất) |
|---|---|---|---|
rotate-point |
Quay điểm quanh gốc tọa độ | ⭐ | Phép quay |
rotate-angle |
Góc giữa hai vector | ⭐ | Góc vector |
rotate-ccw |
Xác định hướng quay | ⭐ | Cross product |
rotate-around |
Quay điểm quanh điểm bất kỳ | ⭐⭐ | Phép quay |
rotate-sort-angle |
Sắp xếp theo góc | ⭐⭐ | Sắp xếp góc cực |
rotate-clock-angle |
Góc quay đồng hồ | ⭐⭐ | Góc giữa hai vector |
rotate-polar |
Chuyển đổi tọa độ | ⭐ | Tọa độ cực |
rot-tri-rotate |
Diện tích tam giác sau quay | ⭐⭐⭐ | Phép quay + diện tích |
9. Bài tập tự luận¶
Bài 1: Quay điểm¶
Đề bài: Cho điểm \(P(x,y)\) và góc \(\theta\) (độ). Quay \(P\) quanh gốc tọa độ một góc \(\theta\) ngược chiều kim đồng hồ.
Input: 3 số thực \(x, y, \theta\) \((|x|,|y| \leq 10^4, 0 \leq \theta \leq 360)\)
Output: Tọa độ điểm sau khi quay, làm tròn 4 chữ số thập phân.
Ví dụ:
| Input | Output |
|---|---|
1 0 90 |
0.0000 1.0000 |
1 1 45 |
-0.0000 1.4142 |
Lời giải
\(x' = x\cos\theta - y\sin\theta\), \(y' = x\sin\theta + y\cos\theta\). Đổi \(\theta\) từ độ sang radian.
Bài 2: Góc giữa 2 vector¶
Đề bài: Cho 2 vector \(A(x_1,y_1)\) và \(B(x_2,y_2)\). Tính góc giữa chúng (độ).
Input: 4 số thực \(x_1, y_1, x_2, y_2\)
Output: Góc giữa 2 vector (độ), làm tròn 4 chữ số thập phân.
Ví dụ:
| Input | Output |
|---|---|
1 0 0 1 |
90.0000 |
1 0 1 1 |
45.0000 |
Lời giải
\(\theta = \arccos\left(\frac{A \cdot B}{|A| \cdot |B|}\right)\), đổi sang độ.
Bài 3: Điểm đối xứng¶
Đề bài: Cho điểm \(P(x,y)\) và đường thẳng \(Ax + By + C = 0\). Tìm điểm đối xứng của \(P\) qua đường thẳng.
Input: 5 số thực \(x, y, A, B, C\)
Output: Tọa độ điểm đối xứng, làm tròn 4 chữ số thập phân.
Ví dụ:
| Input | Output |
|---|---|
1 0 1 -1 0 |
0.0000 1.0000 |
0 0 1 0 -3 |
6.0000 0.0000 |
Lời giải
Chiếu \(P\) lên đường thẳng \(H\), rồi \(P' = 2H - P\).
Bài 4: Kiểm tra quay¶
Đề bài: Cho 3 điểm \(A, B, C\) theo thứ tự. Xác định \(C\) nằm bên trái, bên phải, hay thẳng hàng so với vector \(AB\).
Input: 6 số thực \(x_A, y_A, x_B, y_B, x_C, y_C\)
Output: LEFT, RIGHT, hoặc COLLINEAR.
Ví dụ:
| Input | Output |
|---|---|
0 0 1 0 0 1 |
LEFT |
0 0 1 0 0 -1 |
RIGHT |
0 0 1 0 2 0 |
COLLINEAR |
Lời giải
Tính cross product \((B-A) \times (C-A)\). Dương = trái, âm = phải, 0 = thẳng hàng.