交点--几何判断线段交点问题

0x01.问题

给定两条线段(表示为起点start = {X1, Y1}和终点end = {X2, Y2}),如果它们有交点,请计算其交点,没有交点则返回空值。
要求浮点型误差不超过10^-6。若有多个交点(线段重叠)则返回 X 值最小的点,X 坐标相同则返回 Y 值最小的点。
坐标绝对值不会超过 2^7,输入的坐标均是有效的二维坐标。

输入示例:
line1 = {0, 0}, {3, 3}
line2 = {1, 1}, {2, 2}
输出示例:
{1, 1}

来自《程序员面试金典》16.03

public double[] intersection(int[] start1, int[] end1, int[] start2, int[] end2)

0x02.简要分析

初看,是个数学的几何问题,以为难度不大,后来仔细一想,发现不是直线的交点,是线段的交点,那么需要考虑的特殊情况就有些多,不过只要理清思路,还是不难的。
具体思路如下:

  • 先判断两条线段所在直线是否平行(用斜率判断)。

    • 如果平行,再考虑所在直线是否重合。

      • 如果不重合,一定没有交点。

      • 如果重合,那么依次判断每个直线的端点是否在另一条直线上线段上,并不断更新交点为最小值。

    • 如果不平行,那么使用参数方程算出参数t1t2,再判断是否满足t1,t2属于[0,1],属于就有交点,算出交点,不属于就没有交点。

0x03.解决代码–分类讨论

class Solution {
    private boolean inside(int x1,int y1,int x2,int y2,int x,int y){
        //同时考虑与x轴,y轴平行,一般情况
        return (x1 == x2 || (Math.min(x1, x2) <= x && x <= Math.max(x1, x2))) 
        && (y1 == y2 || (Math.min(y1, y2) <= y && y <= Math.max(y1, y2)));
    }
    private void up(double[]result,double x,double y){
        if((result[0]==Integer.MAX_VALUE)||x<result[0]||(x==result[0]&&y<result[1])){
            result[0]=x;
            result[1]=y;
        }
    }
    public double[] intersection(int[] start1, int[] end1, int[] start2, int[] end2) {
        int x1=start1[0],y1=start1[1];
        int x2=end1[0],y2=end1[1];
        int x3=start2[0],y3=start2[1];
        int x4=end2[0],y4=end2[1];
        double[] result=new double[2];
        result[0]=Integer.MAX_VALUE;
        result[1]=Integer.MAX_VALUE;
        //平行情况
        if ((y4 - y3) * (x2 - x1) == (y2 - y1) * (x4 - x3)) {
             //判断两直线是否重合
            if ((y2 - y1) * (x3 - x1) == (y3 - y1) * (x2 - x1)){
                //判断 (x3, y3) 是否在「线段」(x1, y1)~(x2, y2) 上
                if (inside(x1, y1, x2, y2, x3, y3)) {
                    up(result,(double)x3,(double)y3);
                }
                 // 判断 (x4, y4) 是否在「线段」(x1, y1)~(x2, y2) 上
                 if (inside(x1, y1, x2, y2, x4, y4)) {
                    up(result, (double)x4, (double)y4);
                }
                // 判断 (x1, y1) 是否在「线段」(x3, y3)~(x4, y4) 上
                if (inside(x3, y3, x4, y4, x1, y1)) {
                    up(result, (double)x1, (double)y1);
                }
                // 判断 (x2, y2) 是否在「线段」(x3, y3)~(x4, y4) 上
                if (inside(x3, y3, x4, y4, x2, y2)) {
                    up(result, (double)x2, (double)y2);
                }    
            }
        }else{
            //参数方程求解
            double t1 = (double)(x3 * (y4 - y3) + y1 * (x4 - x3) - y3 * (x4 - x3)
             - x1 * (y4 - y3)) / ((x2 - x1) * (y4 - y3) - (x4 - x3) * (y2 - y1));
            double t2 = (double)(x1 * (y2 - y1) + y3 * (x2 - x1) - y1 * (x2 - x1)
             - x3 * (y2 - y1)) / ((x4 - x3) * (y2 - y1) - (x2 - x1) * (y4 - y3));
            //判断参数是否满足属于[0,1]
            if (t1 >= 0.0 && t1 <= 1.0 && t2 >= 0.0 && t2 <= 1.0) {
                result[0] = x1 + t1 * (x2 - x1);
                result[1] = y1+  t1 * (y2 - y1);
            }
        }
        return result[0]==Integer.MAX_VALUE?new double[]{}:result;
    }
}

我跨过山,涉过水,见过万物复苏,周而复始,如今,山是__,水是__,万物是__,心间一点清明,还是__。

ATFWUS --Writing By 2020–04-12

  • 24
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ATFWUS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值