求两线段交点

一、概述

题目来源于leetcode。

 

二、思路

先通过快速排斥试验判断以线段为对角线的矩形是否相交,不相交则无交点;
再判断线段是否跨立;
再判断是否共线,并计算交点;
线段相交,根据三角形面积和定比分点公式计算交点坐标。

三、代码

/**
 * @param {number[]} start1
 * @param {number[]} end1
 * @param {number[]} start2
 * @param {number[]} end2
 * @return {number[]}
 */
var intersection = function (start1, end1, start2, end2) {    
    let P1 = new Point(start1);
    let P2 = new Point(end1);
    let Q1 = new Point(start2);
    let Q2 = new Point(end2);
    let arr = [];  //先通过快速排斥试验判断以线段为对角线的矩形是否相交,不相交则无交点;
    if (Math.max(P1.x, P2.x) < Math.min(Q1.x, Q2.x) ||
        Math.max(Q1.x, Q2.x) < Math.min(P1.x, P2.x) ||
        Math.max(P1.y, P2.y) < Math.min(Q1.y, Q2.y) ||
        Math.max(Q1.y, Q2.y) < Math.min(P1.y, P2.y)) {
        return [];
    }
    let Q1P1=getLine(Q1,P1);
    let Q1P2=getLine(Q1,P2);
    let Q1Q2=getLine(Q1,Q2);
    let P1P2=getLine(P1,P2);
    let P1Q1=getLine(P1,Q1);
    let P1Q2=getLine(P1,Q2);
    let P2Q2=getLine(P2,Q2);    //再判断线段是否跨立;
    let crossV=vectorCross(Q1P1,Q1Q2)*vectorCross(Q1P2,Q1Q2);
    let crossV2=vectorCross(P1Q1,P1P2)*vectorCross(P1Q2,P1P2);
    if(crossV>0||crossV2>0){
        return [];
    }  //再判断是否共线,并计算交点;
    if(vectorCross(Q1P1,P1Q2)===0||vectorCross(Q1P2,P2Q2)===0||vectorCross(Q1P2,P2Q2)===0){//共线
        let isQ1inP1P2=isPointInLine(P1,P2,Q1);
        if(isQ1inP1P2){
            arr=update(Q1.x,Q1.y,arr);
        }
        let isQ2inP1P2=isPointInLine(P1,P2,Q2);
        if(isQ2inP1P2){
            arr=update(Q2.x,Q2.y,arr);
        }
        let isP1inQ1Q2=isPointInLine(Q1,Q2,P1);
        if(isP1inQ1Q2){
            arr=update(P1.x,P1.y,arr);
        }
        let isP2inQ1Q2=isPointInLine(Q1,Q2,P2);
        if(isP2inQ1Q2){
            arr=update(P2.x,P2.y,arr);
        }
    }else{     //线段相交,根据三角形面积和定比分点公式计算交点坐标。
        let s1=Math.abs(vectorCross(Q1Q2,Q1P2))*0.5;
        let s2=Math.abs(vectorCross(Q1Q2,Q1P1))*0.5;
        let lamda=s1/s2;
        let x,y;
        x=(P2.x+lamda*P1.x)/(1+lamda);
        y=(P2.y+lamda*P1.y)/(1+lamda);
        arr=[x,y];
    }
    return arr;
};

var Point = function (p) {
    this.x = p[0];
    this.y = p[1];
}

var vectorCross=function(v1,v2){
    return v1[0]*v2[1]-v2[0]*v1[1];
}

//点p在线段point1——point2上,且是有交点的前提下
var isPointInLine=function(point1,point2,p){
    let minX=min(point1.x,point2.x);
    let minY=min(point1.y,point2.y);
    let maxX=max(point1.x,point2.x);
    let maxY=max(point1.y,point2.y);
    if(p.x>=minX&&p.x<=maxX&&p.y>=minY&&p.y<=maxY&&vectorCross(getLine(point1,p),getLine(p,point2))===0){
        return true;
    }
    return false;    
}

var update=function(x,y,arr){//获取坐标最小的点
    if(arr.length===0||x<arr[0]||(x===arr[0]&&y<arr[1])){
        arr=[x,y];        
    }
    return arr;
}

var min=function(a,b){
    return Math.min(a,b);
}

var max=function(a,b){
    return Math.max(a,b);
}

var getLine=function(Q1,P1){
    let Q1P1=[P1.x-Q1.x,P1.y-Q1.y];
    return Q1P1;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值