判断两个多边形相交的面积_点与多边形

乍一看这标题,多像是中学数学课本里的章节标题。

点和多边形就是本文的两位主角。本文主要探讨的问题是:如何判断点在多边形内部

如果要判断点是否在矩形或者圆内部,其实很简单。

a4f1a4d3741704379bb40396767ab04c.png
/**
 * 勾股定理
 * 圆心:cx, cy
 * 半径: r
 */

const inside = (p.x - cx) ** 2 + (p.y - cy) ** 2 <= r ** 2

/**
 * 矩形
 * 左上角坐标: x, y
 * 宽高: w, h
 */
 
 const inside = (p.x - x) <= w && (p.y - y) <= h

说完了简单的,下面进入正题。

1743a429f2db7d2ce69311a656187e30.png

如何判断P1, P2, P3在三角形内(外)呢?

这里向大家介绍的方法叫Winding Number (wn) 。

25a1ac6003210110383f3f640ac9887f.png

由目标点水平向右发出射线,如果多边形的边向上穿过这条射线计数 +1,向下穿过射线则 -1

很难想象?看下图就明白了。

1ff6174241305bbf04eaa66ec292c937.png

从上图可以看出wn = 0时则点在多边形外。

图看明白了,怎么用代码实现呢?

在这之前,先了解一下如何判断点在有向线段的左(右)边还是在线段上。这是实现上面算法的关键。

d89d087b8f0cf5bc9303ed504df9ed8c.png

从上图可以看出:

  1. P在线段BA的左边,在线段CD的右边。
  2. E在线段BA的右边,在线段CD上。

不多废话了,直接上代码。

/**
 * @param {Array<number>} p - 点坐标: [x, y]
 * @param {Array<number>} p1 - 线段起点: [x, y]
 * @param {Array<number>} p2 - 线段终点: [x, y]
 * @return {number} 
 * 0: p 在线段上 
 * <0: p 在线段右侧
 * >0: p 在线段左侧
 */
 // Y 轴正方形向下则 p1,p2 位置调换
function calc(p, p1, p2) {
  return (p1[0] - p2[0]) * (p[1] - p2[1]) - (p[0] - p2[0]) * (p1[1] - p2[1])
}

也可以简单验证一下:

// P@BA: -52
calc([42, 12], [46, 6], [48, 16])
// E@CD: 0
calc([53, 11], [52, 16], [54, 6])

回到点与多边形的判断。这里直接上代码了。因为代码很简单。

/**
 * @param {Array<number>} point - 点坐标: [x, y]
 * @param {Array<number>} points - 多边形坐标点: [x1,y1, x2,y2, x3,y3...]
 */
function wind(point, points) {
  let wn = 0
  for (let i = 0; i < points.length; i += 2) {
    const
      p1 = [points[i], points[i + 1]],
      p2 = i + 2 === points.length ? [points[0], points[1]] : [points[i + 2], points[i + 3]]

    if (point[1] >= p1[1]) {
      if (point[1] < p2[1] && calc(point, p1, p2) > 0) wn++
    } else if (point[1] >= p2[1] && calc(point, p1, p2) < 0) wn--
  }
  return wn
}

简单解释一下为什么会有关于Y轴坐标的判断:

if (point[1] >= p1[1]) {
  if (point[1] < p2[1] && calc(point, p1, p2) > 0) wn++
} else if (point[1] >= p2[1] && calc(point, p1, p2) < 0) wn--

e392e6d04c0fb918e62e64e930b781a9.png

通过calc计算的结果可知:P2在线段a的左边,但实际上发出的射线并没有与线段a相交。考虑线段e,d的情况,即代码中的约束条件

在线示例:https://codepen.io/jerald/full/OJLOqwv

c43d217d34d4cc0deda7efedda57a70f.gif

参考资料

  • http://geomalgorithms.com/a03-_inclusion.html
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值