กำหนดวงกลมด้วย 3 จุดที่ไม่一直線 (non-collinear) แล้วตรวจสอบว่าจุดที่ 4 อยู่ภายใน นอก หรือบนวงกลม
หลักการทางเรขาคณิต
สมการวงกลมทั่วไป: (x - h)² + (y - k)² = r²
โดยจุดศูนย์กลาง (h, k) และรัศมี r สามารถคำนวณจาก 3 จุดได้
สำหรับจุดทดสอบ (x, y) คำนวณค่า:
s = (x - h)² + (y - k)² - r²
s < 0→ จุดอยู่ ภายใน วงกลมs = 0→ จุดอยู่ บน วงกลมs > 0→ จุดอยู่ นอก วงกลม
การหาจุดศูนย์กลางจาก 3 จุด
กำหนด 3 จุด: A(x₁,y₁), B(x₂,y₂), C(x₃,y₃)
จุดศูนย์กลางเป็นจุดตัดของเส้นแบ่งมุมตั้งฉากของ AB และ BC
ตัวอย่างโค้ด (ปรับปรุงจากต้นฉบับ)
#include <iostream>
#include <cmath>
#include <limits>
using namespace std;
struct Point {
double x, y;
};
struct Circle {
Point center;
double radius;
bool valid;
};
// คำนวณวงกลมจาก 3 จุด
Circle circleFrom3Points(const Point& A, const Point& B, const Point& C) {
Circle result = {{0, 0}, 0, false};
// ตรวจสอบ collinearity
double d = 2 * (A.x * (B.y - C.y) + B.x * (C.y - A.y) + C.x * (A.y - B.y));
if (fabs(d) < 1e-10) return result; // จุดอยู่บนเส้นตรงเดียวกัน
double ux = ((A.x*A.x + A.y*A.y) * (B.y - C.y) +
(B.x*B.x + B.y*B.y) * (C.y - A.y) +
(C.x*C.x + C.y*C.y) * (A.y - B.y)) / d;
double uy = ((A.x*A.x + A.y*A.y) * (C.x - B.x) +
(B.x*B.x + B.y*B.y) * (A.x - C.x) +
(C.x*C.x + C.y*C.y) * (B.x - A.x)) / d;
result.center = {ux, uy};
result.radius = sqrt((ux - A.x)*(ux - A.x) + (uy - A.y)*(uy - A.y));
result.valid = true;
return result;
}
// ตรวจสอบตำแหน่งจุดเทียบวงกลม
int pointInCircle(const Point& p, const Circle& c) {
if (!c.valid) return -2; // error
double dx = p.x - c.center.x;
double dy = p.y - c.center.y;
double distSq = dx*dx + dy*dy;
double rSq = c.radius * c.radius;
double diff = distSq - rSq;
const double EPS = 1e-10;
if (fabs(diff) < EPS) return 0; // บนวงกลม
return (diff < 0) ? -1 : 1; // -1: ใน, 1: นอก
}
int main() {
// จุดกำหนดวงกลม
Point A = {0, 0}, B = {4, 0}, C = {2, 3};
Circle circle = circleFrom3Points(A, B, C);
if (!circle.valid) {
cout << "3 จุดอยู่บนเส้นตรงเดียวกัน ไม่สามารถสร้างวงกลมได้" << endl;
return 1;
}
cout << "วงกลมจากจุด A(" << A.x << "," << A.y << ") "
<< "B(" << B.x << "," << B.y << ") "
<< "C(" << C.x << "," << C.y << ")" << endl;
cout << "ศูนย์กลาง: (" << circle.center.x << ", " << circle.center.y << ")" << endl;
cout << "รัศมี: " << circle.radius << endl;
// ทดสอบจุดต่างๆ
Point testPoints[] = {
{2, 1}, // ภายใน
{2, 3}, // บนวงกลม (จุด C)
{10, 10}, // นอก
{0, 0} // บนวงกลม (จุด A)
};
cout << "\nการทดสอบ:" << endl;
for (const auto& p : testPoints) {
int pos = pointInCircle(p, circle);
string posStr = (pos == -1) ? "ภายใน" : (pos == 0) ? "บนวงกลม" : "นอก";
cout << "จุด (" << p.x << ", " << p.y << ") -> " << posStr << endl;
}
// รับจากผู้ใช้
Point userPt;
cout << "\nป้อนจุดทดสอบ (x y): ";
if (cin >> userPt.x >> userPt.y) {
int pos = pointInCircle(userPt, circle);
string posStr = (pos == -1) ? "ภายใน" : (pos == 0) ? "บนวงกลม" : "นอก";
cout << "จุด (" << userPt.x << ", " << userPt.y << ") -> " << posStr << endl;
}
return 0;
}
ผลลัพธ์ตัวอย่าง
วงกลมจากจุด A(0,0) B(4,0) C(2,3) ศูนย์กลาง: (2, 1.33333) รัศมี: 2.4037 การทดสอบ: จุด (2, 1) -> ภายใน จุด (2, 3) -> บนวงกลม จุด (10, 10) -> นอก จุด (0, 0) -> บนวงกลม
ข้อควรระวัง
- ความแม่นยำ floating-point: ใช้ epsilon ในการเปรียบเทียบ
- 3 จุดต้องไม่一直線 (collinear) มิฉะนั้นไม่มีวงกลมที่ผ่านทั้ง 3 จุด
- สำหรับ integer coordinates ใหญ่ ควรใช้ exact arithmetic หรือ arbitrary precision