首页 > 其他分享 >二维平面多边形的相交判定

二维平面多边形的相交判定

时间:2023-06-12 11:47:57浏览次数:30  
标签:多边形 Polygon plys 二维 判定 let segA segB

一、类型定义

1、点

export type Point = {
    x: number;
    y: number;
}

2、线

type Segment = [Point, Point];

3、面

type Polygon = Array<Point>;

二、使用

判断两个四边形是否相交:

import { isPolygonsOverlap } from "./util.ts";

let A: Polygon = [{x: 0, y: 4}, {x: 4, y: 4}, {x: -4, y: 0}, {x: 0, y: 0}];
let B: Polygon = [{x: 2, y: 6}, {x: 6, y: 6}, {x: 2, y: 0}, {x: 6, y: 0}];
isPolygonsOverlap(A, B);

OR

import PolygonUtils from "./util.ts";

let A: Polygon = [{x: 0, y: 4}, {x: 4, y: 4}, {x: -4, y: 0}, {x: 0, y: 0}];
let B: Polygon = [{x: 2, y: 6}, {x: 6, y: 6}, {x: 2, y: 0}, {x: 6, y: 0}];
PolygonUtils.isPolygonsOverlap(A, B);

三、高阶

import { isPolygonsOverlaps } from "./util.ts";

let A: Polygon = [{x: 0, y: 4}, {x: 4, y: 4}, {x: -4, y: 0}, {x: 0, y: 0}];
let B: Polygon = [{x: 2, y: 6}, {x: 6, y: 6}, {x: 2, y: 0}, {x: 6, y: 0}];
let c: Polygon = [{x: 4, y: 8}, {x: 8, y: 8}, {x: 4, y: 2}, {x: 8, y: 2}];

1、判断A、B是否相交

isPolygonsOverlaps(A, B);

2、判断A与B、C是否相交

isPolygonsOverlaps(A, [B, C]);

3、判断A、B、C是否相交

isPolygonsOverlaps(A, B, C);

四、源代码

export interface Point {
    x: number;
    y: number;
}
export type Polygon = Array<Point>;
export type Segment = [Point, Point];

/**
 * 判断两多边形线段是否相交
 *
 * @param {Segment} segA-线段A
 * @param {Segment} segB-线段B
 * @returns {Boolean} 两条线段是否相交
 */
export function isSegmentsIntersectant(segA: Segment, segB: Segment): Boolean {
    //线线
    const abc = (segA[0].x - segB[0].x) * (segA[1].y - segB[0].y) - (segA[0].y - segB[0].y) * (segA[1].x - segB[0].x);
    const abd = (segA[0].x - segB[1].x) * (segA[1].y - segB[1].y) - (segA[0].y - segB[1].y) * (segA[1].x - segB[1].x);
    if (abc * abd >= 0) {
        return false;
    }
    const cda = (segB[0].x - segA[0].x) * (segB[1].y - segA[0].y) - (segB[0].y - segA[0].y) * (segB[1].x - segA[0].x);
    const cdb = cda + abc - abd;
    return !(cda * cdb >= 0);
}

/**
 * 判断两多边形边界是否相交
 *
 * @param {Polygon} plyA-多边形A
 * @param {Polygon} plyB-多边形B
 * @returns {Boolean} 两个多边形边界是否相交
 */
export function isPolygonsIntersectant(plyA: Polygon, plyB: Polygon): Boolean {
    //面面
    for (let i = 0, il = plyA.length; i < il; i++) {
        for (let j = 0, jl = plyB.length; j < jl; j++) {
            const segA: Segment = [plyA[i], plyA[i === il - 1 ? 0 : i + 1]];
            const segB: Segment = [plyB[j], plyB[j === jl - 1 ? 0 : j + 1]];
            if (isSegmentsIntersectant(segA, segB)) {
                return true;
            }
        }
    }
    return false;
}

/**
 * 判断点是否在另一平面图中
 *
 * @param {Point} point-点
 * @param {Polygon} polygon-多边形
 * @returns {Boolean} 是否在另一平面图中
 */
export function isPointInPolygon(point: Point, polygon: Polygon): Boolean {
    //下述代码来源:http://paulbourke.net/geometry/insidepoly/,进行了部分修改
    //基本思想是利用射线法,计算射线与多边形各边的交点,如果是偶数,则点在多边形外,否则
    //在多边形内。还会考虑一些特殊情况,如点在多边形顶点上,点在多边形边上等特殊情况。
    var N = polygon.length;
    var boundOrVertex = true; //如果点位于多边形的顶点或边上,也算做点在多边形内,直接返回true
    var intersectCount = 0; //cross points count of x
    var precision = 2e-10; //浮点类型计算时候与0比较时候的容差
    var p1, p2; //neighbour bound vertices
    var p = point; //测试点
    
    p1 = polygon[0]; //left vertex
    for (var i = 1; i <= N; ++i) {
        //check all rays
        if (p.x == p1.x && p.y == p1.y) {
            return boundOrVertex; //p is an vertex
        }
        p2 = polygon[i % N]; //right vertex
        if (p.y < Math.min(p1.y, p2.y) || p.y > Math.max(p1.y, p2.y)) {
            //ray is outside of our interests
            p1 = p2;
            continue; //next ray left point
        }
        if (p.y > Math.min(p1.y, p2.y) && p.y < Math.max(p1.y, p2.y)) {
            //ray is crossing over by the algorithm (common part of)
            if (p.x <= Math.max(p1.x, p2.x)) {
                //x is before of ray
                if (p1.y == p2.y && p.x >= Math.min(p1.x, p2.x)) {
                    //overlies on a horizontal ray
                    return boundOrVertex;
                }
                if (p1.x == p2.x) {
                    //ray is vertical
                    if (p1.x == p.x) {
                        //overlies on a vertical ray
                        return boundOrVertex;
                    } else {
                        //before ray
                        ++intersectCount;
                    }
                } else {
                    //cross point on the left side
                    var xinters = ((p.y - p1.y) * (p2.x - p1.x)) / (p2.y - p1.y) + p1.x; //cross point of x
                    if (Math.abs(p.x - xinters) < precision) {
                        //overlies on a ray
                        return boundOrVertex;
                    }

                    if (p.x < xinters) {
                        //before ray
                        ++intersectCount;
                    }
                }
            }
        } else {
            //special case when ray is crossing through the vertex
            if (p.y == p2.y && p.x <= p2.x) {
                //p crossing over p2
                var p3 = polygon[(i + 1) % N]; //next vertex
                if (p.y >= Math.min(p1.y, p3.y) && p.y <= Math.max(p1.y, p3.y))                 {
                    //p.y lies between p1.y & p3.y
                    ++intersectCount;
                } else {
                    intersectCount += 2;
                }
            }
        }
        p1 = p2; //next ray left point
    }
    
    if (intersectCount % 2 == 0) {
        //偶数在多边形外
        return false;
    } else {
        //奇数在多边形内
        return true;
    }
}
  
/**
 * 判断两多变形是否存在点与区域的包含关系(A的点在B的区域内或B的点在A的区域内)
 *
 * @param {Polygon} plyA-多边形A
 * @param {Polygon} plyB-多边形B
 * @returns {Boolean} 两多变形是否存在点与区域的包含关系
 */
export function isPointInPolygonBidirectional(plyA: Polygon, plyB: Polygon): Boolean {
    //面面
    let [a, b] = [false, false];
    a = plyA.some(item => isPointInPolygon(item, plyB));
    if (!a) {
        b = plyB.some(item => isPointInPolygon(item, plyA));
    }
    return a || b;
}

/**
 * 判断两个多边形是否相交
 *
 * @param {Polygon} plyA-多边形A
 * @param {Polygon} plyB-多边形B
 * @returns {Boolean} 两个多边形是否相交
 * @example
 *  let A = [{x: 0, y: 4}, {x: 4, y: 4}, {x: -4, y: 0}, {x: 0, y: 0}];
 *  let B = [{x: 2, y: 6}, {x: 6, y: 6}, {x: 2, y: 0}, {x: 6, y: 0}];
 *  isPolygonsOverlap(A, B) -> true
 */
export function isPolygonsOverlap(plyA: Polygon, plyB: Polygon): Boolean {
    return isPolygonsIntersectant(plyA, plyB) || isPointInPolygonBidirectional(plyA, plyB);
}

/**
 * 判断两个多边形是否相交
 *
 * @param {Polygon} plyA-多边形A
 * @param {Polygon} plyB-多边形B
 * @returns {Boolean} 是否相交
 */
export function isPolygonsOverlaps(plyA: Polygon, plyB: Polygon): Boolean;

/**
 * 判断一个多边形是否与其他多边形是否相交
 *
 * @param {Polygon} plyA
 * @param {Array<Polygon>} plys
 * @returns {Boolean} 是否相交
 */
export function isPolygonsOverlaps(plyA: Polygon, plys: Array<Polygon>): Boolean;

/**
 * 判断多个多边形是否有相交
 *
 * @param {Polygon} plyA
 * @param {...Array<Polygon>} plys
 * @returns {Boolean} 是否相交
 */
export function isPolygonsOverlaps(...plys: Array<Polygon>): Boolean;

export function isPolygonsOverlaps(...plys: Array<Polygon> | [Polygon, Array<Polygon>] | [Polygon, Polygon]): Boolean {
    let flag = false;
    if (plys.length < 2) return flag;
    else if (plys.length > 2) {
        for (let i = 0; i < plys.length - 1; i++) {
            for (let j = i + 1; j < plys.length; j++) {
                if (isPolygonsOverlap(plys[i] as Polygon, plys[j] as Polygon)) flag = true;
            }
        }
        return flag;
    } else if (Array.isArray(plys[1])) {
        for (let i = 0; i < plys[1].length - 1; i++) {
            if (isPolygonsOverlap(plys[0] as Polygon, plys[1][i] as Polygon)) flag = true;
        }
        return flag;
    } else return isPolygonsOverlap(plys[0], plys[1]);
}

export default {
    isPolygonsOverlap,
    isPointInPolygonBidirectional,
    isPointInPolygon,
    isPolygonsIntersectant,
    isSegmentsIntersectant,
    isPolygonsOverlaps
};

标签:多边形,Polygon,plys,二维,判定,let,segA,segB
From: https://www.cnblogs.com/one-yutian/p/17474597.html

相关文章

  • 二维码qrcode插件
    一.安装npminstall--saveqrcode二.canvas绘制importQRCodefrom"qrcode";//选择二维码添加的元素constchild=this.$el.querySelector(".child");QRCode.toCanvas(value,options,(error,canvas)=>{if(error){throwerror;}child.app......
  • 任意多边形切割/裁剪(附C#代码实现)
    任意多边形切割/裁剪(附C#代码实现) 本实现主要参考了发表于2003年《软件学报》的《一个有效的多边形裁剪算法》(刘勇奎,高云,黄有群)这篇论文,所使用的理论与算法大都基于本文,对论文中部分阐述进行了详细解释,并提取了论文中一些重要的理论加以汇总。另外对于论文描述无法处理......
  • 射线法判断点是否在多边形内
    射线法isPointInPolygon方法用于判断点是否在多边形内部,points表示多边形各个点的坐标,point表示要判断的点的坐标publicclassPointInPolygon{/***判断点是否在多边形内部**@parampoints多边形各个点的坐标*@parampoint要判断的点的坐标......
  • 使用matlab的LTIViewer完成系统稳定性判定
    如题:一、建立模型:z=[-3];p=[0-2-5];k=3;G=zpk(z,p,k)G=3(s+3)-------------s(s+2)(s+5)Continuous-timezero/pole/gainmodel.ModelProperties>>Gf=feedback(G,1)Gf=3(s+3)--------------------------------......
  • 使用zxing来生成二维码
    使用zxing来生成二维码二维码已经成为了现代生活中不可或缺的一部分,无论是商业还是个人使用,二维码都有着广泛的应用。而在二维码的生成过程中,zxing是一款非常优秀的开源库,它提供了一系列的API,可以帮助我们快速、方便地生成二维码。接下来,我们就来介绍一下如何使用zxing来生成二......
  • 计算点二维A到线段B的垂线距离
    #include<iostream>#include<cmath>usingnamespacestd;//计算距离函数doubledistance(doublex1,doubley1,doublex2,doubley2){returnsqrt(pow(x1-x2,2)+pow(y1-y2,2));}//计算点A到线段B的垂线距离doubleperpendicularDistance(doubl......
  • 二维码测试点__肖sir__测试点整理
    二维码测试点==================================================功能测试1.扫描成功是否做出正确响应2.扫描失败是否有提示3.扫码进入页面显示是否正确,跳转链接是否正确4.保存扫码图片,是否支持长按图片识别进入5.只扫描部分时,是否扫描成功6.扫描模糊的二维码,能否扫描成功......
  • LeetCode----二维网格DFS
    1算法模板voiddfs(int[][]grid,intr,intc){//判断basecase//如果坐标(r,c)超出了网格范围,直接返回if(!inArea(grid,r,c)){return;}//访问上、下、左、右四个相邻结点dfs(grid,r-1,c);dfs(grid,r+1,c);......
  • 在前端生成H5二维码海报
    海报图片生成前后端都能实现,个人喜欢在前端生成,主要是前端可以用html+css去实现海报样式,便于调试,对于熟悉前端代码的小伙伴来说再好不过。以下是在vue项目中的实现,非vue前端同理。思路及步骤:1.用html实现海报效果制作海报模板图,用js二维码库生成二维码,用CSS的绝对定位实现二......
  • P5288 [HNOI2019]多边形
    P5288[HNOI2019]多边形Solution先进行大量的模拟。最终所有线段的端点均为点\(n\)。第一问答案为\((n-1-与n相连的线段数量)\)。可以把线段看成节点,将原图转为若干棵二叉树组成的森林。这里只建那些不与点\(n\)相连的非边线段。原操作可以看作是sp......