【threejs】二维坐标内判断 点 与 凹凸多边形 位置关系

核心思路

从点向 ± xy方向发射四条射线,从相交次数判断点与多边形关系,理论上只要有一条射线相交奇数次(n%2==1)即可判定点在多边形内,此方法可避免凹凸多边形造成的判断错误。
在这里插入图片描述

相交判断

根据参数方程判断相交(好像高三的知识,推到忘了23333…想起来了再补充)。


/**
// 判断两条线段是否相交
 * (x1,y1,x2,y2)(x3,y3,x4,y4)
 * @param {*} x1 //point1
 * @param {*} y1 //point1
 * @param {*} x2 //point2
 * @param {*} y2 //point2
 * @param {*} x3 //point3
 * @param {*} y3 //point3
 * @param {*} x4 //point4
 * @param {*} y4 //point4
 * @returns 
 */
function segmentsIntersect(x1, y1, x2, y2, x3, y3, x4, y4) {

    var ua, ub, denom, intersectX, intersectY;

    denom = (x4 - x3) * (y2 - y1) - (y4 - y3) * (x2 - x1);

    if (denom === 0) {
        return false; // Lines are parallel
    }

    ua = ((y4 - y3) * (x1 - x3) - (x4 - x3) * (y1 - y3)) / denom;
    ub = ((y2 - y1) * (x1 - x3) - (x2 - x1) * (y1 - y3)) / denom;


    if (ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1) {
        // Intersection point
        // intersectX = x1 + ua * (x2 - x1);
        // intersectY = y1 + ua * (y2 - y1);
        // return [intersectX, intersectY];
        return true
    }

    return false;
}

export default segmentsIntersect

计算是否再多边形内

使用滚筒循环遍历所有边 统计相交次数(边和射线看作两线段)

/**
* 这里 x , y 为点,captureVec3为一个Vector3({x,y,z})
* max min 分别为 {x:999999,y:999999}{x:0,y:0}
* 根据情况自行给定max,min边界范围
*/
// 计算范围内的点
const isInArea = (x, y, max, min, captureVec3) => {
    let oddIntersections = [0, 0, 0, 0];  // 记录每个方向的交点个数→←↑↓

    for (let i = 0; i < 4; i++) {
        let [x1, y1] = [x, y];  // 起点为给定点
        let [x2, y2] = getEndPoint(x, y, max, min, i);  // 获取当前方向上的终点
        // 遍历多边形的边,计算交点个数
        for (let k = 0, j = captureVec3.length - 1; k < captureVec3.length; j = k++) {

            let x3 = captureVec3[k].x, y3 = captureVec3[k].y
            let x4 = captureVec3[(j) % captureVec3.length].x,
                y4 = captureVec3[(j) % captureVec3.length].y

            let isIntersect = segmentsIntersect(x1, y1, x2, y2, x3, y3, x4, y4)
            if (isIntersect) oddIntersections[i]++
        }
    }

    for (let i = 0; i < 4; i++) {
        let v = oddIntersections[i]
        if (v % 2 == 0) {
            return false
        }
    }
    return true
}
// 获取边界值
const getEndPoint = (x, y, max, min, i) => {
    let _x = x, _min_x = min.x, _max_x = max.x
    let _y = y, _min_y = min.y, _max_y = max.y
    let result = null
    switch (i) {
        case 0:
            result = [_max_x, _y]
            break;
        case 1:
            result = [_min_x, _y]
            break;

        case 2:
            result = [_x, _max_y]
            break;

        case 3:
            result = [_x, _min_y]
            break;

    }
    return result

}

改进

其实只要有一条射线交点是奇数就够了,但我实际操作时出现了问题,暂时还没找到在哪…🤣,这个方法重复了四遍。

  • 10
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

鸢_

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

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

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

打赏作者

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

抵扣说明:

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

余额充值