当前位置: 首页 > news >正文

【算法学习】射线法判断点在多边形内外(C#)以及确定内外两点连线与边界的交点

1.前言:

在GIS开发中,经常会遇到确定一个坐标点是否在一块区域的内部这一问题。
如果这个问题不是一个单纯的数学问题,例如:在判断DEM、二维图像像素点、3D点云点等含有自身特征信息的这些点是否在一个区域范围内部的时候,可以结合其高程信息、RGB信息、深度信息来辅助处理,相比与单纯从数学角度来看更简单、快速。

举几个我认为正确的例子:SLAM中前端角点的选取,利用的是OpenCV来提取;DEM提取边界,根据周围高程的有无;PS中扣出某物边界,利用的是RGB差异性;点云提取可以利用深度信息(本质也是RGB)来做。

但是,如果我现在只拥有点的坐标,该问题就变成一个数学问题了。

2.射线法:

在这里插入图片描述

该算法基本思路是从待定点朝任意方向射出一条射线(通常是水平向右),判断该射线与多边形边的交点个数。一般来说,交点个数为偶数(包括0),点在外部;交点个数为奇数,点在内部。
因为点和图形的位置是固定不动的,所以射线的朝向,对于最终的交点个数,也就是位置结果是没有影响的。

2.1 算法介绍

在分析前要先明白几个问题:

  • 如果没有特殊需求,待求点在图形的边界(线段、交点)上,默认是属于图形内部的。
  • 默认待求点的射线沿着x轴方向水平射出(水平向)。
  • 射线经过边界交点情况很常见,为了防止上一个线段的末顶点和下一个线段的首顶点(这两个是一个点)被算作两次,所以只看线段的y更小的一端,即参数方程的值域符号:[y1,y2)
    假如逆时针遍历各边,看下图示例:
    在这里插入图片描述

(1)从简单情况开始分析:
最简单的情况当属一个规整的四边形,射线与四边形的交点个数存在的情况有:0,1,2。
如果,不考虑穿过顶点,不考虑点的射线与边平行(重合),就单纯考虑穿的全部是边,遇到这种情况:
先建立遍历边的参数方程,找到射线与参数方程的交点,再判断交点X交和待定点的位置关系。
在这里插入图片描述
如果P在X交左侧,有一个交点则计数+1;
如果P和X交是一个点,则说明P在边界线段上,直接返回true;
如果在X交右侧,没有交点。

注意:这里的上下yi和yj的取值,要包含下界,不包含上界,否则会被计算两次,而且这样可以有效忽略水平边界而待求点在左侧的问题。
当然,反过来也可以,都选择更大的y值。

(2)我认为的几种特殊情况,这几种特殊情况有特点:就是无法找到线段去做参数方程或者实际交点无数个。这几种特殊情况需要单独处理。

  • 待求点就是边界交点:通过坐标判断,直接返回是否在边界内。
  • 待求点在水平边界线上:通过坐标判断,直接返回是否在边界内。
  • 待求点在水平边界线左侧:配合前后该水平边界先后线段参数方程的值域,这种情况可以直接忽略!(忽略不是没有考虑)

2.2 C#代码实现

using System;
using System.Collections.Generic;public class Point
{public double X { get; set; }public double Y { get; set; }public Point(double x, double y){X = x;Y = y;}
}
public class Polygon
{private List<Point> vertices;public Polygon(List<Point> points){vertices = points;}public bool IsPointInside(Point testPoint){int intersectionCount = 0;int vertexCount = vertices.Count;for (int i = 0, j = vertexCount - 1; i < vertexCount; j = i++){Point vi = vertices[i];Point vj = vertices[j];// 检查测试点是否在顶点上if ((vi.X == testPoint.X && vi.Y == testPoint.Y) ||(vj.X == testPoint.X && vj.Y == testPoint.Y)){return true;}// 检查测试点是否在水平边上if (vi.Y == vj.Y && vi.Y == testPoint.Y){if (testPoint.X > Math.Min(vi.X, vj.X) && testPoint.X < Math.Max(vi.X, vj.X)){return true;}}// 检查testpoint.y是否在两个端点的中间//if ((vi.Y > testPoint.Y) != (vj.Y > testPoint.Y)) // 这行代码更简单,但是有点小小的不直观if ((vi.Y <= testPoint.Y && vj.Y > testPoint.Y) || (vj.Y <= testPoint.Y && vi.Y > testPoint.Y)){double intersectionX = (vj.X - vi.X) * (testPoint.Y - vi.Y) / (vj.Y - vi.Y) + vi.X;// 处理边界情况if (testPoint.X == intersectionX){return true;}if (testPoint.X < intersectionX){intersectionCount++;}}}// 如果交点数为奇数,则点在多边形内部return intersectionCount % 2 != 0;}
}
internal class Program
{static void Main(string[] args){List<Point> vertices = new List<Point>{new Point(0,0),new Point(1,0),new Point(2,-1),new Point(3,0),new Point(5,0),new Point(5,1),new Point(4,1),new Point(4,2),new Point(3,3),new Point(3,4),new Point(2,4),new Point(2,3),new Point(1,3),new Point(1,4),new Point(0,4),new Point(0,2),new Point(-1,1),};Polygon polygon = new Polygon(vertices);List<Point> testPoint = new List<Point>();for (int i = -1; i < 6; i++){for (int j = -1; j < 7; j++){testPoint.Add(new Point(i, j));}}foreach (var p in testPoint){Console.WriteLine($"p点坐标:({p.X}, {p.Y}),是否在图形内部:{polygon.IsPointInside(p)}");}Console.ReadKey();}
}

在这里插入图片描述
用for循环写了一个从(-1,-1)到(5,6)覆盖的测试点,最后结果:

p点坐标:(-1, -1,是否在图形内部:False|p点坐标:(-1, 0,是否在图形内部:False
p点坐标:(-1, 1,是否在图形内部:True|p点坐标:(-1, 2,是否在图形内部:False
p点坐标:(-1, 3,是否在图形内部:False|p点坐标:(-1, 4,是否在图形内部:False
p点坐标:(-1, 5,是否在图形内部:False|p点坐标:(-1, 6,是否在图形内部:False
p点坐标:(0, -1,是否在图形内部:False|p点坐标:(0, 0,是否在图形内部:True
p点坐标:(0, 1,是否在图形内部:True|p点坐标:(0, 2,是否在图形内部:True
p点坐标:(0, 3,是否在图形内部:True|p点坐标:(0, 4,是否在图形内部:True
p点坐标:(0, 5,是否在图形内部:False|p点坐标:(0, 6,是否在图形内部:False
p点坐标:(1, -1,是否在图形内部:False|p点坐标:(1, 0,是否在图形内部:True
p点坐标:(1, 1,是否在图形内部:True|p点坐标:(1, 2,是否在图形内部:True
p点坐标:(1, 3,是否在图形内部:True|p点坐标:(1, 4,是否在图形内部:True
p点坐标:(1, 5,是否在图形内部:False|p点坐标:(1, 6,是否在图形内部:False
p点坐标:(2, -1,是否在图形内部:True|p点坐标:(2, 0,是否在图形内部:True
p点坐标:(2, 1,是否在图形内部:True|p点坐标:(2, 2,是否在图形内部:True
p点坐标:(2, 3,是否在图形内部:True|p点坐标:(2, 4,是否在图形内部:True
p点坐标:(2, 5,是否在图形内部:False|p点坐标:(2, 6,是否在图形内部:False
p点坐标:(3, -1,是否在图形内部:False|p点坐标:(3, 0,是否在图形内部:True
p点坐标:(3, 1,是否在图形内部:True|p点坐标:(3, 2,是否在图形内部:True
p点坐标:(3, 3,是否在图形内部:True|p点坐标:(3, 4,是否在图形内部:True
p点坐标:(3, 5,是否在图形内部:False|p点坐标:(3, 6,是否在图形内部:False
p点坐标:(4, -1,是否在图形内部:False|p点坐标:(4, 0,是否在图形内部:True
p点坐标:(4, 1,是否在图形内部:True|p点坐标:(4, 2,是否在图形内部:True
p点坐标:(4, 3,是否在图形内部:False|p点坐标:(4, 4,是否在图形内部:False
p点坐标:(4, 5,是否在图形内部:False|p点坐标:(4, 6,是否在图形内部:False
p点坐标:(5, -1,是否在图形内部:False|p点坐标:(5, 0,是否在图形内部:True
p点坐标:(5, 1,是否在图形内部:True|p点坐标:(5, 2,是否在图形内部:False
p点坐标:(5, 3,是否在图形内部:False|p点坐标:(5, 4,是否在图形内部:False
p点坐标:(5, 5,是否在图形内部:False|p点坐标:(5, 6,是否在图形内部:False

相关文章:

【算法学习】射线法判断点在多边形内外(C#)以及确定内外两点连线与边界的交点

1.前言&#xff1a; 在GIS开发中&#xff0c;经常会遇到确定一个坐标点是否在一块区域的内部这一问题。 如果这个问题不是一个单纯的数学问题&#xff0c;例如&#xff1a;在判断DEM、二维图像像素点、3D点云点等含有自身特征信息的这些点是否在一个区域范围内部的时候&#x…...

SQL语句(DML)

DML英文全称是Data Manipulation Language&#xff08;数据操作语言&#xff09;&#xff0c;用来对数据库中表的数据记录进行增删改等操作 DML-添加数据 insert into employee(id, workno, name, gender, age, idcard) values (1,1,Itcast,男,10,123456789012345678);select *…...

uniapp小程序打开地图导航

uniapp uni.getLocation({type: gcj02, //返回可以用于uni.openLocation的经纬度success: function (res) {const latitude res.latitude;const longitude res.longitude;uni.openLocation({latitude: latitude,longitude: longitude,success: function () {console.log(suc…...

webstorm格式化或保存时 vue3引入的组件被删除了

解决办法 保存时设置 格式化设置...

Java时间转换

一、线程不安全 Date date new Date(); SimpleDateFormat dateFormat new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String prefix dateFormat.format(date);二、线程安全,建议使用 String t1 LocalDateTime.now().format(DateTimeFormatter.ofPattern("y…...

Spring Boot与WebFlux的实战案例

Spring Boot与WebFlux的实战案例 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天&#xff0c;我们将探讨如何利用Spring Boot和WebFlux构建响应式应用的实战…...

vue3引入本地静态资源图片

一、单张图片引入 import imgXX from /assets/images/xx.png二、多张图片引入 说明&#xff1a;import.meta.url 是一个 ESM 的原生功能&#xff0c;会暴露当前模块的 URL。将它与原生的 URL 构造器 组合使用 注意&#xff1a;填写自己项目图片存放的路径 /** vite的特殊性…...

git 禁止dev合并到任何其他分支

创建 pre-merge-commit 钩子 导航到 Git 仓库的钩子目录&#xff1a; cd /path/to/your/repo/.git/hooks创建或编辑 pre-merge-commit 钩子&#xff1a; 也可以通过指令创建 nano pre-merge-commit在钩子文件中添加以下代码&#xff1a; #!/bin/sh# 获取当前分支名称 curr…...

第二节:如何使用thymeleaf渲染html(自学Spring boot 3.x的第一天)

大家好&#xff0c;我是网创有方&#xff0c;今天来学习如何使用thymeleaf渲染html。该模板运用不广泛&#xff0c;所以本节内容了解既可。 第一步&#xff1a;创建html文件。 在模板templates目录下创建一个html文件。 编写代码如下&#xff1a; <!DOCTYPE html> <…...

计算机相关术语科普之什么叫网关(Gateway)

网关&#xff08;Gateway&#xff09;是一个在计算机网络中起到关键作用的设备或系统&#xff0c;它扮演着网络间连接器或协议转换器的角色。 一、定义与功能 1&#xff09;定义&#xff1a; 网关是在不同网络之间实现互连的复杂设备&#xff0c;仅用于两个高层协议不同的网…...

B站网页部分API

https://www.bilibili.com/ 数据结构 mid: 用户id name: 用户名 face: 用户头像url noface.jpg为默认头像 sign&#xff1a; 签名level: b站等级 coins: b站硬币粉丝 https://api.bilibili.com/x/relation/fans?vmid{mid}&pn{pn}&ps{limit}&orderdesc&…...

使用Spring Boot和Spring Security保护你的应用

使用Spring Boot和Spring Security保护你的应用 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天我们将深入探讨如何利用Spring Boot和Spring Security来保护…...

CVE-2019-12272 Openwrt可视页面LuCi命令注入漏洞复现(完结)

声明 本文所使用的一些源代码等内容已经上传至github&#xff0c;具体地址如下 Vulnerability_POC-EXP/OpenWrt/CVE-2019-12272 at main a2148001284/Vulnerability_POC-EXP GitHub 漏洞简介 参考内容&#xff1a; CVE-2019-12272 OpenWrt图形化管理界面LuCI命令注入分析 |…...

【多线程开发 4】从源码学习LockSupport

从源码学习LockSupport 2024年6月30日 大家好啊&#xff0c;好久没写博客了&#xff0c;今天打算写一下&#xff0c;讲一下JUC里面LockSupport这个类。 这个是一个工具类&#xff0c;实际上也是为了线程通信开发的。它的源码比较短&#xff0c;也只引用了Unsafe一个类。所以…...

gameui C++的代码

gameui C的代码 #include <graphics.h> #include "gameboard.h" const int WIDTH 560; const int HEIGHT 780; const int GRID_SIZE 120; class GameUi { private: public:GameUi(GameBoard& gb) {// 初始化图形窗口initgraph(WIDTH, HEIGHT);// 设置…...

1.什么是js?特点是什么?组成部分?

Js是一种直译式脚本语言&#xff0c;一种动态类型&#xff0c;弱类型&#xff0c;基于原型的高级语言。 直译式&#xff1a;js程序运行过程中直接编译成机器语言。 脚本语言&#xff1a;在程序运行过程中逐行进行解释说明&#xff0c;不需要预编译。 动态类型&#xff1a;js…...

爬虫是什么?

目录 1.什么是互联网爬虫&#xff1f; 2.爬虫核心? 3.爬虫的用途? 4.爬虫分类&#xff1f; 5.反爬手段&#xff1f; 1.什么是互联网爬虫&#xff1f; 如果我们把互联网比作一张大的蜘蛛网&#xff0c;那一台计算机上的数据便是蜘蛛网上的一个猎物&#xff0c;而爬虫程序…...

深入理解Presto分页查询:方法与最佳实践

目录 引言为什么需要分页查询Presto简介分页查询的基本概念Presto分页查询的实现方法 使用LIMIT和OFFSET使用游标分页结合外部工具和框架 分页查询的性能优化 索引优化查询计划优化数据分区 实际案例分析最佳实践与常见问题 大数据集分页复杂查询分页实时性要求高的场景 总结 …...

如何使用Go语言中的并发函数实现网络爬虫的分布式部署?

如何使用go语言中的并发函数实现网络爬虫的分布式部署&#xff1f; 在当今的互联网时代&#xff0c;大量的信息蕴藏在各个网站中&#xff0c;爬虫成为了一种重要的工具。而对于大规模的数据爬取任务&#xff0c;采用分布式部署能够更有效地提升爬取速度和效率。Go语言的并发机…...

STM32第九课:DHT11温湿度传感器

文章目录 需求一、DHT11温湿度传感器二、模块配置流程1.配置时钟和IO2.读取数据3.数据处理 三、导入语音模块四、关键代码总结 需求 1.完成DHT11温湿度检测模块的配置。 2.处理DHT11获取的数据&#xff0c;在串口打印处理后的实时数据。 2.通过Su-03t语音识别模块实现实时温湿…...

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…...

Android Wi-Fi 连接失败日志分析

1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分&#xff1a; 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析&#xff1a; CTR…...

3.3.1_1 检错编码(奇偶校验码)

从这节课开始&#xff0c;我们会探讨数据链路层的差错控制功能&#xff0c;差错控制功能的主要目标是要发现并且解决一个帧内部的位错误&#xff0c;我们需要使用特殊的编码技术去发现帧内部的位错误&#xff0c;当我们发现位错误之后&#xff0c;通常来说有两种解决方案。第一…...

DAY 47

三、通道注意力 3.1 通道注意力的定义 # 新增&#xff1a;通道注意力模块&#xff08;SE模块&#xff09; class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...

【Go】3、Go语言进阶与依赖管理

前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课&#xff0c;做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程&#xff0c;它的核心机制是 Goroutine 协程、Channel 通道&#xff0c;并基于CSP&#xff08;Communicating Sequential Processes&#xff0…...

【单片机期末】单片机系统设计

主要内容&#xff1a;系统状态机&#xff0c;系统时基&#xff0c;系统需求分析&#xff0c;系统构建&#xff0c;系统状态流图 一、题目要求 二、绘制系统状态流图 题目&#xff1a;根据上述描述绘制系统状态流图&#xff0c;注明状态转移条件及方向。 三、利用定时器产生时…...

Spring Boot面试题精选汇总

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点睡觉 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...

AI编程--插件对比分析:CodeRider、GitHub Copilot及其他

AI编程插件对比分析&#xff1a;CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展&#xff0c;AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者&#xff0c;分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...

智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制

在数字化浪潮席卷全球的今天&#xff0c;数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具&#xff0c;在大规模数据获取中发挥着关键作用。然而&#xff0c;传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时&#xff0c;常出现数据质…...

Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析

Java求职者面试指南&#xff1a;Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问&#xff08;基础概念问题&#xff09; 1. 请解释Spring框架的核心容器是什么&#xff1f;它在Spring中起到什么作用&#xff1f; Spring框架的核心容器是IoC容器&#…...