zoukankan      html  css  js  c++  java
  • 【计算几何】线段相交

    问题描述:已知两条线段P1P2和Q1Q2,判断P1P2和Q1Q2是否相交,若相交,求出交点。

    两条线段的位置关系可以分为三类:有重合部分、无重合部分但有交点、无交点。

    算法的步骤如下:

    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。

    若Q1Q2跨立P1P2,则矢量(Q1-P1)和(Q2-P1)位于矢量(P2-P1)的两侧,即( Q1 - P1 ) × ( P2 - P1 ) * ( Q2 - P1 ) × ( P2 - P1 ) < 0。

    排斥实验和跨立实验的示例如下图所示。

    3.计算交点。

    当判定两条线段相交后,可以进行交点的求解,求交点可以用平面几何方法,列点斜式方程来完成。但由于点斜式方程难以处理斜率为0的特殊情况,不方便求解。因而,参用向量法求解交点。

    设交点为(x0,y0),则下列方程组成立:

    根据以上方程组,消除参数k1和k2,得到如下方程:

    然后求解(x0,y0),结果如下所示:

    复制代码

     1 typedef struct Point
     2 {
     3     int x;
     4     int y;
     5 }Point;
     6 //排斥实验
     7 bool IsRectCross(const Point &p1,const Point &p2,const Point &q1,const Point &q2)
     8 {
     9     bool ret = min(p1.x,p2.x) <= max(q1.x,q2.x)    &&
    10                 min(q1.x,q2.x) <= max(p1.x,p2.x) &&
    11                 min(p1.y,p2.y) <= max(q1.y,q2.y) &&
    12                 min(q1.y,q2.y) <= max(p1.y,p2.y);
    13     return ret;
    14 }
    15 //跨立判断
    16 bool IsLineSegmentCross(const Point &pFirst1,const Point &pFirst2,const Point &pSecond1,const Point &pSecond2)
    17 {
    18     long line1,line2;
    19     line1 = pFirst1.x * (pSecond1.y - pFirst2.y) +
    20         pFirst2.x * (pFirst1.y - pSecond1.y) +
    21         pSecond1.x * (pFirst2.y - pFirst1.y);
    22     line2 = pFirst1.x * (pSecond2.y - pFirst2.y) +
    23         pFirst2.x * (pFirst1.y - pSecond2.y) + 
    24         pSecond2.x * (pFirst2.y - pFirst1.y);
    25     if (((line1 ^ line2) >= 0) && !(line1 == 0 && line2 == 0))
    26         return false;
    27 
    28     line1 = pSecond1.x * (pFirst1.y - pSecond2.y) +
    29         pSecond2.x * (pSecond1.y - pFirst1.y) +
    30         pFirst1.x * (pSecond2.y - pSecond1.y);
    31     line2 = pSecond1.x * (pFirst2.y - pSecond2.y) + 
    32         pSecond2.x * (pSecond1.y - pFirst2.y) +
    33         pFirst2.x * (pSecond2.y - pSecond1.y);
    34     if (((line1 ^ line2) >= 0) && !(line1 == 0 && line2 == 0))
    35         return false;
    36     return true;
    37 }
    38 
    39 bool GetCrossPoint(const Point &p1,const Point &p2,const Point &q1,const Point &q2,long &x,long &y)
    40 {
    41     if(IsRectCross(p1,p2,q1,q2))
    42     {
    43         if (IsLineSegmentCross(p1,p2,q1,q2))
    44         {
    45             //求交点
    46             long tmpLeft,tmpRight;
    47             tmpLeft = (q2.x - q1.x) * (p1.y - p2.y) - (p2.x - p1.x) * (q1.y - q2.y);
    48             tmpRight = (p1.y - q1.y) * (p2.x - p1.x) * (q2.x - q1.x) + q1.x * (q2.y - q1.y) * (p2.x - p1.x) - p1.x * (p2.y - p1.y) * (q2.x - q1.x);
    49 
    50             x = (int)((double)tmpRight/(double)tmpLeft);
    51 
    52             tmpLeft = (p1.x - p2.x) * (q2.y - q1.y) - (p2.y - p1.y) * (q1.x - q2.x);
    53             tmpRight = p2.y * (p1.x - p2.x) * (q2.y - q1.y) + (q2.x- p2.x) * (q2.y - q1.y) * (p1.y - p2.y) - q2.y * (q1.x - q2.x) * (p2.y - p1.y); 
    54             y = (int)((double)tmpRight/(double)tmpLeft);
    55             return true;
    56         }
    57     }
    58     return false;
    59 }

    复制代码

  • 相关阅读:
    kafka 幂等生产者及事务(kafka0.11之后版本新特性)
    git 忽略 .idea文件
    Java Scala 混合编程导致 编译失败 ,【找不到符号】问题解决
    Starting sshd: /var/empty/sshd must be owned by root and not group or world-writable.
    Spark RDD持久化、广播变量和累加器
    PSQLException: FATAL: no pg_hba.conf entry for host "127.0.0.1", user "ambari", database "ambari", SSL off
    PostgreSQL:Java使用CopyManager实现客户端文件COPY导入
    ThreadLocal的使用及原理分析
    gradlew和gradle的区别
    Managing Large State in Apache Flink®: An Intro to Incremental Checkpointing
  • 原文地址:https://www.cnblogs.com/xmphoenix/p/4508463.html
Copyright © 2011-2022 走看看