判断两线段是否相交(快速排斥和跨立)

2023-10-11 19:50

本文主要是介绍判断两线段是否相交(快速排斥和跨立),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

背景知识:

判断两线段是否相交:  

我们分两步确定两条线段是否相交:  

(1)快速排斥试验    

    设以线段 P1P2 为对角线的矩形为R, 

    设以线段 Q1Q2 为对角线的矩形为T,

    如果R和T不相交,显然两线段不会相交。  

(2)跨立试验

  如果两线段相交,则两线段必然相互跨立对方。若P1P2跨立Q1Q2 ,则矢量 ( P1 - Q1 ) 和( P2 - Q1 )位于矢量( Q2 - Q1 ) 的两侧,即( P1 - Q1 ) × ( Q2 - Q1 ) * ( P2 - Q1 ) × ( Q2 - Q1 ) < 0。上式可改写成( P1 - Q1 ) × ( Q2 - Q1 ) * ( Q2 - Q1 ) × ( P2 - Q1 ) > 0。当 ( P1 - Q1 ) × ( Q2 - Q1 ) = 0 时,说明 ( P1 - Q1 ) 和 ( Q2 - Q1 )共线,但是因为已经通过快速排斥试验,所以 P1 一定在线段 Q1Q2上;同理,( Q2 - Q1 ) ×(P2 - Q1 ) = 0 说明 P2 一定在线段 Q1Q2上。所以判断P1P2跨立Q1Q2的依据是:( P1 - Q1 ) × ( Q2 - Q1 ) * ( Q2 - Q1 ) × ( P2 - Q1 ) >= 0。同理判断Q1Q2跨立P1P2的依据是:( Q1 - P1 ) × ( P2 - P1 ) * ( P2 - P1 ) × ( Q2 - P1 ) >= 0。具体情况如下图所示:

程序模版:

#include"stdio.h"
#include"string.h"
#include"math.h"
#include"stdlib.h"
#define M 101
#define inf 999999999
#define eps 1e-10
typedef struct node
{double x,y;
}P;
typedef struct line
{P s;P e;
}Line;
Line L[M];
double max(double x,double y)
{return x>y?x:y;
}
double min(double x,double y)
{return x<y?x:y;
}
int paichi(line a,line b)//快速排斥,若通过快速排斥进行跨立实验,否则无交点;
{if(max(a.e.x,a.s.x)>=min(b.s.x,b.e.x)&&max(b.s.x,b.e.x)>=min(a.s.x,a.e.x)&&max(a.s.y,a.e.y)>=min(b.s.y,b.e.y)&&max(b.s.y,b.e.y)>=min(a.s.y,a.e.y))return 1;elsereturn 0;
}
double cross(node a,node b,node c)//叉积
{double x1=b.x-a.x;double y1=b.y-a.y;double x2=c.x-a.x;double y2=c.y-a.y;return x1*y2-x2*y1;
}
int kuali(line a,line b)//跨立实验(通过相互跨立则可确定两线段相交返回1)
{if(cross(a.s,a.e,b.s)*cross(a.s,a.e,b.e)<=0&&cross(b.s,b.e,a.s)*cross(b.s,b.e,a.e)<=0)return 1;return 0;
}


相关题目:

hdu1086 判断线段相交

You can Solve a Geometry Problem too

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 6740    Accepted Submission(s): 3256


Problem Description
Many geometry(几何)problems were designed in the ACM/ICPC. And now, I also prepare a geometry problem for this final exam. According to the experience of many ACMers, geometry problems are always much trouble, but this problem is very easy, after all we are now attending an exam, not a contest :)
Give you N (1<=N<=100) segments(线段), please output the number of all intersections(交点). You should count repeatedly if M (M>2) segments intersect at the same point.

Note:
You can assume that two segments would not intersect at more than one point. 

Input
Input contains multiple test cases. Each test case contains a integer N (1=N<=100) in a line first, and then N lines follow. Each line describes one segment with four float values x1, y1, x2, y2 which are coordinates of the segment’s ending. 
A test case starting with 0 terminates the input and this test case is not to be processed.

Output
For each case, print the number of intersections, and one line one case.

Sample Input
  
2 0.00 0.00 1.00 1.00 0.00 1.00 1.00 0.00 3 0.00 0.00 1.00 1.00 0.00 1.00 1.00 0.000 0.00 0.00 1.00 0.00 0

Sample Output
  
1 3
分析:判断交点数:

程序:

#include"stdio.h"
#include"string.h"
#include"math.h"
#include"stdlib.h"
#define M 101
#define inf 999999999
#define eps 1e-10
typedef struct node
{double x,y;
}P;
typedef struct line
{P s;P e;
}Line;
Line L[M];
double max(double x,double y)
{return x>y?x:y;
}
double min(double x,double y)
{return x<y?x:y;
}
int paichi(line a,line b)//快速排斥,若通过快速排斥进行跨立实验,否则无交点;
{if(max(a.e.x,a.s.x)>=min(b.s.x,b.e.x)&&max(b.s.x,b.e.x)>=min(a.s.x,a.e.x)&&max(a.s.y,a.e.y)>=min(b.s.y,b.e.y)&&max(b.s.y,b.e.y)>=min(a.s.y,a.e.y))return 1;elsereturn 0;
}
double cross(node a,node b,node c)//叉积
{double x1=b.x-a.x;double y1=b.y-a.y;double x2=c.x-a.x;double y2=c.y-a.y;return x1*y2-x2*y1;
}
int kuali(line a,line b)//跨立实验(通过相互跨立则可确定两线段相交返回1)
{if(cross(a.s,a.e,b.s)*cross(a.s,a.e,b.e)<=0&&cross(b.s,b.e,a.s)*cross(b.s,b.e,a.e)<=0)return 1;return 0;
}
int main()
{int n,i,j;while(scanf("%d",&n),n){for(i=1;i<=n;i++)scanf("%lf%lf%lf%lf",&L[i].s.x,&L[i].s.y,&L[i].e.x,&L[i].e.y);int cnt=0;for(i=1;i<=n;i++){for(j=i+1;j<=n;j++){if(paichi(L[i],L[j])&&kuali(L[i],L[j]))cnt++;}}printf("%d\n",cnt);}
}
poj1127

题目:

Jack Straws
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 3066 Accepted: 1376

Description

In the game of Jack Straws, a number of plastic or wooden "straws" are dumped on the table and players try to remove them one-by-one without disturbing the other straws. Here, we are only concerned with if various pairs of straws are connected by a path of touching straws. You will be given a list of the endpoints for some straws (as if they were dumped on a large piece of graph paper) and then will be asked if various pairs of straws are connected. Note that touching is connecting, but also two straws can be connected indirectly via other connected straws.

Input

Input consist multiple case,each case consists of multiple lines. The first line will be an integer n (1 < n < 13) giving the number of straws on the table. Each of the next n lines contain 4 positive integers,x1,y1,x2 and y2, giving the coordinates, (x1,y1),(x2,y2) of the endpoints of a single straw. All coordinates will be less than 100. (Note that the straws will be of varying lengths.) The first straw entered will be known as straw #1, the second as straw #2, and so on. The remaining lines of the current case(except for the final line) will each contain two positive integers, a and b, both between 1 and n, inclusive. You are to determine if straw a can be connected to straw b. When a = 0 = b, the current case is terminated. 

When n=0,the input is terminated. 

There will be no illegal input and there are no zero-length straws. 

Output

You should generate a line of output for each line containing a pair a and b, except the final line where a = 0 = b. The line should say simply "CONNECTED", if straw a is connected to straw b, or "NOT CONNECTED", if straw a is not connected to straw b. For our purposes, a straw is considered connected to itself.

Sample Input

7
1 6 3 3 
4 6 4 9 
4 5 6 7 
1 4 3 5 
3 5 5 5 
5 2 6 3 
5 4 7 2 
1 4 
1 6 
3 3 
6 7 
2 3 
1 3 
0 02
0 2 0 0
0 0 0 1
1 1
2 2
1 2
0 00

Sample Output

CONNECTED 
NOT CONNECTED 
CONNECTED 
CONNECTED 
NOT CONNECTED 
CONNECTED
CONNECTED
CONNECTED
CONNECTED
分析:判断线段相交+并查集

程序:

#include"stdio.h"
#include"string.h"
#include"math.h"
#include"stdlib.h"
#define M 101
#define inf 999999999
#define eps 1e-10
typedef struct node
{double x,y;
}P;
int f[M];
int finde(int x)
{if(x!=f[x])f[x]=finde(f[x]);return f[x];
}
void make(int a,int b)
{int x=finde(a);int y=finde(b);if(x!=y)f[x]=y;
}
double max(double x,double y)
{return x>y?x:y;
}
double min(double x,double y)
{return x<y?x:y;
}
typedef struct line
{P s;P e;
}Line;
Line L[M];
int paichi(line a,line b)
{if(max(a.e.x,a.s.x)>=min(b.s.x,b.e.x)&&max(b.s.x,b.e.x)>=min(a.s.x,a.e.x)&&max(a.s.y,a.e.y)>=min(b.s.y,b.e.y)&&max(b.s.y,b.e.y)>=min(a.s.y,a.e.y))return 1;elsereturn 0;
}
double cross(node a,node b,node c)
{double x1=b.x-a.x;double y1=b.y-a.y;double x2=c.x-a.x;double y2=c.y-a.y;return x1*y2-x2*y1;
}
int kuali(line a,line b)
{if(cross(a.s,a.e,b.s)*cross(a.s,a.e,b.e)<=0&&cross(b.s,b.e,a.s)*cross(b.s,b.e,a.e)<=0)return 1;return 0;
}
int main()
{int i,n,j;while(scanf("%d",&n),n){for(i=1;i<=n;i++)scanf("%lf%lf%lf%lf",&L[i].s.x,&L[i].s.y,&L[i].e.x,&L[i].e.y);for(i=1;i<=n;i++)f[i]=i;for(i=1;i<=n;i++){for(j=i+1;j<=n;j++){if(paichi(L[i],L[j])&&kuali(L[i],L[j]))make(i,j);}}int a,b;while(scanf("%d%d",&a,&b),a||b){if(finde(a)==finde(b))printf("CONNECTED\n");elseprintf("NOT CONNECTED\n");}}return 0;
}




这篇关于判断两线段是否相交(快速排斥和跨立)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/190438

相关文章

电脑桌面文件删除了怎么找回来?别急,快速恢复攻略在此

在日常使用电脑的过程中,我们经常会遇到这样的情况:一不小心,桌面上的某个重要文件被删除了。这时,大多数人可能会感到惊慌失措,不知所措。 其实,不必过于担心,因为有很多方法可以帮助我们找回被删除的桌面文件。下面,就让我们一起来了解一下这些恢复桌面文件的方法吧。 一、使用撤销操作 如果我们刚刚删除了桌面上的文件,并且还没有进行其他操作,那么可以尝试使用撤销操作来恢复文件。在键盘上同时按下“C

poj 3259 uva 558 Wormholes(bellman最短路负权回路判断)

poj 3259: 题意:John的农场里n块地,m条路连接两块地,w个虫洞,虫洞是一条单向路,不但会把你传送到目的地,而且时间会倒退Ts。 任务是求你会不会在从某块地出发后又回来,看到了离开之前的自己。 判断树中是否存在负权回路就ok了。 bellman代码: #include<stdio.h>const int MaxN = 501;//农场数const int

poj 1127 线段相交的判定

题意: 有n根木棍,每根的端点坐标分别是 px, py, qx, qy。 判断每对木棍是否相连,当他们之间有公共点时,就认为他们相连。 并且通过相连的木棍相连的木棍也是相连的。 解析: 线段相交的判定。 首先,模板中的线段相交是不判端点的,所以要加一个端点在直线上的判定; 然后,端点在直线上的判定这个函数是不判定两个端点是同一个端点的情况的,所以要加是否端点相等的判断。 最后

hdu 4565 推倒公式+矩阵快速幂

题意 求下式的值: Sn=⌈ (a+b√)n⌉%m S_n = \lceil\ (a + \sqrt{b}) ^ n \rceil\% m 其中: 0<a,m<215 0< a, m < 2^{15} 0<b,n<231 0 < b, n < 2^{31} (a−1)2<b<a2 (a-1)^2< b < a^2 解析 令: An=(a+b√)n A_n = (a +

v0.dev快速开发

探索v0.dev:次世代开发者之利器 今之技艺日新月异,开发者之工具亦随之进步不辍。v0.dev者,新兴之开发者利器也,迅速引起众多开发者之瞩目。本文将引汝探究v0.dev之基本功能与优势,助汝速速上手,提升开发之效率。 何谓v0.dev? v0.dev者,现代化之开发者工具也,旨在简化并加速软件开发之过程。其集多种功能于一体,助开发者高效编写、测试及部署代码。无论汝为前端开发者、后端开发者

zoj 1721 判断2条线段(完全)相交

给出起点,终点,与一些障碍线段。 求起点到终点的最短路。 枚举2点的距离,然后最短路。 2点可达条件:没有线段与这2点所构成的线段(完全)相交。 const double eps = 1e-8 ;double add(double x , double y){if(fabs(x+y) < eps*(fabs(x) + fabs(y))) return 0 ;return x + y ;

POJ1269 判断2条直线的位置关系

题目大意:给两个点能够确定一条直线,题目给出两条直线(由4个点确定),要求判断出这两条直线的关系:平行,同线,相交。如果相交还要求出交点坐标。 解题思路: 先判断两条直线p1p2, q1q2是否共线, 如果不是,再判断 直线 是否平行, 如果还不是, 则两直线相交。  判断共线:  p1p2q1 共线 且 p1p2q2 共线 ,共线用叉乘为 0  来判断,  判断 平行:  p1p

Codeforces Round #113 (Div. 2) B 判断多边形是否在凸包内

题目点击打开链接 凸多边形A, 多边形B, 判断B是否严格在A内。  注意AB有重点 。  将A,B上的点合在一起求凸包,如果凸包上的点是B的某个点,则B肯定不在A内。 或者说B上的某点在凸包的边上则也说明B不严格在A里面。 这个处理有个巧妙的方法,只需在求凸包的时候, <=  改成< 也就是说凸包一条边上的所有点都重复点都记录在凸包里面了。 另外不能去重点。 int

easyui同时验证账户格式和ajax是否存在

accountName: {validator: function (value, param) {if (!/^[a-zA-Z][a-zA-Z0-9_]{3,15}$/i.test(value)) {$.fn.validatebox.defaults.rules.accountName.message = '账户名称不合法(字母开头,允许4-16字节,允许字母数字下划线)';return fal

【408DS算法题】039进阶-判断图中路径是否存在

Index 题目分析实现总结 题目 对于给定的图G,设计函数实现判断G中是否含有从start结点到stop结点的路径。 分析实现 对于图的路径的存在性判断,有两种做法:(本文的实现均基于邻接矩阵存储方式的图) 1.图的BFS BFS的思路相对比较直观——从起始结点出发进行层次遍历,遍历过程中遇到结点i就表示存在路径start->i,故只需判断每个结点i是否就是stop