打印
[经验分享]

C语言判断两线段是否相交

[复制链接]
1668|8
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
vivilyly|  楼主 | 2023-10-21 15:00 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式


 /*
        利用矢量叉积判断是逆时针还是顺时针。
        设A(x1,y1),B(x2,y2),C(x3,y3),则三角形两边的矢量分别是:
        AB=(x2-x1,y2-y1), AC=(x3-x1,y3-y1)
        则AB和AC的叉积为:(2*2的行列式)
        |x2-x1, y2-y1|
        |x3-x1, y3-y1|
        值为:(x2-x1)*(y3-y1) - (y2-y1)*(x3-x1)
        利用右手法则进行判断:
        如果AB*AC>0,则三角形ABC是逆时针的
        如果AB*AC<0,则三角形ABC是顺时针的
        */
       
        #include<stdio.h>
        #include<math.h>
       
        typedef struct point{
                double x,y;
        }Point; //点
       
        typedef struct vector{
                double x,y;
        }Vector; //向量
       
        typedef struct{
                double xmax,xmin; //矩形在x轴的最小值和最大值
                double ymax,ymin; //矩形在y轴的最小值和最大值
        }MBR; //最小外包矩形
       
        /*返回x和y的最大值*/
        double Max(double x,double y){
                return x>y?x:y;
        }
       
        /*返回x和y的最小值*/
        double Min(double x,double y){
                return x<y?x:y;
        }
       
        /*
        由 A(x1,y1),B(x2,y2) 构造向量AB
        向AB=OB-OA=(x2-x1, y2-y1)
         */
        Vector VectorConstruct(Point A, Point B) {
                Vector v;
                v.x = B.x - A.x;  
                v.y = B.y - A.y;
                return v;
        }
       
        /*
        向量a(x1,y1)和b(x2,y2)的叉积
        a×b = x1y2-x2y1
        */
        double CrossProduct(Vector a, Vector b) {
                return a.x * b.y - a.y * b.x;
        }
       
        /*
        由A点和B点构造一个最小外包矩形【以线段AB为对角线的矩形】
         */
        MBR MbrConstruct(Point A, Point B) {
                MBR m;
                /*将点A和点B中x值大的赋给xmax,小的赋给xmin*/
                if(A.x > B.x){
                        m.xmax = A.x;
                        m.xmin = B.x;
                }
                else{
                        m.xmax = B.x;
                        m.xmin = A.x;
                }
                /*将点A和点B中y值大的赋给ymax,小的赋给ymin*/
                if(A.y > B.y){
                        m.ymax = A.y;
                        m.ymin = B.y;
                }
                else{
                        m.ymax = B.y;
                        m.ymin = A.y;
                }
                return m;
        }
       
        /*
        快速排斥实验【两个MBR在x以及y坐标的投影是否有重合】
        判断两个MBR是否有交集,有返回1,否0
        */
        int MbrOverlap(MBR m1, MBR m2) {
                double xmin, xmax, ymin, ymax;
                xmin = Max(m1.xmin, m2.xmin);   //两个外包矩形中最小x中的大者
                xmax = Min(m1.xmax, m2.xmax);   //两个外包矩形中最大x中的小者
                ymin = Max(m1.ymin, m2.ymin);   //两个外包矩形中最小y中的大者
                ymax = Min(m1.ymax, m2.ymax);   //两个外包矩形中最大y中的小者
               
                /*
                如果:两个外包矩形中最大x中的小者 >= 两个外包矩形中最小x中的大者
                并且:两个外包矩形中最大y中的小者 >= 两个外包矩形中最小y中的大者
                则两个MBR是有交集,返回1
                */
                return (xmax >= xmin && ymax >= ymin) ? 1 : 0;
        }
       
        /*
        方法一:快速排斥+跨立
        判断两线段(线段AB和CD)是否相交,是返回1,否0
        */
        int SegmentIntersection(Point A, Point B, Point C, Point D) {
                MBR m1,m2;
                Vector CA,CB,CD,AC,AD,AB;
       
            /*求线段AB和CD所在的MBR*/
                m1 = MbrConstruct(A, B);
                m2 = MbrConstruct(C, D);
       
                /*【快速排斥实验】判断AB和CD所在的MBR是否相交*/
                if(MbrOverlap(m1, m2) == 0) //不相交,直接返回0
                        return 0;
               
                /*求向量CA、CB、CD的坐标表示*/
                CA = VectorConstruct(C, A);
                CB = VectorConstruct(C, B);
                CD = VectorConstruct(C, D);
               
                /*求向量AC、AD、AB的坐标表示*/
                AC = VectorConstruct(A, C);
                AD = VectorConstruct(A, D);
                AB = VectorConstruct(A, B);
               
                /*【跨立实验】进一步判断*/
                /*AB跨立CD,并且,CD跨立AB*/
                /*判断条件:(CA×CD)*(CB×CD)<= 0 && (AC×AB)*(AD×AB)<= 0*/
                if (CrossProduct(CA, CD) * CrossProduct(CB, CD) <= 0 && CrossProduct(AC, AB) * CrossProduct(AD, AB) <= 0)
                        return 1;
                else
                        return 0;
        }
       
        void main(){
                int tag;
                Point A,B,C,D;
                A.x=1,A.y=2;
                B.x=3,B.y=4;
                C.x=1,C.y=3;
                D.x=4,D.y=1;
                /*方法一:快速排斥+跨立试验*/
                tag=SegmentIntersection(A,B,C,D);
                if(tag)
                        printf("两直线相交\n");
                else
                        printf("两直线不相交\n");
        }


使用特权

评论回复
沙发
tpgf| | 2023-11-7 11:19 | 只看该作者
这样判定的原理是是怎么呢

使用特权

评论回复
板凳
heimaojingzhang| | 2023-11-7 11:54 | 只看该作者
是否需要判断当前两个线是线段呢?

使用特权

评论回复
地板
keaibukelian| | 2023-11-7 12:30 | 只看该作者
判断线段相交的前提是先判断是不是平行的

使用特权

评论回复
5
paotangsan| | 2023-11-7 12:59 | 只看该作者
至少得分两步走 而且在计算交点的时候还得不能直接计算

使用特权

评论回复
6
renzheshengui| | 2023-11-7 13:45 | 只看该作者
这种直接做乘法的会不会不太好啊

使用特权

评论回复
7
wakayi| | 2023-11-7 21:21 | 只看该作者
有没有更加简便的算法呢

使用特权

评论回复
8
zwsam| | 2023-11-8 08:54 | 只看该作者

使用特权

评论回复
9
duo点| | 2023-12-7 14:40 | 只看该作者
C语言判断两线段是否相交

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

79

主题

1644

帖子

0

粉丝