最近做了一个算法题【盒马配货】:

(题目大意)盒马店的配送范围由一些点组成的多边形确定,给定一个点判断其是否在配送范围内,若在,则此点不需要挪动,打印"no 0";若不在,则给出此点需要挪动到配送范围的最短距离,打印"yes 距离"。

如何求解点到多边形的距离

此题求解需要解决两个问题:

  • 点到多边形的边的最短距离。
  • 点是否包含在多边形内。

点到边的距离

计算点到多边形最短距离的基本原理是:依次计算点到多边形每条边的距离,然后筛选出最短距离。

如下图,假设AB为多边形的一条边,现在求点P到AB的距离。

根据向量内积公式(\vec a \cdot \vec b=|a||b|\cos\theta),我们可以推出:

根据以上公式,我们可以求出t,进而求出点D的坐标,最终PD的长度就很容易求得了。

但是还有一些边界条件需要注意,即最终D点不是落在AB上,有以下三种情况:

  • t < 0,D在BA延长线上,此时最短距离取PA;
  • 0 <= t <= 1,D在AB上,此时最短距离取PD;
  • t > 1,D在AB延长线上,此时最短距离取PB;

Java实现代码如下:

private static double pointToSegmentDist(double px, double py, double ax, double ay, double bx, double by) {double ABx = bx - ax;double ABy = by - ay;double APx = px - ax;double APy = py - ay;double AB_AP = ABx * APx + ABy * APy;double distAB2 = ABx * ABx + ABy * ABy;double Dx = ax, Dy = ay;if (distAB2 != 0) {double t = AB_AP / distAB2;if (t >= 1) {Dx = bx;Dy = by;} else if (t > 0) {Dx = ax + ABx * t;Dy = ay + ABy * t;} else {Dx = ax;Dy = ay;}}double PDx = Dx - px, PDy = Dy - py;return Math.sqrt(PDx * PDx + PDy * PDy);
}

点是否包含在多边形内

根据W. Randolph Franklin 提出的PNPoly算法,只需区区几行代码就解决了这个问题。

假设配送范围多边形的点横纵坐标分别存放在两个数组xs、ys里,(x,y)表示配送点的坐标,先贴代码:

private static void polygon(double[] xs, double[] ys, double x, double y) {boolean contained = false; // 点是否包含在多边形内double xMin = Arrays.stream(xs).min().getAsDouble();double xMax = Arrays.stream(xs).max().getAsDouble();double yMin = Arrays.stream(ys).min().getAsDouble();double yMax = Arrays.stream(ys).max().getAsDouble();if (x > xMax || x < xMin || y > yMax || y < yMin) {contained = false;}// 核心算法部分int N = xs.length;double dist = Double.MAX_VALUE;for (int i = 0, j = N - 1; i < N; j = i++) {if (((ys[j] > y) != (ys[i] > y))&& (x < (xs[j] - xs[i]) * (y - ys[i]) / (ys[j] - ys[i]) + xs[i])) {contained = !contained;}dist = Math.min(dist, pointToSegmentDist(x, y, xs[i], ys[i], xs[j], ys[j]));}System.out.println(contained ? "no 0" : "yes" + " " + dist);
}

首先,我们需要取得该数组在横坐标和纵坐标的最大值和最小值,根据这四个点算出一个四边型,判断目标坐标点是否在这个四边型之内,如果在这个四边型之外,那可以跳过后面较为复杂的计算,直接返回false。

if (x > xMax || x < xMin || y > yMax || y < yMin) {contained = false;
}

接下来是核心算法部分:

for (int i = 0, j = N - 1; i < N; j = i++) {if (((ys[j] > y) != (ys[i] > y))&& (x < (xs[j] - xs[i]) * (y - ys[i]) / (ys[j] - ys[i]) + xs[i])) {contained = !contained;}
}

每次计算都涉及到相邻的两个点和待测试点,然后考虑两个问题:

  • 被测试点的纵坐标testy是否在本次循环所测试的两个相邻点纵坐标范围之内,即

    ys[i] <y < ys[j]

    或者

    ys[j] <y < ys[i]。

  • 待测点test是否在i,j两点之间的连线之下(相交判断)。

每次这两个条件同时满足的时候我们把返回的布尔量取反

这个表达式的意思是说,随便画个多边形,随便定一个点,然后通过这个点水平划一条线,先数数看这条横线和多边形的边相交几次(可先排除那些不相交的边,即第一个判断条件),然后再数这条横线穿越多边形的次数是否为奇数,如果是奇数,那么该点在多边形内,如果是偶数,则在多边形外(射线法)。

点在直线下 - 相交判断

如下图,ab与过p点的水平线相交于c,

则有:

Java代码实现:

if (((ys[j] > y) != (ys[i] > y))&& (x < (xs[j] - xs[i]) * (y - ys[i]) / (ys[j] - ys[i]) + xs[i])) {contained = !contained;
}

点在多边形内部 - 射线法

判断点是否在多边形内,可以从这个点做一条射线,计算它跟多边形边界的交点个数,如果交点个数为奇数,那么点在多边形内部,否则点在多边形外。参考https://www.cnblogs.com/anningwang/p/7581545.html

参考

https://wrf.ecse.rpi.edu//Research/Short_Notes/pnpoly.html

https://www.cnblogs.com/anningwang/p/7581545.html

https://jingsam.github.io/2016/09/26/polydist.html

(完)

算法 - PNPoly解决点到多边形距离的问题相关推荐

  1. python点到多边形距离,点到轮廓距离

    python点到多边形距离 最简单例子: 负数表示在多边形外,正数代表多边形内. 要求:hull的数据必须是int类型,不能是float类型. import numpy as nppoint=(7,7 ...

  2. POJ 1584 A Round Peg in a Ground Hole 判断凸多边形,点到线段距离,点在多边形内

    ACM博客_kuangbin POJ 1584 A Round Peg in a Ground Hole(判断凸多边形,点到线段距离,点在多边形内) A Round Peg in a Ground H ...

  3. HDU3662(求三维凸包表面的多边形个数,表面三角形个数,体积,表面积,凸包重心,凸包中点到面的距离)

    题目:3D Convex Hull   题意:给定空间中的n个点,求这n个点形成的凸包的表面的多边形个数. 增量法求解:首先任选4个点形成的一个四面体,然后每次新加一个点,分两种情况: 1> 在 ...

  4. 依据地图上的经纬度坐标计算某个点到多边形各边的距离

    http://www.th2w.com/article/85 依据地图上的经纬度坐标计算某个点到多边形各边的距离 最近公司有一个需求:依据地图上的经纬度坐标计算某个点到多边形各边的距离. 主要原理: ...

  5. 为什么a*算法采用哈密尔顿距离作为启发函数比不在位数为启发函数的性能要好?_【论文研读】路径规划中的Hybrid A*算法...

    本文目的 由于在carla-autoware的示例中使用了hybrid A* 算法,所以本文基于以下两篇文章对hybrid A* 算法过程进行整理:(文中挑选了一些个人认为便于理解算法的图片,均来自于 ...

  6. 【MATLAB】求点到多边形的最短距离

    文章目录 0.引言 1.原理 2.代码及实用教程 0.引言 \qquad点与多边形的关系无非三种--内部.上.外部.本文定义点在多边形内部距离为负,点在多边形边上距离为0,到多边形外部距离为正. 1. ...

  7. [原创]物探小宽线坐标快速生成(平行线坐标互算 、点到线距离计算、两线交点计算等)...

    界面如下: 下载地址:CSDN 功能简介: 主要是解决并简化各项目中坐标(特别是是斜测线坐标方程组)的重复脑残计算问题,降低脑残机率,为懒而生 1.对于斜线.规则线坐标理论快速生成等 2.两线交点的标 ...

  8. 蚁群算法解决tsp问题python_蚁群算法在解决TSP问题中的应用

    陈灵佳 文章首先对蚁群算法与TSP问题进行简要介绍,在此基础上对蚁群算法在解决TSP问题中的应用进行论述.期望通过本文的研究能够对TSP问题的解决有所帮助. [关键词]蚁群算法 TSP问题 最优解 1 ...

  9. 叉积求点到平面距离_OpenCV计算点到直线的距离 数学法

    我们在检测图像的边缘图时,有时需要检测出直线目标,hough变换检测出直线后怎么能更进一步的缩小区域呢?其中,可以根据距离来再做一判断,就涉及到了点与直线的距离问题. 点到直线距离代码如下: //== ...

最新文章

  1. JDBC连接各种数据库方法
  2. excel两个指标相关性分析_Excel实操分析函数,投资决策指标的假设分析,就是那么简单...
  3. 生成器模式(Builder)解析例子
  4. C++ Set常用用法
  5. php信息采集开发,程序php信息采集程序代码
  6. 统计学习方法第三章作业:一般k邻近、平衡kd树构造、kd树邻近搜索算法代码实现
  7. 查询大于2分钟的数据
  8. Codeforces Round #722 (Div. 2)
  9. 如何使用悲观锁定修复乐观锁定竞争条件
  10. 11054 - Wine trading in Gergovia
  11. Grafana 中存在严重的未授权任意文件读取漏洞,已遭利用
  12. Rust: Integers: Recreation One
  13. TypeError: only size-1 arrays can be converted to Python scalars 报错如何解决
  14. 阅读整理笔记,正能量
  15. 【Java--日期的使用】
  16. 【纪中集训2019.3.30】星辰大海
  17. 如何取消服务器自动关机,服务器自动关机求助
  18. 日语常用语3000句
  19. Windows11镜像网盘链接
  20. 编译原理Antlr教程

热门文章

  1. (一)JAVA基于OPENXML的word文档插入、合并、替换操作系列之基础篇
  2. 使用ONNXRuntime部署阿里达摩院开源DAMO-YOLO目标检测,一共包含27个onnx模型(代码开源)...
  3. Thinkphp5的项目配置到西部数码虚拟主机
  4. 计算机会计实务好学吗,会计电算化难吗
  5. 基于matlab的RS编译码仿真,从底层原理分析RS编译码的实现过程
  6. 简单linux命令之备份文件
  7. 【常用软件】Ubuntu-划词翻译软件Stardict
  8. [因果推断] 学习资料汇总
  9. (附源码)springboot客户信息管理系统 毕业设计 181936
  10. 视频基础知识—720P/1080i/1080P