[经验分享] C语言判断两线段是否相交

[复制链接]
2128|8
 楼主| vivilyly 发表于 2023-10-21 15:00 | 显示全部楼层 |阅读模式


  1. /*
  2.         利用矢量叉积判断是逆时针还是顺时针。
  3.         设A(x1,y1),B(x2,y2),C(x3,y3),则三角形两边的矢量分别是:
  4.         AB=(x2-x1,y2-y1), AC=(x3-x1,y3-y1)
  5.         则AB和AC的叉积为:(2*2的行列式)
  6.         |x2-x1, y2-y1|
  7.         |x3-x1, y3-y1|
  8.         值为:(x2-x1)*(y3-y1) - (y2-y1)*(x3-x1)
  9.         利用右手法则进行判断:
  10.         如果AB*AC>0,则三角形ABC是逆时针的
  11.         如果AB*AC<0,则三角形ABC是顺时针的
  12.         */
  13.        
  14.         #include<stdio.h>
  15.         #include<math.h>
  16.        
  17.         typedef struct point{
  18.                 double x,y;
  19.         }Point; //点
  20.        
  21.         typedef struct vector{
  22.                 double x,y;
  23.         }Vector; //向量
  24.        
  25.         typedef struct{
  26.                 double xmax,xmin; //矩形在x轴的最小值和最大值
  27.                 double ymax,ymin; //矩形在y轴的最小值和最大值
  28.         }MBR; //最小外包矩形
  29.        
  30.         /*返回x和y的最大值*/
  31.         double Max(double x,double y){
  32.                 return x>y?x:y;
  33.         }
  34.        
  35.         /*返回x和y的最小值*/
  36.         double Min(double x,double y){
  37.                 return x<y?x:y;
  38.         }
  39.        
  40.         /*
  41.         由 A(x1,y1),B(x2,y2) 构造向量AB
  42.         向AB=OB-OA=(x2-x1, y2-y1)
  43.          */
  44.         Vector VectorConstruct(Point A, Point B) {
  45.                 Vector v;
  46.                 v.x = B.x - A.x;  
  47.                 v.y = B.y - A.y;
  48.                 return v;
  49.         }
  50.        
  51.         /*
  52.         向量a(x1,y1)和b(x2,y2)的叉积
  53.         a×b = x1y2-x2y1
  54.         */
  55.         double CrossProduct(Vector a, Vector b) {
  56.                 return a.x * b.y - a.y * b.x;
  57.         }
  58.        
  59.         /*
  60.         由A点和B点构造一个最小外包矩形【以线段AB为对角线的矩形】
  61.          */
  62.         MBR MbrConstruct(Point A, Point B) {
  63.                 MBR m;
  64.                 /*将点A和点B中x值大的赋给xmax,小的赋给xmin*/
  65.                 if(A.x > B.x){
  66.                         m.xmax = A.x;
  67.                         m.xmin = B.x;
  68.                 }
  69.                 else{
  70.                         m.xmax = B.x;
  71.                         m.xmin = A.x;
  72.                 }
  73.                 /*将点A和点B中y值大的赋给ymax,小的赋给ymin*/
  74.                 if(A.y > B.y){
  75.                         m.ymax = A.y;
  76.                         m.ymin = B.y;
  77.                 }
  78.                 else{
  79.                         m.ymax = B.y;
  80.                         m.ymin = A.y;
  81.                 }
  82.                 return m;
  83.         }
  84.        
  85.         /*
  86.         快速排斥实验【两个MBR在x以及y坐标的投影是否有重合】
  87.         判断两个MBR是否有交集,有返回1,否0
  88.         */
  89.         int MbrOverlap(MBR m1, MBR m2) {
  90.                 double xmin, xmax, ymin, ymax;
  91.                 xmin = Max(m1.xmin, m2.xmin);   //两个外包矩形中最小x中的大者
  92.                 xmax = Min(m1.xmax, m2.xmax);   //两个外包矩形中最大x中的小者
  93.                 ymin = Max(m1.ymin, m2.ymin);   //两个外包矩形中最小y中的大者
  94.                 ymax = Min(m1.ymax, m2.ymax);   //两个外包矩形中最大y中的小者
  95.                
  96.                 /*
  97.                 如果:两个外包矩形中最大x中的小者 >= 两个外包矩形中最小x中的大者
  98.                 并且:两个外包矩形中最大y中的小者 >= 两个外包矩形中最小y中的大者
  99.                 则两个MBR是有交集,返回1
  100.                 */
  101.                 return (xmax >= xmin && ymax >= ymin) ? 1 : 0;
  102.         }
  103.        
  104.         /*
  105.         方法一:快速排斥+跨立
  106.         判断两线段(线段AB和CD)是否相交,是返回1,否0
  107.         */
  108.         int SegmentIntersection(Point A, Point B, Point C, Point D) {
  109.                 MBR m1,m2;
  110.                 Vector CA,CB,CD,AC,AD,AB;
  111.        
  112.             /*求线段AB和CD所在的MBR*/
  113.                 m1 = MbrConstruct(A, B);
  114.                 m2 = MbrConstruct(C, D);
  115.        
  116.                 /*【快速排斥实验】判断AB和CD所在的MBR是否相交*/
  117.                 if(MbrOverlap(m1, m2) == 0) //不相交,直接返回0
  118.                         return 0;
  119.                
  120.                 /*求向量CA、CB、CD的坐标表示*/
  121.                 CA = VectorConstruct(C, A);
  122.                 CB = VectorConstruct(C, B);
  123.                 CD = VectorConstruct(C, D);
  124.                
  125.                 /*求向量AC、AD、AB的坐标表示*/
  126.                 AC = VectorConstruct(A, C);
  127.                 AD = VectorConstruct(A, D);
  128.                 AB = VectorConstruct(A, B);
  129.                
  130.                 /*【跨立实验】进一步判断*/
  131.                 /*AB跨立CD,并且,CD跨立AB*/
  132.                 /*判断条件:(CA×CD)*(CB×CD)<= 0 && (AC×AB)*(AD×AB)<= 0*/
  133.                 if (CrossProduct(CA, CD) * CrossProduct(CB, CD) <= 0 && CrossProduct(AC, AB) * CrossProduct(AD, AB) <= 0)
  134.                         return 1;
  135.                 else
  136.                         return 0;
  137.         }
  138.        
  139.         void main(){
  140.                 int tag;
  141.                 Point A,B,C,D;
  142.                 A.x=1,A.y=2;
  143.                 B.x=3,B.y=4;
  144.                 C.x=1,C.y=3;
  145.                 D.x=4,D.y=1;
  146.                 /*方法一:快速排斥+跨立试验*/
  147.                 tag=SegmentIntersection(A,B,C,D);
  148.                 if(tag)
  149.                         printf("两直线相交\n");
  150.                 else
  151.                         printf("两直线不相交\n");
  152.         }


tpgf 发表于 2023-11-7 11:19 | 显示全部楼层
这样判定的原理是是怎么呢
heimaojingzhang 发表于 2023-11-7 11:54 | 显示全部楼层
是否需要判断当前两个线是线段呢?
keaibukelian 发表于 2023-11-7 12:30 | 显示全部楼层
判断线段相交的前提是先判断是不是平行的
paotangsan 发表于 2023-11-7 12:59 | 显示全部楼层
至少得分两步走 而且在计算交点的时候还得不能直接计算
renzheshengui 发表于 2023-11-7 13:45 | 显示全部楼层
这种直接做乘法的会不会不太好啊
wakayi 发表于 2023-11-7 21:21 | 显示全部楼层
有没有更加简便的算法呢
zwsam 发表于 2023-11-8 08:54 | 显示全部楼层
duo点 发表于 2023-12-7 14:40 | 显示全部楼层
C语言判断两线段是否相交
您需要登录后才可以回帖 登录 | 注册

本版积分规则

113

主题

2034

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部