这是一篇解题记录,不确保内容完全正确。
规范相交:两线段相交,不包含端点。
不规范相交:两线段相交,包含一个端点。
其他的看图片就懂了。
一、这是线段是否相交的六种情况,下面开始分析:
对于计算几何问题,一般考虑用向量解决
首先对线段进行参数化(请忽略潦草的字迹):
设出方程求解线性方程组可以得到参数t、u
对于参数的含义如下:
t:t取0,表示线段AB的起点A ,t取1,表示线段AB的终点B
u:u取0,表示线段CD的起点C,u取1,表示线段CD的终点D
二、解决线段不平行的部分(规范相交、不规范相交、不相交)
1、首先计算AB和CD的叉乘判断是否平行
2、再计算参数t、u
- 若t、u都在[0,1]内,说明两线段相交
- 若t、u都在(0,1)内,说明两线段规范相交
- 若t、u不在[0,1]内,说明两线段不相交
对于参数t、u:
t和u都在区间[0,1]内,说明两线段相交。
t和u都在区间(0,1)内,说明规范相交,交点在两线段上(不包含端点)。
t不在区间[0,1]内或u不在区间[0,1]内,说明两线段不相交。
#include <bits/stdc++.h>
using namespace std;
const long double ESP = 1e-10;
struct point {long double x,y;
};int main()
{ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);point A,B,C,D;//A B C D -int t;cin >> t;while(t--) {cin >> A.x >> A.y;//Acin >> B.x >> B.y;//Bcin >> C.x >> C.y;//Ccin >> D.x >> D.y;//D//AB和CD的叉积long double cross = (B.x - A.x) * (D.y - C.y) - (B.y - A.y) *(D.x - C.x); if(abs(cross) < ESP) {//如果两线段平行}else {// 如果两条线段不平行,计算它们的交点参数//参数 t,表示交点在线段 AB 上的位置//参数 u,表示交点在线段 CD 上的位置long double t = ((C.x - A.x) * (D.y - C.y) - (C.y - A.y) * (D.x - C.x)) / cross;long double u = ((C.x - A.x) * (B.y - A.y) - (C.y - A.y) * (B.x - A.x)) / cross;// 如果 t 和 u 都在 [0, 1] 范围内,说明两条线段相交if(0 <= t && t <= 1 && 0 <= u && u <= 1) {if(0 < t && t < 1 && 0 < u && u < 1) { // 如果 t 和 u 都在 (0, 1) 范围内,说明是规范相交cout << 2 << endl;}else {cout << 1 << endl;}}else {// 如果 t 或 u 不在 [0, 1] 范围内,说明两条线段不相交cout << 0 << endl;}}}return 0;
}
三、解决线段平行的部分(平行不共线、共线不重叠、共线重叠)
1、首先计算AB和CD的叉乘判断是否平行
2、再判断点C和点D是否在直线AB上(共线)
3、解出点C和点D在线段AB上的参数值
- 若两线段共线,重叠部分为[t1,t2]与[0,1]的交集
- 若两线段不共线,不相交
#include <bits/stdc++.h>
using namespace std;
const long double ESP = 1e-10;
struct point {long double x,y;
};int main()
{ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);point A,B,C,D;//A B C D -int t;cin >> t;while(t--) {cin >> A.x >> A.y;//Acin >> B.x >> B.y;//Bcin >> C.x >> C.y;//Ccin >> D.x >> D.y;//D//AB和CD的叉积long double cross = (B.x - A.x) * (D.y - C.y) - (B.y - A.y) *(D.x - C.x); if(abs(cross) < ESP) {//两线段平行//AC和AB是否共线double cross1 = (C.x - A.x) * (B.y - A.y) - (C.y - A.y) * (B.x - A.x);//AD和AB是否共线--->点D是否在直线ABdouble cross2 = (D.x - A.x) * (B.y - A.y) - (D.y - A.y) * (B.x - A.x);if(abs(cross1) < ESP && abs(cross2) < ESP) {// 如果点 C 和点 D 都在线段 AB 所在的直线上//点 C 和点 D 在线段 AB 上的参数值//通过解参数方程可得double t1 = (C.x - A.x) / (B.x - A.x);double t2 = (D.x - A.x) / (B.x - A.x);//如果两线段共线,重叠部分为[t1,t2]与[0,1]的交集if(0 <= max(t1,t2) && min(t1,t2) <= 1) {cout << 1 << endl;// 如果两条线段在参数区间 [0, 1] 内有重叠部分}else {cout << 0 << endl;}}else {cout << 0 << endl;// 如果两条线段平行但不共线,输出 0,表示不相交}}return 0;
}
完整代码
#include <bits/stdc++.h>
using namespace std;
const long double ESP = 1e-10;
struct point {long double x,y;
};int main()
{ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);point A,B,C,D;//A B C D -int t;cin >> t;while(t--) {cin >> A.x >> A.y;//Acin >> B.x >> B.y;//Bcin >> C.x >> C.y;//Ccin >> D.x >> D.y;//D//AB和CD是否平行long double cross = (B.x - A.x) * (D.y - C.y) - (B.y - A.y) *(D.x - C.x); if(abs(cross) < ESP) {//AC和AB是否共线double cross1 = (C.x - A.x) * (B.y - A.y) - (C.y - A.y) * (B.x - A.x);//AD和AB是否共线--->点D是否在直线ABdouble cross2 = (D.x - A.x) * (B.y - A.y) - (D.y - A.y) * (B.x - A.x);if(abs(cross1) < ESP && abs(cross2) < ESP) {// 如果点 C 和点 D 都在线段 AB 所在的直线上//点 C 和点 D 在线段 AB 上的参数值double t1 = (C.x - A.x) / (B.x - A.x);double t2 = (D.x - A.x) / (B.x - A.x);//如果两线段共线,重叠部分为[t1,t2]与[0,1]的交集if(0 <= max(t1,t2) && min(t1,t2) <= 1) {cout << 1 << endl;// 如果两条线段在参数区间 [0, 1] 内有重叠部分}else {cout << 0 << endl;}}else {cout << 0 << endl;// 如果两条线段平行但不共线,输出 0,表示不相交}}else {// 如果两条线段不平行,计算它们的交点参数//参数 t,表示交点在线段 AB 上的位置//参数 u,表示交点在线段 CD 上的位置long double t = ((C.x - A.x) * (D.y - C.y) - (C.y - A.y) * (D.x - C.x)) / cross;long double u = ((C.x - A.x) * (B.y - A.y) - (C.y - A.y) * (B.x - A.x)) / cross;// 如果 t 和 u 都在 [0, 1] 范围内,说明两条线段相交if(0 <= t && t <= 1 && 0 <= u && u <= 1) {if(0 < t && t < 1 && 0 < u && u < 1) { // 如果 t 和 u 都在 (0, 1) 范围内,说明是规范相交cout << 2 << endl;}else {cout << 1 << endl;}}else {// 如果 t 或 u 不在 [0, 1] 范围内,说明两条线段不相交cout << 0 << endl;}}}return 0;
}
参考例题:线段相交判断https://www.lanqiao.cn/problems/1287/learning
原创【转载请注明】