Qt判断一个点在多边形内还是外(支持凸边形和凹变形)

Qt判断一个点在多边形内还是外(支持凸边形和凹变形)_qt 判断点是否在多边形内-CSDN博客

这里实现的方法是转载于https://blog.csdn.net/trj14/article/details/43190653和https://blog.csdn.net/WilliamSun0122/article/details/77994526
来实现的,并且按照Qt的规则进行了调整。
以下实现方法有四种,每种方法的具体讲解在转载的博客中有说明,这里不做重复阐述。
这里只说下代码的具体实现和每种方法的时间复杂度。

强烈推荐第一种方法,其它三种针对一些特殊图形或多或少都有一些问题。

方法一:射线法

时间复杂度:O(n) 。
适用范围:任意多边形。
优点:不需考虑精度误差和多边形点给出的顺序。
算法思想:以被测点Q为端点,向任意方向作射线(一般水平向右作射线),统计该射线与多边形的交点数。如果为奇数,Q在多边形内;如果为偶数,Q在多边形外。计数的时候会有一些特殊情况,如图

//判断点P在多边形内-射线法
bool Widget::InsidePolygon( QVector<QPointF> polygon,QPointF pt )
{int i,j;bool inside,redo;int N = polygon.size();redo = true;for (i = 0;i < N;++i){// 是否在顶点上if (polygon[i].x() == pt.x() && polygon[i].y() == pt.y()){redo = false;inside = true;break;}}while (redo){redo = false;inside = false;for (i = 0,j = N - 1;i < N;j = i++){if ( (polygon[i].y() < pt.y() && pt.y() < polygon[j].y()) ||(polygon[j].y() < pt.y() && pt.y() < polygon[i].y()) ){if (pt.x() <= polygon[i].x() || pt.x() <= polygon[j].x()){double _x = (pt.y()-polygon[i].y())*(polygon[j].x()-polygon[i].x())/(polygon[j].y()-polygon[i].y())+polygon[i].x();if (pt.x() < _x)          // 在线的左侧inside = !inside;else if (pt.x() == _x)    // 在线上{inside = true;break;}}}else if ( pt.y() == polygon[i].y()){if (pt.x() < polygon[i].x())    // 交点在顶点上{if (polygon[i].y() > polygon[j].y())pt.setY(pt.y() - 1);elsept.setY(pt.y() + 1);redo = true;break;}}else if ( polygon[i].y() ==  polygon[j].y() && pt.y() == polygon[i].y() &&((polygon[i].x() < pt.x() && pt.x() < polygon[j].x()) ||(polygon[j].x() < pt.x() && pt.x() < polygon[i].x())) )// 在水平的边界线上{inside = true;break;}}}return inside;
}

方法二:面积和判别法

时间复杂度:大于O(n)。
适用范围:所有凸边形,部分凹变形。
优点:算法简单。
缺点:有精度要求,强调多边形点给出的方向(逆时针)。
算法思想:如果点在多边形内部或者边上,那么点与多边形所有边组成的三角形面积和等于多边形面积。多边形的面积可以用叉积计算即连接坐标原点和各顶点形成向量,所有向量叉积的0.5的和即为多边形面积。不过计算面积是会有一定误差的,需要设置精度的误差范围。

//面积和判别法
bool InsidePolygon3( QVector<QPointF> polygon,QPointF pt )
{int i,j;bool inside = false;double polygon_area = 0;double trigon_area = 0;int N = polygon.size();for (i = 0,j = N - 1;i < N;j = i++){polygon_area += polygon[i].x() * polygon[j].y() - polygon[j].x() * polygon[i].y();trigon_area += abs(pt.x() * polygon[i].y() -pt.x() * polygon[j].y() -polygon[i].x() * pt.y() +polygon[i].x() * polygon[j].y() +polygon[j].x() * pt.y() -polygon[j].x() * polygon[i].y());}trigon_area *= 0.5;polygon_area = abs(polygon_area * 0.5);if ( fabs(trigon_area - polygon_area) < 1e-7 )inside = true;return inside;
}

方法三:点线判别法

时间复杂度:O(n)。
适用范围:所有凸边形,部分凹变形。
算法思想:对于多边形(正向,即逆时针),如果一个点它的所有有向边的左边,那么这个点一定在多边形内部。利用叉积正好可以判断点与给定边的关系,即点是在边的左边右边还是边上。

//点线判别法
bool InsidePolygon4( QVector<QPointF> polygon,QPointF p )
{int i,j;bool inside = false;int count1 = 0;int count2 = 0;int N = polygon.size();for (i = 0,j = N - 1;i < N;j = i++){double value = (p.x() - polygon[j].x()) * (polygon[i].y() - polygon[j].y()) - (p.y() - polygon[j].y()) * (polygon[i].x() - polygon[j].x());if (value > 0)++count1;else if (value < 0)++count2;}if (0 == count1 ||0 == count2){inside = true;}return inside;
}

方法四:角度和判别法

时间复杂度:O(n)。
适用范围:所有凸边形,部分凹变形。
优点:不强调多边形点给出顺序。
缺点:这个算法对精度的要求很高(会造成很大精度误差)。
算法思想:连接被测点与多边形所有顶点所形成的所有角的角度和在精度范围内等于则该点在多边形内,否则在多边形外。

// 根据需要不判断顶点
bool IsPointInLine( QPointF &pt,QPointF &pt1,QPointF &pt2 )
{bool inside = false;if (pt.y() == pt1.y() &&pt1.y() == pt2.y() &&((pt1.x() < pt.x() && pt.x() < pt2.x()) ||(pt2.x() < pt.x() && pt.x() < pt1.x())) ){inside = true;}else if (pt.x() == pt1.x() &&pt1.x() == pt2.x() &&((pt1.y() < pt.y() && pt.y() < pt2.y()) ||(pt2.y() < pt.y() && pt.y() < pt1.y())) ){inside = true;}else if ( ((pt1.y() < pt.y() && pt.y() < pt2.y()) ||(pt2.y() < pt.y() && pt.y() < pt1.y())) &&((pt1.x() < pt.x() && pt.x() < pt2.x()) ||(pt2.x() < pt.x() && pt.x() < pt1.x())) ){if (0 == (pt.y()-pt1.y())/(pt2.y()-pt1.y())-(pt.x() - pt1.x()) / (pt2.x()-pt1.x())){inside = true;}}return inside;
}//角度和判别法
bool InsidePolygon2( QVector<QPointF> polygon,QPointF p)
{int i,j;double angle = 0;bool inside = false;int N = polygon.size();for (i = 0,j = N - 1;i < N;j = i++){if (polygon[i].x() == p.x() &&    // 是否在顶点上polygon[i].y() == p.y()){inside = true;break;}else if (IsPointInLine(p,polygon[i],polygon[j]))    // 是否在边界线上{inside = true;break;}double x1,y1,x2,y2;x1 = polygon[i].x() - p.x();y1 = polygon[i].y() - p.y();x2 = polygon[j].x() - p.x();y2 = polygon[j].y() - p.y();double radian = atan2(y1,x1) - atan2(y2,x2);radian = abs(radian);if (radian > M_PI) radian = 2* M_PI - radian;angle += radian;            // 计算角度和}if ( fabs(6.28318530717958647692 - angle) < 1e-7 )inside = true;return inside;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/600847.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

24考研-东南大学916经验贴

文章目录 一、个人情况二、初试备考经验1.政治 67&#xff0c;客观382.英语 60&#xff0c;客观大概40左右3.数学 136&#xff0c;客观应该满分4.专业课 数据结构计网 114小分不清楚 三、复试备考经验笔试&#xff1a;C面试复试流程 附一下成绩单&#xff1a; 一、个人情况 本…

vue 中使 date/time/datetime 类型的 input 支持 placeholder 方法

一般在开发时&#xff0c;设置了 date/time/datetime 等类型的 input 属性 placeholder 提示文本时&#xff0c; 发现实际展示中却并不生效&#xff0c;如图&#xff1a; 处理后效果如图&#xff1a; 处理逻辑 判断表单项未设置值时&#xff0c;则设置其伪类样式&#xff0c;文…

postgresql发布和订阅

一、发布订阅介绍 发布和订阅使用了pg的逻辑复制的功能&#xff0c;通过发布端创建publication与表绑定&#xff0c;订阅端创建subscription同时会在发布端创建逻辑复制槽实现逻辑复制功能 逻辑复制基于 发布&#xff08;Publication&#xff09; 与 订阅&#xff08;Subscri…

低代码平台种草推荐

告别繁琐&#xff0c;拥抱未来&#xff01;只需简单拖拽&#xff0c;Vue代码即刻生成&#xff0c;一键下载&#xff0c;轻松上手。我们的低代码平台&#xff0c;不仅高效便捷&#xff0c;更完全开源&#xff0c;让你自由探索编程的无限可能&#xff01; 下载网址&#xff1a;ht…

three.js零基础入门超全超细的教程整理(一)

事情是这样的&#xff1a; 有一天 我干完活 看技术文章 发现了three.js 诶&#xff01;这玩应挺有意思 盘盘 于是第一天找教程 上官网 初上手 第二天 找案例 渲模型 试VR 第三天 捋文档 然后来活了 没时间捋了 下面是集百家精华教程的整理总结 涉及到教程方面有加源作者和地址…

前端用Scss简化媒体查询

1、演示 2、未优化前的代码 .header {width: 100px;height: 100px;background-color: red; } media (min-width: 320px) and (max-width: 480px) {.header {width: 10px;} } media (min-width: 320px) and (max-width: 480px) {.header {height: 20px;} } media (min-width: 48…

如何做接口测试呢?接口测试有哪些工具!

回想入职测试已经10年时间了&#xff0c;初入职场的我对于接口测试茫然不知。后来因为业务需要&#xff0c;开始慢慢接触接口测试。从最开始使用工具进行接口测试到编写代码实现接口自动化&#xff0c;到最后的测试平台开发。回想这一路走来感触颇深&#xff0c;因此为了避免打…

期货量化交易软件:模式搜索的暴力方法(第六部分)循环优化

概述 考虑到我上一篇文章中的材料&#xff0c;我赫兹量化软件可以说这只是我在算法中引入的所有函数的肤浅描述。它们不仅涉及EA创建的完全自动化&#xff0c;还涉及诸如结果优化和选择的完全自动化以及随后用于自动交易&#xff0c;或者我赫兹量化稍后将展示的更先进的EA的创…

Vscode 中调试Django程序

调试介绍: ​​​​​​​Explore the debugger Debug/调试 可以让我们在特定的代码行上暂停程序的运行。当程序暂停时&#xff0c;我们可以查看变量的数值&#xff0c;在“Debug控制台”中运行代码&#xff0c;或利用“Debug”工具提供的其他功能。启动Debugger/调试器会自动…

LeetCode-热题100:138. 随机链表的复制

题目描述 给你一个长度为 n 的链表&#xff0c;每个节点包含一个额外增加的随机指针 random &#xff0c;该指针可以指向链表中的任何节点或空节点。 构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成&#xff0c;其中每个新节点的值都设为其对应的原节点的值。…

Golang——方法

一. 方法定义 Golang方法总是绑定对象的实例&#xff0c;并隐式将实例作为第一实参。 只能为当前包内命名类型定义方法参数receiver可以任意命名。如方法中未曾使用&#xff0c;可省略参数名参数receiver类型可以是T或*T。基类型T不能是接口或指针类型(即多级指针)不支持方法重…

【随笔】Git 高级篇 -- 相对引用2 HEAD~n(十三)

&#x1f48c; 所属专栏&#xff1a;【Git】 &#x1f600; 作  者&#xff1a;我是夜阑的狗&#x1f436; &#x1f680; 个人简介&#xff1a;一个正在努力学技术的CV工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎咨询&#xff01; &#x1f496; 欢迎大…