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;
}相关文章:
Qt判断一个点在多边形内还是外(支持凸边形和凹变形)
这里实现的方法是转载于https://blog.csdn.net/trj14/article/details/43190653和https://blog.csdn.net/WilliamSun0122/article/details/77994526 来实现的,并且按照Qt的规则进行了调整。 以下实现方法有四种,每种方法的具体讲解在转载的博客中有说明&…...
MySQL导入数据库出现 Got error 168 from storage engine错误
“Got error 168 from storage engine” 是 MySQL 数据库的一个错误,通常是由于存储引擎发生了一些问题导致的。这个错误可能有多种原因引起。以下是一些可能的解决方法: 检查硬盘空间:确保目标数据库的服务器有足够的硬盘空间来执行导入操作…...
使用 VS Code 作为 VC6 的编辑器
使用 VS Code 作为 VC 6.0 的编辑器 由于一些众所周知的原因,我们不得不使用经典(过时)的比我们年龄还大的已有 25 年历史的 VC 6.0 来学习 C 语言。而对于现在来说,这个经典的 IDE 过于简陋,并且早已不兼容新的操作系…...
Peter算法小课堂—蠕动区间
蠕动区间 蠕动区间(尺取法、双游标)是一个经典的优化算法。 我们以毛毛虫🐛举例说明 具体的,我们看题目 例题 最小区间 这一题,我们用暴力法,复杂度O(N^2) 先给出暴力法代码 int ansn1; for(int tail…...
Vant和ElementPlus在vue的hash模式的路由下路由离开拦截使用Dialog和MessageBox失效
问题复现 ElementPlus:当点击返回或者地址栏回退时,MessageBox无效 <template><div>Element Plus Dialog 路由离开拦截测试</div><el-button type"primary" click"$router.back()">返回</el-button>…...
上海市通过区块链技术攻关 构建数字经济可信安全技术底座
日前,上海市印发《上海区块链关键技术攻关专项行动方案(2023—2025年)》(以下简称《行动方案》),提出到2025年,在区块链体系安全、密码算法等基础理论以及区块链专用处理器、智能合约、跨链、新…...
Java 面试题
昨天面试了两个Java开发程序员,问了一些问题,回答的不是很好,看看大家的回答如何,可以在评论区回复,测试下自己的水平。 A程序员: 1. 自我介绍一下; 2. 企业级和互联网行业都有那些项目经验,简…...
layui 表格 展开
一、表格嵌套表格(手风琴打开) <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><title>设备上下线统计</title><script type"text/javascript" src"../../../l…...
[尚硅谷React笔记]——第4章 React ajax
目录: 脚手架配置代理_方法一 server1.js开启服务器server1:App.js解决跨域问题:脚手架配置代理_方法二 server2.js开启服务器server2第一步:创建代理配置文件编写setupProxy.js配置具体代理规则:App.js运行结果&a…...
Richard Stallman 正在与癌症作战
导读为了纪念 GNU 项目成立 40 周年,自由软件基金会(FSF)已计划在 10 月 1 日(即GNU 40)为家庭、学生以及美国的其他人群组织一场黑客马拉松活动。 活动之前,GNU 项目于 9 月 27 日迎来了 40 岁生日&#…...
MathType7.4最新免费版(公式编辑器)下载安装包附安装教程
MathType是一款专业的数学公式编辑器,理科生专用的必备工具,可应用于教育教学、科研机构、工程学、论文写作、期刊排版、编辑理科试卷等领域。可视化公式编辑器轻松创建数学方程式和化学公式。兼容Office Word、PowerPoint、Pages、Keynote、Numbers 等7…...
如何支持h.265视频
前言 略 h.265视频 h.265是一种视频编码格式。 随着视频编码技术的发展,相比H.264, H.265同等画质体积仅为一半、带宽占用省一半、画质更细腻等诸多优势。 但Web浏览器还不支持H.265的解码播放,因此基于Web Assembly(封装FFmpeg)、JS解封装、Canvas投…...
vue 放大镜(简易)
目录 zoom组件 <template><div class"pic-img"><div class"img-container"><img ref"img" load"imgLoaded" :src"url" :style"overlayStyle" error"imgerrorfun"/><div cl…...
【计算机网络】第一章——概述
个人主页直达:小白不是程序媛 系列专栏:计算机网络基础 目录 前言 计算机网络概述 概念 功能 组成 分类 标准化工作 性能指标 速率 带宽 吞吐量 时延 时延带宽积 往返时延RTT 利用率 分层 为什么要分层? 分层的基本原则&am…...
vue实现在页面拖拽放大缩小div并显示鼠标在div的坐标
1、功能要求: 实现在一个指定区域拖拽div,并可以放大缩小,同时显示鼠标在该div里的坐标,如图可示 缩小并拖动 2、实现 <div class"div_content" ref"div_content"><div class"div_image" id"…...
LuatOS-SOC接口文档(air780E)-- io - io操作(扩展)
示例 -- io模块是lua原生模块,LuatOS增加了一些API -- 请配合os模块一起使用-- 只读模式, 打开文件 local fd io.open("/xxx.txt", "rb") -- 读写默认,打开文件 local fd io.open("/xxx.txt", "wb") -- 写入文件,且截断为0字节 loc…...
【数据结构】线性表(六)堆栈:顺序栈及其基本操作(初始化、判空、判满、入栈、出栈、存取栈顶元素、清空栈)
文章目录 一、堆栈1. 定义2. 基本操作 二、顺序栈0. 顺序表1. 头文件和常量2. 栈结构体3. 栈的初始化4. 判断栈是否为空5. 判断栈是否已满6. 入栈7. 出栈8. 查看栈顶元素9. 清空栈10. 主函数11. 代码整合 堆栈Stack 和 队列Queue是两种非常重要的数据结构,两者都是特…...
父组件可以监听到子组件的生命周期吗?
在 Vue 中,父组件是可以监听到子组件的生命周期的。Vue 提供了一些特殊的钩子函数,可以在父组件中监听子组件的生命周期事件。 以下是一些常用的方法来监听子组件的生命周期: 1:使用$emit: 在子组件的生命周期钩子函数中,使用 $emit 方法触发自定义事件,向父组件发送通…...
[开源]MIT开源协议,基于Vue3.x可视化拖拽编辑,页面生成工具
一、开源项目简介 AS-Editor 基于 Vue3.x 可视化拖拽编辑,页面生成工具。提升前端开发效率,可集成至移动端项目作为通过定义 JSON 直接生成 UI 界面。 二、开源协议 使用MIT开源协议 三、界面展示 四、功能概述 基于Vue可视化拖拽编辑,…...
【C++ Primer Plus学习记录】数组的替代品
目录 1.模板类vector 2.模板类array(C11) 3.比较数组、vector对象和array对象 模板类vector和array是数组的替代品。 1.模板类vector 模板类vector类似于string类,也是一种动态数组。您可以在运行阶段设置vector对象的长度,可…...
19c补丁后oracle属主变化,导致不能识别磁盘组
补丁后服务器重启,数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后,存在与用户组权限相关的问题。具体表现为,Oracle 实例的运行用户(oracle)和集…...
[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解
突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 安全措施依赖问题 GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...
装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...
Flask RESTful 示例
目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题: 下面创建一个简单的Flask RESTful API示例。首先,我们需要创建环境,安装必要的依赖,然后…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...
BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...
【C++特殊工具与技术】优化内存分配(一):C++中的内存分配
目录 一、C 内存的基本概念 1.1 内存的物理与逻辑结构 1.2 C 程序的内存区域划分 二、栈内存分配 2.1 栈内存的特点 2.2 栈内存分配示例 三、堆内存分配 3.1 new和delete操作符 4.2 内存泄漏与悬空指针问题 4.3 new和delete的重载 四、智能指针…...
【JVM面试篇】高频八股汇总——类加载和类加载器
目录 1. 讲一下类加载过程? 2. Java创建对象的过程? 3. 对象的生命周期? 4. 类加载器有哪些? 5. 双亲委派模型的作用(好处)? 6. 讲一下类的加载和双亲委派原则? 7. 双亲委派模…...
wpf在image控件上快速显示内存图像
wpf在image控件上快速显示内存图像https://www.cnblogs.com/haodafeng/p/10431387.html 如果你在寻找能够快速在image控件刷新大图像(比如分辨率3000*3000的图像)的办法,尤其是想把内存中的裸数据(只有图像的数据,不包…...
云安全与网络安全:核心区别与协同作用解析
在数字化转型的浪潮中,云安全与网络安全作为信息安全的两大支柱,常被混淆但本质不同。本文将从概念、责任分工、技术手段、威胁类型等维度深入解析两者的差异,并探讨它们的协同作用。 一、核心区别 定义与范围 网络安全:聚焦于保…...
