首页 > 其他分享 >如何判断一个点在地图上?如何判断一个点在多边形内?

如何判断一个点在地图上?如何判断一个点在多边形内?

时间:2023-09-30 14:44:06浏览次数:42  
标签:判断 多边形 var points y0 y1 一个点 y2

highlight: a11y-dark

近期,有接手到一个echarts地图图表项目,因为采集的散点数据很多打不到准确的地图点上,故有了这个问题。

一般而言,标题的两个问题其是同一个问题,因为对与一个地图数据,也就是geoJson来说,其实就是一个有很多个点的多边形。

目前来说判断点是否在一个多边形内,江湖上流传的主要方法有射线法,面积法,叉积(凸多边形)等等很多方法。但就笔者看各种技术文章,以及多方探(bai)索(du)研究(google)的情况下来看,射线法是比较常用的一种,基于射线法又派生出奇偶规则(Odd-even Rule)非零环绕数规则(Nonzero Winding Number Rule)

全文可能就只会用到一个数学公式直线方程的两点式:

\(\frac{y-y2}{y1-y2} = \frac{x-x2}{x1-x2}\)

射线法

基本思想: 所谓射线法,就是指,从被测点引出一条射线,而后判断与多边形的交点。与边的交点的个数决定了当前点是否在多边形内,这是奇偶规则与非零环绕数规则的共同点,两者的不同点在于是否考虑被交边的方向以及对点的交点个数的判断。

奇偶规则(Odd-even Rule)

所谓奇偶规则是指,若交点数为奇数则点在多边形内,否则点在多边形外。

图示:

image

代码示例

/**
 * 
 * @param {*} param0 [number,number]
 * @param {*} points [number,number][]
 * @returns 
 */
function oddEvenRule([x,y], points) {

  let ans = false;
  if (points.length < 3) {
    return ans;
  }

  for (let i = 0, L = points.length - 1; i < L; i++ ) {
    const point1 = points[i];
    const point2 = points[i+1]

    const [x1, y1] = point1;
    const [x2, y2] = point2;

    if (y < Math.min(y1, y2) || y > Math.max(y1, y2)) { // 限定 y 在  y1 及y2之间
      continue;
    }
    // 在 point1及point2确定的直线上,根据待测点的y,求出交点坐标x
    // 直线方程。两点式(y-y2)/(y1-y2) = (x-x2)/(x1-x2)
    let crossoverX = (y - y2) * (x1 - x2) /(y1 - y2) + x2;
    if (y1 === y2) { // 水平边的交点即为待测点的坐标 暂时先不管了 感兴趣可以自己处理一下
      // crossoverX = x;
      continue;
    }
    if (crossoverX > x) { // 只考虑一个方向
      ans = !ans; 
    }

  }

  return ans;
    
}

判断一般的多边形,奇偶规则判断就够了,但是奇偶规则有个限制,就是一个多边形有多部分构成的时候,考虑如下场景:
image

此时再使用奇偶规则去判断就不能准确判断了,由此引出下面一个方法:

非零环绕数规则(Nonzero Winding Number Rule)

所谓非零环绕,是指,基于射线法,当射线穿过多边形边的时候,根据多边形边的方向,给总的交点数加1或者减1,最后判断总的节点数是不是0,不是0则为多边形内部,否则就是多边形外部。

图示:

image

可以看到非零环绕规则很好的解决了上边的问题

代码示例

这里援引一下zRender的contain源码

var EPSILON = 1e-8;
function isAroundEqual(a, b) {
    return Math.abs(a - b) < EPSILON;
}
function contain(points, x, y) {
    var w = 0;
    var p = points[0];
    if (!p) {
        return false;
    }
    for (var i = 1; i < points.length; i++) {
        var p2 = points[i];
        w += windingLine(p[0], p[1], p2[0], p2[1], x, y);
        p = p2;
    }
    // Close polygon
    var p0 = points[0];
    if (!isAroundEqual(p[0], p0[0]) || !isAroundEqual(p[1], p0[1])) {
        w += windingLine(p[0], p[1], p0[0], p0[1], x, y);
    }
    return w !== 0;
}
function windingLine(x0, y0, x1, y1, x, y) {
    if ((y > y0 && y > y1) || (y < y0 && y < y1)) {
        return 0;
    }
    // Ignore horizontal line
    if (y1 === y0) {
        return 0;
    }
    var t = (y - y0) / (y1 - y0);
    var dir = y1 < y0 ? 1 : -1;
    // Avoid winding error when intersection point is the connect point of two line of polygon
    if (t === 1 || t === 0) {
        dir = y1 < y0 ? 0.5 : -0.5;
    }
    var x_ = t * (x1 - x0) + x0;
    // If (x, y) on the line, considered as "contain".
    return x_ === x ? Infinity : x_ > x ? dir : 0;
}

标签:判断,多边形,var,points,y0,y1,一个点,y2
From: https://www.cnblogs.com/ZiLongZiLong/p/17144887.html

相关文章

  • Bash-条件判断(文件判断,整型/字符串判断)
    按文件类型判断红框常用 使用方式:test-e/root/install.log[-e/root/install.log]#[前后有空格]常用判断,比如判断root是否为目录[-d/root]&&echo"yes"||echo"no" 按文件权限判断 例子:若有student.txt权限如下:-rw-r--r--;不能判断是哪个是否......
  • JS判断字符串是否全为空
    1、使用trim()方法trim()方法会去除首尾空格,并返回一个处理后的新值<template><divclass="box">content</div></template><scriptsetup>import{ref,reactive,toRefs,watch,computed,defineProps,}from'vue';import{useStore}......
  • JS的循环、判断,选择语句
    1、选择语句switch(条件){casea:caseb:casec:cased:default:}2、判断语句letflag=true;if(flag){document.write("这是真的");}else{document.write("这是假的")}3、JS的循环语句3.1、while循环while(循环条件){}3.2......
  • false == ''在js中为何判断为true
    当用==操作符将false对象和其他对象进行比较的时候只有0和空字符串、空数组等于false;undefined和null对象并不等于false对象,而null和undefined是相等的。letcompleted=false;console.log(completed==0);console.log(completed=='');console.log(completed......
  • 如何优雅地类型转换和非空判断
    提问如何优雅地类型转换和非空判断回答使用模式匹配......
  • vue,用户可操作权限判断,数据创建人判断
    需求:需要判断登录用户是否有对应的操作权限,有则显示对应的操作入口。判断某物的创建人是否为当前用户,是则可进行删除或修改操作。  调用以下函数。userId为当前登录的用户id;   ......
  • 向目标输入框输入值(WebDriverWait判断是否有该输入框)
    #导包fromseleniumimportwebdriverfromselenium.webdriver.common.byimportByfromtimeimportsleepfromselenium.webdriver.support.uiimportWebDriverWaitfromselenium.webdriver.supportimportexpected_conditionsasEC#浏览器驱动driver=webdriver.Ch......
  • C# 枚举使用[Flags] 特性形成一个位掩码及判断是否存在某个枚举组合
    在C#中,通过给枚举类型添加 [Flags] 特性,可以指示该枚举类型是用于表示位标志的枚举。使用带有 [Flags] 特性的枚举类型允许将多个枚举值组合在一起,形成一个位掩码,提供了一种更方便和可读性更好的方式来表示多个选项的组合。当给枚举类型添加 [Flags] 特性后,可以使用按位或......
  • JavaScript——判断0, NaN, false, null, underfined, 空字符串
    1.判断NaN//NaN出现的原因:(NotaNumber)//操作两个类型不一致的数、用NaN值计算最终得到NaN、不合法运算(如0/0)letnum=0/0;if(isNaN(num)){console.log("num为NaN!")}2.判断undefinedlettemp=undefined//方法一if(typeof(temp)=="undefined"......
  • 取模算术运算符-应用1-判断一个数能否被另外一个数整除
    C语言中判断一个整数能否被另外一个整数整除,可以使用取模运算符%。不能直接使用两个整数相除来进行计算,因为直接使用两个整数相除,结果只会保留整数,会舍弃掉小数部分。比如使用C语言计算11/2结果为5,但是11是不能被2整除的,计算结果舍弃掉了小数部分。因此需要使用取余运算符。示......