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

这里实现的方法是转载于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.mzph.cn/news/113489.shtml

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

相关文章

Python之爬虫

目录 HTTP请求HTTP响应获得页面响应伪装用户访问打包数据爬取豆瓣top250 HTTP请求 HTTP&#xff1a;HypertextTransferProtcol 超文本传输协议 1、请求行 POST/user/info?new_usertrue HTTP/1.1#资源了路径user/info 查询参数new_usertrue 协议版本HTTP/1.1 2、请求头 Ho…

element ui 下拉框 选择月份和天数

一、背景 目前做的管理系统项目&#xff0c;期望实现功能为&#xff1a;设置出账周期和出账日&#xff0c;考虑使用element ui下拉框实现功能 二、所用技术 vue2element ui 三、实现效果 四、具体代码 <template><popup-frame :title"批量设置出账日" …

Leetcode—2530.执行K次操作后的最大分数【中等】(C语言向上取整数学公式)

2023每日刷题&#xff08;五&#xff09; Leetcode—2530.执行K次操作后的最大分数 向上取整思想 参考了这篇文章 有人肯定会问&#xff0c;这个向上取整为什么是这样来的。接下来我简单讲解一下。 数学式&#xff1a; x y 数学式&#xff1a;\frac{x}{y} 数学式&#xff1a…

配置Linux

首先安装VMware&#xff1a; 安装说明&#xff1a;&#xff08;含许可证的key&#xff09; https://mp.weixin.qq.com/s/XE-BmeKHlhfiRA1bkNHTtg 给大家提供了VMware Workstation Pro16&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1q8VE3TkPzDnM3u9bkTdA_g 提取码&…

文件的物理结构(连续分配,链接分配,索引分配)

1.文件块&#xff0c;磁盘块 类似于内存分页&#xff0c;磁盘中的存储单元也会被分为一个个“块/磁盘块/物理块”。 很多操作系统中&#xff0c;磁盘块的大小与内存块、页面的大小相同。 内存与磁盘之间的数据交换&#xff08;即读/写操作、磁盘I/O&#xff09;都是以“块”为…

详细解读DALLE 3技术报告:Improving Image Generation with Better Captions

Diffusion models代码解读&#xff1a;入门与实战 前言&#xff1a;OpenAI是推动大模型创新的领头羊&#xff0c;最近发布的DALLE 3凭借着远超市面上其他图片生成模型的表现&#xff0c;再次火出圈。最近OpenAI官方发布了DALLE 3的技术报告《Improving Image Generation with B…

后缀表达式求值

题目要求: 后缀表达式求值&#xff1a;建立一个操作数栈S。然后从左到右读表达式&#xff0c;如果读到操作数就将它压入栈S中&#xff0c;如果读到n元运算符(即需要参数个数为n的运算符)则取出由栈顶向下的n项操作数进行运算&#xff0c;再将运算的结果代替原栈顶的n项压入栈中…

Catalan 数 和 Stirling 数

这个也可以理解为栈&#xff0c;用 ( 表示 入栈 &#xff0c; ) 表示出栈 , 任何情况下表示入栈的 ( 都必须大于等于 ) 的个数 这个思路和入栈出栈的思路是等价的

ms-sql server sql 把逗号分隔的字符串分开

案例&#xff1a; sql 查询-字段里是逗号,分隔开的数组&#xff0c;查询匹配数据 sql 查询-字段里是逗号,分隔开的数组&#xff0c;查询匹配数据_sql server 数组匹配-CSDN博客 SQL SERVER 把逗号隔开的字符串拆分成行 SQL SERVER 把逗号隔开的字符串拆分成行_sqlserver拆分…

【暴力剪枝】CF1708D

https://codeforces.com/contest/1708/problem/D 题意 思路 这样的操作下&#xff0c;数列减的速度是非常快的&#xff0c;也就是说&#xff0c;易出现很多的0&#xff0c;0的操作没啥意义&#xff0c;所以我们要找到第一个 >0 的数对其后的序列进行排序&#xff0c;就能大…

【Edabit 算法 ★☆☆☆☆☆】Power Calculator

【Edabit 算法 ★☆☆☆☆☆】Power Calculator math numbers Instructions Create a function that takes voltage and current and returns the calculated power. Examples circuitPower(230, 10) // 2300 circuitPower(110, 3) // 330 circuitPower(480, 20) // 9600Not…

大数据平台开发经验

如果我是一个有着10年大数据平台开发经验的开发者&#xff0c;面试时可能需要准备以下知识 大数据生态系统&#xff1a;** 熟悉大数据技术栈&#xff0c;如Hadoop、Spark、Flink等&#xff0c;了解它们的原理、用途和优劣势。 分布式系统设计&#xff1a; 深入了解分布式系统的…

java项目运行时信息获取

大体思路如下&#xff0c;想要获取启动时处理器数量、jvm 相关信息&#xff0c;操作系统信息、运行机器信息 运行机器信息 import org.slf4j.Logger; import org.slf4j.LoggerFactory;import java.lang.invoke.MethodHandles;/*** 机器工具类*/ public abstract class ServerU…

051校园短期闲置资源置换平台

大家好✌&#xff01;我是CZ淡陌。一名专注以理论为基础实战为主的技术博主&#xff0c;将再这里为大家分享优质的实战项目&#xff0c;本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目&#xff0c;希望你能有所收获&#xff0c;少走一些弯路…

git第一次推送出现推送被拒绝

前言 git 第一次推送出现以下错误 ! [rejected] master -> master (fetch first) error: failed to push some refs to ‘https://gitee.com/fengshangyunwang/iot-front-end.git’ hint: Updates were rejected because the remote contains work that you do hint: not …

Mac硬盘检测工具

Mac硬盘检测软件是一款用于检测和诊断Mac硬盘健康状态的工具&#xff0c;帮助用户及时发现潜在的硬盘问题&#xff0c;避免数据丢失和系统故障。通过全面的检测和报告功能&#xff0c;用户可以更好地了解自己的硬盘状况&#xff0c;确保数据的安全和可靠。给大家介绍几款好用的…

数字秒表VHDL启动暂停清零,源码和视频

名称&#xff1a;数字秒表VHDL启动暂停清零&#xff08;代码在文末付费下载&#xff09; 软件&#xff1a;Quartus 语言&#xff1a;VHDL 代码功能&#xff1a; 数字秒表 使用VHDL语言设置数字秒表。要求具有百分秒、秒和分钟显示,百分秒范围00-99,秒范围00-59,分钟范围0…

CMakeList 编写示例

cmake_minimum_required(VERSION 3.8) #指定cmake的最小版本 set(PROJECT_NAME Untitled_1) #初始化变量 project(${PROJECT_NAME} VERSION 1.0) #创建一个project set(CMAKE_AUTOMOC ON) #初始化内置变量, 该变量为Qt工程专属变量 set(CMAKE_AUTORCC ON) set(CMAKE_A…

【Python 千题 —— 基础篇】分割有效信息

题目描述 题目描述 有时候我们需要截取字符串以获取有用的信息&#xff0c;比如对于字符串 “日期&#xff1a;2010-10-29”&#xff0c;我们需要截取后面的 10 个字符来获取日期&#xff0c;以便进行进一步分析。编写一个程序&#xff0c;输入一个字符串&#xff0c;然后输出…

git仓删除当前仓且保留嵌套子仓--类似保留特定文件目录

当前git若有损坏需删除重新下载&#xff0c;但其还含有子仓&#xff0c;不能直接删除整体目录。清理方法如下&#xff1a; 分如下两种场景 1、若是子仓当前没有进行任何操作&#xff0c;即子仓可以临时移动 这种比较简单&#xff0c;分如下几步&#xff1a; step1:找到全部子…