ใช้การทดสอบ Above-Below (หรือ Orientation Test) เพื่อตรวจสอบว่าเส้นสองเส้น intersect กันหรือไม่ โดยดูจากตำแหน่งปลายทางของเส้นหนึ่งเทียบกับอีกเส้นหนึ่ง
หลักการ
เส้นสองเส้น L1 (จุด p1, p2) และ L2 (จุด q1, q2) จะ intersect กันก็ต่อเมื่อ:
- ปลายทางของ L2 อยู่คนละด้านของ L1 (หนึ่ง above, หนึ่ง below)
- AND ปลายทางของ L1 อยู่คนละด้านของ L2
สูตรสำหรับเส้นผ่านจุด (x1,y1) และ (x2,y2):
F(x, y) = (y2 - y1) * x + (x1 - x2) * y + (x2*y1 - x1*y2)
F(x, y) > 0→ ด้านหนึ่ง (above/left)F(x, y) < 0→ อีกด้าน (below/right)F(x, y) = 0→ อยู่บนเส้น
ตัวอย่างโค้ด
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
struct Point {
int x, y;
};
// คำนวณค่า F(x,y) สำหรับเส้นผ่าน p1, p2
long long lineTest(const Point& p1, const Point& p2, const Point& p) {
return 1LL * (p2.y - p1.y) * p.x +
1LL * (p1.x - p2.x) * p.y +
1LL * (p2.x * p1.y - p1.x * p2.y);
}
// ตรวจสอบการ intersect (รวมกรณี collinear overlap)
bool doLinesIntersect(const Point& p1, const Point& p2,
const Point& q1, const Point& q2) {
long long d1 = lineTest(p1, p2, q1);
long long d2 = lineTest(p1, p2, q2);
long long d3 = lineTest(q1, q2, p1);
long long d4 = lineTest(q1, q2, p2);
// General case: ตัดกันที่จุดเดียว (ไม่ collinear)
if (((d1 > 0 && d2 < 0) || (d1 < 0 && d2 > 0)) &&
((d3 > 0 && d4 < 0) || (d3 < 0 && d4 > 0))) {
return true;
}
// Special cases: collinear และ overlap
// (ต้องเพิ่มตรวจสอบ projection overlap)
if (d1 == 0 && onSegment(p1, p2, q1)) return true;
if (d2 == 0 && onSegment(p1, p2, q2)) return true;
if (d3 == 0 && onSegment(q1, q2, p1)) return true;
if (d4 == 0 && onSegment(q1, q2, p2)) return true;
return false;
}
// ตรวจสอบจุด p อยู่บน line segment p1-p2
bool onSegment(const Point& p1, const Point& p2, const Point& p) {
return (p.x >= min(p1.x, p2.x) && p.x <= max(p1.x, p2.x) &&
p.y >= min(p1.y, p2.y) && p.y <= max(p1.y, p2.y));
}
// แสดงสมการเส้น
void printLineEquation(const Point& p1, const Point& p2, const string& label) {
long long A = p2.y - p1.y;
long long B = p1.x - p2.x;
long long C = p2.x * p1.y - p1.x * p2.y;
cout << label << ": (" << A << ")x + (" << B << ")y + (" << C << ") = 0" << endl;
}
int main() {
srand(time(0));
// สร้างเส้นสุ่ม
Point p1 = {rand() % 20, rand() % 20};
Point p2 = {rand() % 20, rand() % 20};
Point q1 = {rand() % 20, rand() % 20};
Point q2 = {rand() % 20, rand() % 20};
printLineEquation(p1, p2, "เส้นที่ 1");
printLineEquation(q1, q2, "เส้นที่ 2");
bool intersect = doLinesIntersect(p1, p2, q1, q2);
cout << (intersect ? "เส้นทั้งสอง intersect กัน" : "เส้นทั้งสองไม่ intersect") << endl;
// ทดสอบกรณีเฉพาะ
cout << "\n--- ทดสอบกรณีเฉพาะ ---" << endl;
// ตัดกัน
Point a1 = {0, 0}, a2 = {10, 10};
Point b1 = {0, 10}, b2 = {10, 0};
printLineEquation(a1, a2, "เส้น A");
printLineEquation(b1, b2, "เส้น B");
cout << "ตัดกัน: " << (doLinesIntersect(a1, a2, b1, b2) ? "Yes" : "No") << endl;
// 平行 ไม่ตัด
Point c1 = {0, 0}, c2 = {10, 0};
Point d1 = {0, 5}, d2 = {10, 5};
printLineEquation(c1, c2, "เส้น C");
printLineEquation(d1, d2, "เส้น D");
cout << "ตัดกัน: " << (doLinesIntersect(c1, c2, d1, d2) ? "Yes" : "No") << endl;
return 0;
}
ผลลัพธ์ตัวอย่าง
เส้นที่ 1: (5)x + (-3)y + (2) = 0 เส้นที่ 2: (-4)x + (6)y + (-10) = 0 เส้นทั้งสอง intersect กัน --- ทดสอบกรณีเฉพาะ --- เส้น A: (10)x + (-10)y + (0) = 0 เส้น B: (-10)x + (-10)y + (100) = 0 ตัดกัน: Yes เส้น C: (0)x + (10)y + (0) = 0 เส้น D: (0)x + (10)y + (-50) = 0 ตัดกัน: No
ขยายเป็น Line Segment Intersection
โค้ดด้านบนรองรับ line segment แล้ว (ด้วยฟังก์ชัน onSegment) สำหรับ infinite lines ให้ลบส่วน special cases ออก
ประยุกต์ใช้
- Collision detection ในเกม
- Computer graphics: clipping, rendering
- GIS: road network analysis
- CAD: geometric constraint solving