四点构成的两条直线相交判断程序优化及问题排查请求
判断两条直线(线段)是否存在交点的简便实现及问题修复
给定四个点坐标,将前两点连成一条线段、后两点连成另一条线段,判断二者是否存在交点。针对你原程序的问题,这里给出更鲁棒的实现方案,并分析原代码的问题:
原程序的核心问题
- 错误处理垂直x轴的线段:原代码遇到
x1 == x2或x3 == x4直接exit(0),但垂直x轴的线段是合法的;且直接用浮点数==判断相等存在精度误差,应该用极小阈值(如fabs(x1-x2) < 1e-8)判断。 - 未处理线段重合/共线情况:原代码仅通过斜率和截距计算交点,完全忽略了两条线段共线且重叠的场景。
- 区间判断逻辑漏洞:原代码仅验证交点的x坐标是否在线段区间内,未同步验证y坐标,存在误判可能。
更简便鲁棒的实现:向量叉积法
向量叉积可以避免除法运算,无需处理斜率不存在的情况,还能精准判断线段的位置关系(相交、平行、共线重合)。
原理简述
对于两点构成的向量vec1 = (x2-x1, y2-y1)和vec2 = (x3-x1, y3-y1),叉积计算规则为:
double cross(double x1, double y1, double x2, double y2, double x3, double y3) { return (x2 - x1) * (y3 - y1) - (x3 - x1) * (y2 - y1); }
- 叉积绝对值小于极小阈值:两点与基准点共线;
- 叉积正负:判断点在直线的哪一侧。
对于线段L1(A1,A2)和L2(A3,A4):
- 计算四个叉积:
c1 = cross(A1,A2,A3)、c2 = cross(A1,A2,A4)、c3 = cross(A3,A4,A1)、c4 = cross(A3,A4,A2); - 若
c1和c2异号,且c3和c4异号,则两线段相交; - 若存在叉积为0,则判断对应点是否在线段上(覆盖共线重合的情况)。
完整C++代码
#include <iostream> #include <cmath> #include <algorithm> using namespace std; const double EPS = 1e-8; // 处理浮点数精度的极小阈值 // 计算向量叉积:(A2-A1) × (P-A1) double cross(double x1, double y1, double x2, double y2, double x3, double y3) { return (x2 - x1) * (y3 - y1) - (x3 - x1) * (y2 - y1); } // 判断点(x,y)是否在线段(x1,y1)-(x2,y2)上 bool isPointOnSegment(double x, double y, double x1, double y1, double x2, double y2) { // 先判断是否共线 if (fabs(cross(x1, y1, x2, y2, x, y)) > EPS) { return false; } // 再判断坐标是否在线段的区间内 return (min(x1, x2) - EPS <= x && x <= max(x1, x2) + EPS) && (min(y1, y2) - EPS <= y && y <= max(y1, y2) + EPS); } // 判断两条线段是否有交点 bool hasIntersection(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) { double c1 = cross(x1, y1, x2, y2, x3, y3); double c2 = cross(x1, y1, x2, y2, x4, y4); double c3 = cross(x3, y3, x4, y4, x1, y1); double c4 = cross(x3, y3, x4, y4, x2, y2); // 情况1:两线段互相跨立,直接相交 if (c1 * c2 < -EPS && c3 * c4 < -EPS) { return true; } // 情况2:其中一个线段的端点在另一个线段上 if (isPointOnSegment(x3, y3, x1, y1, x2, y2)) return true; if (isPointOnSegment(x4, y4, x1, y1, x2, y2)) return true; if (isPointOnSegment(x1, y1, x3, y3, x4, y4)) return true; if (isPointOnSegment(x2, y2, x3, y3, x4, y4)) return true; // 其他情况:平行或无交点 return false; } int main() { double x1, y1, x2, y2, x3, y3, x4, y4; cin >> x1 >> y1 >> x2 >> y2 >> x3 >> y3 >> x4 >> y4; cout << (hasIntersection(x1, y1, x2, y2, x3, y3, x4, y4) ? "1" : "0") << endl; return 0; }
代码优势
- 避免除法运算,彻底解决斜率不存在的问题;
- 用
EPS处理浮点数精度误差,避免因精度问题导致的误判; - 覆盖所有场景:相交、共线重合、端点在另一条线段上、平行无交点;
- 逻辑清晰,易于维护和扩展。
内容的提问来源于stack exchange,提问作者Arash Alipoor
相关产品推荐
相关产品推荐

