如何计算点、线、面关系

 从公众号转载,关注微信公众号掌握更多技术动态

---------------------------------------------------------------

普遍有三种方式

  • 面积和判别法:判断目标点与多边形的每条边组成的三角形面积和是否等于该多边形,相等则在多边形内部。

  • 夹角和判别法:判断目标点与所有边的夹角和是否为360度,为360度则在多边形内部。

  • 引射线法:从目标点出发引一条射线,看这条射线和多边形所有边的交点数目。如果有奇数个交点,则说明在内部,如果有偶数个交点,则说明在外部。

今天我们主要讲解一下引射线法。

一、理论基础

1.引射线法是什么

图片

    将测试点的Y坐标与多边形的每一个点进行比较,会得到一个测试点所在的行与多边形边的交点的列表。在下图的这个例子中有8条边与测试点所在的行相交,而有6条边没有相交。如果测试点的两边点的个数都是奇数个则该测试点在多边形内,否则在多边形外。在这个例子中测试点的左边有5个交点,右边有三个交点,它们都是奇数,所以点在多边形内。

2.数理基础

(1)斜率

图片

斜率公式(yi - y)/(A - xi)=(yi - yi+1)/(xi+1-xi)====>(yi-y)/(yi-yi+1)=(A-xi)/(xi+1-xi)===>A=( y -yi)/( yi+1-yi)* (xi+1-xi)+ xi

(2)三角函数

sin,称为正弦,sinθ=对边/斜边;

cos,称为余弦,cosθ=邻边/斜边;

tan,称为正切,tanθ=对边/邻边。

图片

(3)叉乘

图片

向量a×向量b(×为向量叉乘),若结果小于0,表示向量b在向量a的顺时针方向;若结果大于0,表示向量b在向量a的逆时针方向;若等于0,表示向量a与向量b平行。(顺逆时针是指两向量平移至起点相连,从某个方向旋转到另一个向量小于180度)

图片

OA×OB = 2 > 0, OB在OA的逆时针方向;OA×OC = -2 < 0,OC在OA的顺势针方向。即叉乘结果大于0,后一个在前一个的逆时针方向;小于零,后一个在前一个的顺时针方向。

(4)叉积用法

①矢量的概念

如果一条线段的端点是有次序之分的,把这种线段成为有向线段(directed segment)。如果有向线段p1p2的起点p1在坐标原点,我们可以把它称为矢量(vector)p2。

矢量加减法及距离公式:

设二维矢量P(x1,y1),Q(x2,y2),则矢量加法定义为:P+Q=(x1+x2,y1+y2),同样有矢量减法就不赘述了。并且有满足交换律,和结合律,分配律。

距离公式:

假设两点P(x1,y1),Q(x2,y2),其距离为sqrt((x1-x2)(x1-x2)+(y1-y2)(y1-y2)

double dist(point p,point q){ return sqrt((x1-x2)(x1-x2)-(y1-y2)(y1-y2)); }

②矢量叉积

计算叉积的作用有非常多,是直线和线段的核心算法。设P(x1,y1),Q(x2,y2),则其叉积为P×Q=x1y2-x2y1。

double cross(point a,point b){ return a.xb.y-a.yb.x; }

叉积具有一个重要性质是可以通过它的符号判断两个矢量相互之间的顺逆时针关系:

若P×Q>0 则P在Q的顺时针方向

若P×Q<0 则P在Q的逆时针方向

若P×Q=0 则P与Q共线,但有可能为同向或反向

矢量叉积可以看作原点,P点,Q点三点,因此可以推广成任意的3个点来判断它们之间的关系。

假设P(x1,y1),Q(x2,y2),R(x3,y3)三点,

将P和Q连接,对P,Q,R三点进行叉积即:

K=x1y2-x2y1+x2y3-x3y2+x3y1-x1y3

若K>0,其意义为在P点,面向Q点,R在PQ线段的左边

若K<0,其意义为在P点,面向Q点,R在PQ线段的右边

若K=0,其意义为在P点,面向Q点,R在PQ线段上

int mul(point a,point b,point c){    double k=x1y2-x2y1+x2y3-x3y2+x3y1-x1y3;    if(k>eps)return 1;    else if(k<-eps)return -1;    else return 0;}

③判断点是否在矩形中

    只要判断该点的横坐标和纵坐标是否夹在矩形的左右边和上下边之间。但如果点不规则就不好判断,那么我们又可以用到叉积:判断一个点是否在两条线段之间夹着就转化成,判断一个点是否在某条线段的一边上,就可以利用叉乘的方向性,来判断夹角是否超过了180度

图片

设E为任意点,ABCD为矩形

那么我们只要判断(AB×AE)(CD×CE)>=0并且(DA×DE)(BC×BE)>=0。

struct Rec{point a,b,c,d;}bool pointisinRectangle(point e,Rec r){if(mul(r.a,r.b,r.e)*mul(r.c,r.d,e)>=0&&mul(r.d,r.a,e)*mul(r.b,r.c,e)>=0)return true;else return false;}

④判断两条线段是否相交

判断两条线段的 x , y 区间在坐标轴上的投影有没有重合,设两条线段 A-B, C-D

图片

 则两条线断必定不相交

假设有两条线段AB,CD,若AB,CD相交,我们可以确定:

  • 线段AB与CD所在的直线相交,即点A和点B分别在直线CD的两边;

  • 线段CD与AB所在的直线相交,即点C和点D分别在直线AB的两边;

上面两个条件同时满足是两线段相交的充要条件,所以我们只需要证明点A和点B分别在直线CD的两边,点C和点D分别在直线AB的两边,这样便可以证明线段AB与CD相交了。

图片

线段AB与线段CD相交,于是我们可以得到两个向量AC,AD,C和D分别在AB的两边,向量AC在向量AB的逆势针方向,AB×AC > 0;向量AD在向量AB的顺势针方向,AB×AD < 0,两叉乘结果异号。

这样,方法就出来了:如果线段CD的两个端点C和D,与另一条线段的一个端点(A或B,只能是其中一个)连成的向量,与向量AB做叉乘,若结果异号,表示C和D分别在直线AB的两边,若结果同号,则表示CD两点都在AB的一边,则肯定不相交。

当然,不能只证明C,D在直线AB的两边,还要用相同的方法证明A,B在直线CD的两边,两者同时满足才是线段相交的充要条件。

否则,用叉积判断;

图片

若P×Q > 0,则P在Q的顺时针方向

若P×Q < 0,则P在Q的逆时针方向

若P×Q == 0,则P与Q平行

对于线段A-B, C-D

若 (A-C × C-D )*(B-C × C-D) <= 0, 则A和B在C-D的异侧,等号表示临界情况

若 A和B在C-D的异侧&&C和D在A-B的异侧,则 A-C 和 B-D 相交

否则不相交

⑤线段相交特殊情况——只有1点相交

图片

线段AB与CD相交于C点,按照之前介绍的方法,我们可以连成两向量AD和AC,这时候,我们发现,AC与AB共线,AB×AC = 0;而AB×AD < 0;两者并不异号,可实际上仍然相交。所以当出现两叉乘结果中,有一方为0,也可以看成点CD在直线AB的两边。

⑥线段相交特殊情况——两条线段重合

线段AB与线段CD重合,重合部分为CB,这种重合的情况要特殊判断:

首先,我们给没条线段的两个端点排序,大小判断方法如下:横坐标大的点更大,横坐标相同,纵坐标大的点更大。

排好序后,每条线段中,小的点当起点,大的当终点。我们计算向量AB×向量CD,若结果为0,表示线段AB平行CD,平行才有了重合的可能;但平行也分共线和不共线,只有共线才有可能重合

图片

第一种情况不共线,第二种情况共线。那如何来判断是否共线呢?

我们可以在两条线段中各取一点,用这两点组成的向量与其中一条线段进行叉乘,结果若为0,就表示两线段共线,如下图:

图片

我们取向量BC,若BC×CD = 0,表示两点共线,即是第二种情况,否则就是第一种情况。第一种情况肯定不相交。即使他们共线,却还是不一定重合,就如上图中第二种情况。这时候,之前给点排序的妙处就体现出来了:若一条线段AB与另一条线段CD共线,且线段AB的起点小于等于线段CD的起点,但线段AB的终点(注意是终点)大于等于线段CD的起点(注意是起点),或者交换一下顺序,CD的起点小于AB的起点......只要满足其中一个,就表示有重合部分。

3.射线法产生原理

    首先,对于平面内任意闭合曲线,都可以直观地认为,曲线把平面分割成了内、外两部分,其中“内”就是我们所谓的多边形区域。

图片

基于这一认识,对于平面内任意一条直线,可以得出下面这些结论:

  • 直线穿越多边形边界时,有且只有两种情况:进入多边形或穿出多边形。

  • 在不考虑非欧空间的情况下,直线不可能从内部再次进入多边形,或从外部再次穿出多边形,即连续两次穿越边界的情况必然成对(穿入一定会穿出)。

  • 直线可以无限延伸,而闭合曲线包围的区域是有限的,因此最后一次穿越多边形边界,一定是穿出多边形,到达外部。

图片

假如从一个给定的点做射线,还可以得出下面两条结论:

  • 如果点在多边形内部,射线第一次穿越边界一定是穿出多边形。

  • 如果点在多边形外部,射线第一次穿越边界一定是进入多边形。

图片

可以归纳出:

当射线穿越多边形边界的次数为偶数时,所有第偶数次(包括最后一次)穿越都是穿出,因此所有第奇数次(包括第一次)穿越为穿入,由此可推断点在多边形外部。 

图片

当射线穿越多边形边界的次数为奇数时,所有第奇数次(包括第一次和最后一次)穿越都是穿出,由此可推断点在多边形内部。 

4.特殊情况

(1)点在多边形的边上

图片

判断点是否在线上的方法有很多,比较简单直接的就是计算点与两个多边形顶点的连线斜率是否相等

(2)点在多边形顶点上

图片

点和多边形顶点重合的情况更简单,直接比较点的坐标就行了。

(3)射线经过多边形顶点

射线刚好经过多边形顶点的时候,应该算一次还是两次穿越?

图片

顶点穿越看似棘手,其实我们换一个角度,思路会大不相同。射线穿越一条线段需要什么前提条件?没错,就是线段两个端点分别在射线两侧。只要想通这一点,顶点穿越就迎刃而解了。这样一来,只需要规定被射线穿越的点都算作其中一侧。

图片

假如我们规定射线经过的点都属于射线以上的一侧,显然点D和发生顶点穿越的点C都位于射线Y的同一侧,所以射线Y其实并没有穿越CD这条边。而点C和点B则分别位于射线Y的两侧,所以射线Y和BC发生了穿越,由此我们可以断定点Y在多边形内。同理,射线X分别与AD和CD都发生了穿越,因此点X在多边形外,而射线Z没有和多边形发生穿越,点Z位于多边形外。

(4)射线刚好经过多边形的一条边

射线连续经过了多边形的两个相邻顶点。

图片

射线连续经过的两个顶点显然都位于射线以上的一侧,因此这种情况看作没有发生穿越就可以了。由于第三点的解决方案实际上已经覆盖到这种特例,因此不需要再做特别的处理。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

c#程序,oracle使用Devart驱动解决第第三方库是us7ascii,数据乱码的问题

最近做项目&#xff0c;要跟对方系统的库进行读写&#xff0c;结果发现对方采用的是oracle的us7ascii编码&#xff0c;我们系统默认采用的是ZHS16GBK&#xff0c;导致我们客户端读取和写入对方库的数据都是乱码&#xff0c;搜索网上&#xff0c;发现需要采用独立的oracle驱动去…

网络知识

目录 IP地址(Internet protocol address) —— 互联网协议地址 子网掩码 网关 路由 DNS&#xff08;Domain Name Server&#xff09; —— 域名服务器 IP地址(Internet protocol address) —— 互联网协议地址 子网掩码 作用&#xff1a;划分网段 网络部分相同的IP地址&a…

简介高效的 CV 入门指南: 100 行实现 InceptionResNet 图像分类

简介高效的 CV 入门指南: 100 行实现 InceptionResNet 图像分类 概述InceptionResNetInception 网络基本原理关键特征 ResNet 网络深度学习早期问题残差学习 InceptionResNet 网络InceptionResNet v1InceptionResNet v2改进的 Inception 模块更有效的残差连接设计 100 行实现 I…

C 标准库 - <errno.h>

在C语言编程中&#xff0c;<errno.h> 头文件扮演着至关重要的角色&#xff0c;它提供了一个全局变量 errno 以及一系列预定义宏&#xff0c;用于指示系统调用或库函数执行过程中发生的错误。这些宏有助于程序员诊断和处理运行时错误。 errno 变量 extern int errno;err…

【软芯民用】基于数字孪生平台的智慧灌区信息化管理系统

本文介绍了一种基于数字孪生平台的智慧综合管理系统&#xff0c;旨在实现数字化转型和精细化管理。该系统以提高用水效率为核心&#xff0c;以严格的水资源管理制度为保障&#xff0c;通过数据汇集平台监控分析数据、精准测算&#xff0c;为水量调度、精准灌溉、水权交易提供科…

时域系统到频域响应的直观解析及数学推导

课本里经常有已知系统时域的差分方程&#xff0c;求系统的频率响应这样的题&#xff0c;老师会讲怎么带公式进去解决&#xff0c;怎么查表解决&#xff0c;但我们总时无法直观地理解这两种转换的特殊关联在哪里&#xff0c;这篇文章以FIR滤波器为例&#xff0c;不仅列出了课本里…

2024年高项第4版之成本管理(附思维导图)

文章目录 简介一、成本失控原因二、相关术语三、成本类型四、项目成本管理过程1.规划成本管理2.估算成本3.制定预算4.控制成本挣值计算公式 附思维导图 简介 项目成本管理师为了项目在批准的预算内完成&#xff0c;对成本进行规划、估算、预算、融资、筹资、管理和控制的过程。…

yolov9来了,附官方源码地址,蓝奏云国内下载代码

不得不说&#xff0c;yolo的更新是真TMD的勤&#xff0c;v8还没熟悉透&#xff0c;结果V9就来了。 官方地址&#xff1a;https://github.com/WongKinYiu/yolov9/ 如果访问不了github的朋友们&#xff0c;可以下载微智启软件工作室准备好的国内蓝奏云网盘&#xff0c;内容是一样…

代码随想录算法训练营第四十天 | 整数拆分、不同的二叉搜索树

目录 整数拆分不同的二叉搜索树 LeetCode 343. 整数拆分 LeetCode 96.不同的二叉搜索树 整数拆分 dp[i]&#xff1a;分拆数字i&#xff0c;可以得到的最大乘积为dp[i]。dp[i] max(dp[i], max((i - j) * j, dp[i - j] * j)); j是从1开始遍历j * (i - j) 是单纯的把整数拆分为…

UE5 骨骼重定向

1.通过 VRoidStudio 1.26.0 软件创建模型 导出 2.下载ue插件 https://github.com/ruyo/VRM4U/releases 安装 重启 3.拖入创建的模型 到指定文件夹 4.为模型创建 IK绑定&#xff0c;重定向骨骼根 新增链条 5.创建IK 重定向&#xff0c;指定源 和 目标 IK绑定 6.

子查询

Oracle从入门到总裁:https://blog.csdn.net/weixin_67859959/article/details/135209645 子查询 前面我们学过了利用 group by子句可以实现分组的操作&#xff0c;主要的统计函数有&#xff1a;COUNT()、AVG()、SUM()、MAX()、MIN() 并且介绍了分组统计查询的若干限制以及在…

ElementUI组件的安装和使用

Element UI 是一款基于 Vue 2.0 的桌面端组件库&#xff0c;主要用于快速构建网站的前端部分。它提供了丰富的组件&#xff0c;如按钮、输入框、表格、标签页等&#xff0c;以及一些布局元素&#xff0c;如布局容器、分割线等。Element UI 的设计风格简洁&#xff0c;易于上手&…

Three.js加载PLY文件

这是官方的例子 three.js webgl - PLY 我在Vue3中使用&#xff0c;测试了好久始终不显示点云数据。在网上查询后发现ply文件要放置在public目录下才行 <el-row><el-button type"primary" class"el-btn" click"IniThree1">PLY</…

Go 如何按行读取(大)文件?尝试 bufio 包提供的几种方式

嗨&#xff0c;大家好&#xff01;我是波罗学。本文是系列文章 Go 技巧第十七篇&#xff0c;系列文章查看&#xff1a;Go 语言技巧。 本文将介绍 Go 如何按行读取文件&#xff0c;基于此会逐步延伸到如何按块读取文件。 引言 我们将要介绍的按行读取文件的方式其实是非常适合…

每日OJ题_二叉树dfs⑥_力扣257. 二叉树的所有路径

目录 力扣257. 二叉树的所有路径 解析代码 力扣257. 二叉树的所有路径 257. 二叉树的所有路径 难度 简单 给你一个二叉树的根节点 root &#xff0c;按 任意顺序 &#xff0c;返回所有从根节点到叶子节点的路径。 叶子节点 是指没有子节点的节点。 示例 1&#xff1a; 输…

电路设计(27)——交通信号灯的multisim仿真

1.功能要求 使用数字芯片设计一款交通信号灯&#xff0c;使得&#xff1a; 主干道的绿灯时间为60S&#xff0c;红灯时间为45S 次干道的红灯时间为60S&#xff0c;绿灯时间为45S 主、次干道&#xff0c;绿灯的最后5S内&#xff0c;黄灯闪烁 使用数码管显示各自的倒计时时间。 按…

go-zero微服务入门教程

go-zero微服务入门教程 本教程主要模拟实现用户注册和用户信息查询两个接口。 准备工作 安装基础环境 安装etcd&#xff0c; mysql&#xff0c;redis&#xff0c;建议采用docker安装。 MySQL安装好之后&#xff0c;新建数据库dsms_admin&#xff0c;并新建表sys_user&#…

Springboot--整合定时任务quartz--集群篇

文章目录 前言一、quartz 的集群&#xff1a;1.1 服务集群带来的定时任务问题&#xff1a;1.2 服务集群定时任务解决思路&#xff1a; 二、quartz 集群实现&#xff1a;2.1 引入jar2.2 配置文件&#xff1a;2.3 定义quartz 数据源&#xff1a;2.4 集群测试&#xff1a;2.4.1 定…

介绍 CI / CD

目录 一、介绍 CI / CD 1、为什么要 CI / CD 方法简介 1、持续集成 2、持续交付 3、持续部署 2、GitLab CI / CD简介 3、GitLab CI / CD 的工作原理 4、基本CI / CD工作流程 5、首次设置 GitLab CI / CD 6、GitLab CI / CD功能集 一、介绍 CI / CD 在本文档中&#x…

【Pytorch深度学习开发实践学习】B站刘二大人课程笔记整理lecture07多维输入

lecture07多维输入 课程网址 Pytorch深度学习实践 部分课件内容&#xff1a; import torch import numpy as npxy np.loadtxt(diabetes.csv.gz, delimiter,, dtypenp.float32) x_data torch.from_numpy(xy[:,:-1]) #第一列开始最后一列不要 y_data torch.from_numpy(…