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

news2024/11/17 1:59:04

这里实现的方法是转载于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);
                    else
                        pt.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.coloradmin.cn/o/1113516.html

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

相关文章

低代码到底是什么?

究竟什么样的新技术&#xff0c;才能真正解放IT生产力&#xff0c;加速社会数字化转型&#xff0c;Make The World Great Again&#xff1f;我认为是低代码&#xff08;Low-Code&#xff09;。 “Low-Code”是什么&#xff1f;“Code”是指代码&#xff0c;但这个“Low”字是啥…

DFS(分布式文件系统)与 DFSR(分布式文件系统复制)的区别

DFS&#xff08;分布式文件系统&#xff09;和 DFSR&#xff08;分布式文件系统复制&#xff09;是两种不同的技术&#xff0c;尽管它们在名称上有一些相似之处&#xff0c;但它们的用途和功能有所不同。 DFS&#xff08;分布式文件系统&#xff09; DFS 是一种用于创建和管理…

tinker官网加载demo的使用流程

tinker官网加载demo的使用流程 0&#xff0c;首先开接入指南&#xff1a; https://github.com/Tencent/tinker/wiki/Tinker-%E6%8E%A5%E5%85%A5%E6%8C%87%E5%8D%97 1&#xff0c;在gradle 找到tinker的插件&#xff0c;来判断tinker是否集成成功。 2&#xff0c;安装一个现在有…

TikTok:年轻一代的创新驱动力与社会影响

在当今数字媒体和社交网络的时代&#xff0c;TikTok已经崭露头角&#xff0c;成为一个风靡全球的短视频平台&#xff0c;尤其受到年轻一代的热烈欢迎。 但TikTok不仅仅是一个娱乐应用&#xff0c;它也代表着年轻一代的创新驱动力和社会影响力的集大成者。本文将深入探讨TikTok…

【微信小程序】6天精准入门(第4天:自定义组件及案例界面)附源码

一、自定义组件 1、介绍 从小程序基础库版本 1.6.3 开始&#xff0c;小程序支持简洁的组件化编程。所有自定义组件相关特性都需要基础库版本 1.6.3 或更高。 开发者可以将页面内的功能模块抽象成自定义组件&#xff0c;以便在不同的页面中重复使用&#xff1b;也可以将复杂的页…

LiveQing视频点播流媒体RTMP推流服务功能-支持视频点播分屏大屏展示视频轮巡分组播放RMP推流直播大屏展示

LiveQing支持视频点播分屏大屏展示视频轮播分组播放RMP推流直播大屏展示 1、分屏展示2、轮巡播放3、RTMP推流视频直播和点播流媒体服务 1、分屏展示 LiveQing支持将视频点播、鉴权直播&#xff0c;拉转直播视频流&#xff0c;进行分屏播放。 2、轮巡播放 3、RTMP推流视频直播和…

CRC16计算FC(博途SCL语言)

CRC8的计算FC,相关链接请查看下面文章链接: 博途SCL CRC8 计算FC(计算法)_博途怎么计算crc_RXXW_Dor的博客-CSDN博客关于CRC8的计算网上有很多资料和C代码,这里不在叙述,这里主要记录西门子的博途SCL完成CRC8的计算过程, CRC校验算法,说白了,就是把需要校验的数据与多项式…

企业数字化转型时,会遇到的5大挑战

企业数字化转型时&#xff0c;会遇到的5大挑战添加链接描述 数字化转型已然是当今商业战略的一大基石&#xff0c;根据Gartner的《2023年度董事会调查》显示&#xff0c;有89%的企业将数字业务视为其增长的核心。但该研究的另一项统计数据也显示&#xff1a;在这些企业中&…

会议OA小程序【会议管理,个人中心页面布局】

目录 一. 自定义组件介绍 1.1 概念 1.2 创建自定义组件 二. 会议管理页面布局 使用自定义组件 页面布局及样式 三. 个人中心页面布局 一. 自定义组件介绍 1.1 概念 从小程序基础库版本 1.6.3 开始&#xff0c;小程序支持简洁的组件化编程。所有自定义组件相关特性都需…

新服务入驻生产环境 CICD 全流程、自动化脚本教程

文章目录 背景CICD百花齐放 “四部曲”实现优势涉及文件核心流程ci.ymlMakefilepackage.shnoah_control 小结 背景 新服务功能完成测试后&#xff0c;将会进行生产环境的入住&#xff0c;对外提供产品、功能支持。那么如何规范的、安全的、自动化的把本地服务移植到生产环境呢…

uniapp无感刷新token实现过程

路漫漫其修远兮&#xff0c;前端道路逐渐迷茫&#xff0c;时隔好久好久终于想起了我还有一个小博客&#xff0c;最近在一直在弄uniapp&#xff0c;属实有被恶心到&#xff0c;但也至少会用了&#xff0c;最近实现了一个比较通用的功能&#xff0c;就是无感刷新token&#xff0c…

如何下载和安装 Linux Red Hat 9.0安装包

【微|信|公|众|号&#xff1a;厦门微思网络】 官网&#xff1a; www.xmws.cn 【限时优惠】RHCE9.0培训考证-红帽官方授权中心-CSDN博客通过这门课程&#xff0c;您将能够更好的理解企业级需求和解决方案&#xff0c;提升您的战略思 维和决策能力并助力您为企业升级使用新的技…

【C++】引用之带你“消除”C语言版数据结构教材的一些困惑(虽然是C++的内容,但是强烈建议正在学习数据结构的同学点进来看看)

&#x1f440;樊梓慕&#xff1a;个人主页 &#x1f3a5;个人专栏&#xff1a;《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C》 &#x1f31d;每一个不曾起舞的日子&#xff0c;都是对生命的辜负 目录 前言 引用的概念 引用的特性 引用的使用场…

Django实现音乐网站 ⒇

使用Python Django框架做一个音乐网站&#xff0c; 本篇音乐播放器-添加播放音乐功能实现。 目录 创建播放器数据表 设置表结构 执行创建表 命令 执行 数据表结构 添加单个歌曲 创建路由 加入播放器视图 模板处理 基类方法 子页面调用 优化弹窗 加入layui文件 基…

DPDK收发包流程分析

一、 前言 DPDK是intel工程师开发的一款用来快速处理数据包的框架,最初的目的是为了证明传统网络数据包处理性能低不是intel处理器导致的,而是传统数据的处理流程导致,后来随着dpdk的开源及其生态的快速发展,dpdk成为了高性能网络数据处理的优秀框架。本篇文章主要介绍DPDK…

游戏动态库缺失

缺哪个动态库就搜哪个&#xff0c;再下载下来。 百度网盘&#xff1a;链接&#xff1a;https://pan.baidu.com/s/1TlxLtL3hg_iCCvtCzT7bXw 提取码&#xff1a;8888 文件下载完之后要放到指定的位置 C:\Windows\System32

怎么在爬虫中使用ip代理服务器,爬虫代理IP的好处有哪些?

随着互联网的快速发展&#xff0c;网络爬虫已经成为数据采集、分析和整理的重要工具。然而&#xff0c;随着网络技术的不断发展&#xff0c;许多网站都会采取反爬虫措施&#xff0c;以避免数据被恶意获取。在这种情况下&#xff0c;代理IP服务器就成为了爬虫们的必本备文工将具…

Flink学习---15、FlinkCDC(CDC介绍、案例实操)

星光下的赶路人star的个人主页 未来总是藏在迷雾中让人胆怯&#xff0c;但当你踏入其中&#xff0c;便会云开雾散 文章目录 1、CDC简介1.1 什么是CDC1.2 CDC的种类1.3 Flink-CDC 2、FlinkCDC案例实操2.1 开启MySQL Binlog并重启MySQL2.2 FlinkSQL方式的应用2.2.1 导入依赖2.2.2…

jadx的使用

这篇文章主要介绍下jadx的使用。 1&#xff1a;下载安装 开源地址如下&#xff1a; https://github.com/skylot/jadx 当前最新的版本是1.4.7&#xff1a; https://github.com/skylot/jadx/releases/tag/v1.4.7 2&#xff1a;使用jadx mac/linux 使用jadx-gui.windows使用…

2023年中国光模块行业研究报告

第一章 行业概况 1.1 行业简介 光模块行业是光纤通信技术发展的重要组成部分&#xff0c;作为连接光纤通信网络的基础设备&#xff0c;光模块为数据传输提供了必要的硬件支持。光模块是光纤通信系统核心器件之一&#xff0c;它包括多种模块类别&#xff0c;例如光接收模块、光…