Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> C++

ทดสอบการחתךของเส้นสองเส้นด้วย Above-Below Primitive ใน C++

ใช้การทดสอบ 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