如何判断点在多边形内部

如何判断点在多边形内部

预备知识

​ 向量的叉乘
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JRDypVrB-1663419615077)(点在多边形内部.assets/image-20220917205427141.png)]

​ 向量的点乘

​ a = (x1,y1) b=(x2,y2)

​ a·b = x1x2 + y1y2 = |a||b|cos<a,b>

思路

射线法:从一个点向任意方向《不妨设水平向右》发出一条射线,该射线如多边形的交点的个数,如果是奇数,则在多边形内部,如果是偶数则在外部。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ujc0eBCa-1663419615078)(点在多边形内部.assets/image-20220917205603361.png)]

需要前期解决的问题

  • 怎么判断点在一条线上?

  • 怎么判断点和线的交点?

  • 怎么判断点和交点的位置关系?

特殊情况

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dAP6ACPN-1663419615079)(点在多边形内部.assets/image-20220917205720325.png)]

\

解决方案

  • 对于多边形的水平边不作考虑;
  • 对于多边形的顶点和射线相交的情况,如果该顶点是其所属的边上纵坐标较大的顶点,则计数,否则忽略该点:
  • 对于О在多边形边上的情形,直接可判断О属于多边行。

测试用例

在这里插入图片描述

代码

#include <iostream>	
#include <vector>
using namespace std;


const double eps = 1e-6;
int dcmp(double a,double b)
{
	if (fabs(a - b) < eps)
		return 0;
	return a - b > 0 ? 1 : -1;
}

struct  Point
{
	double x, y;
	Point(double x = 0,double y= 0):x(x),y(y){}

	Point operator+(const Point& p)const
	{
		return Point(x + p.x, y + p.y);
	}
	Point operator-(const Point& p)const
	{
		return Point(x - p.x, y - p.y);
	}
	//点积
	double operator*(const Point&p)const
	{
		return x * p.x + y * p.y;
	}
	//叉积
	double operator^(const Point&p)const
	{
		return x * p.y - y * p.x;
	}
};
//点在线上
bool PointOnLine(const Point& p1,const Point& p2,const Point& q)
{
	//1、三点共线
	//2、q 在不在p1,p2中间(包括p1,p2)
	return dcmp((p1 - q) ^ (p2 - q), 0) == 0 && dcmp((p1 - q) * (p2 - q), 0) <= 0;
}

bool PointInPolygon(const vector<Point>& polygon,const Point& p)
{
	int size = polygon.size();
	if (size < 3)return false;
	bool flag = false;
	for(int i=0,j=size-1;i<size;j=i++)
	{
		if (PointOnLine(polygon[i], polygon[j], p)) 
			return true;
		//存在水平线段忽略不计
		if(dcmp(polygon[i].y,polygon[j].y)==0)	
			continue;
		if(dcmp(min(polygon[i].y,polygon[j].y),p.y)<0 && dcmp(max(polygon[i].y, polygon[j].y), p.y) >= 0)
		{
			//是否为竖直线段
			if(dcmp(polygon[i].x,polygon[j].x) == 0 && dcmp(p.x,polygon[i].x)<=0)
			{
				flag = !flag;
				continue;
			}
			//p 是否在相交点的左边
			if(dcmp(p.x, polygon[i].x - (polygon[i].y - p.y) * (polygon[i].x - polygon[j].x) / (polygon[i].y - polygon[j].y)) < 0)
			{
				flag = !flag;
			}
		}
	}
	return flag;
}

//测试用例
/*
3 1
1 2
2 4
6 4
0.5 5
2 5
6 5
6 5.5
1 8

3 1   no
1 2   no
2 4   yes
6 4   yes
0.5 5 no
2 5   no
6 5   yes
6 5.5 yes
1 8   no
*/
int main()
{
	double x = 0, y = 0;
	vector<Point> polygon = { Point(1,5),Point(2,2)
		,Point(5,1),Point(7,4),Point(9,4)
		,Point(7,5),Point(7,6),Point(3,8)
		,Point(1,7),Point(3,4) };
	while (1)
	{
		cin >> x;
		cin >> y;
		if (PointInPolygon(polygon, Point(x, y)))
		{
			std::cout << "yes\n";
		}
		else
		{
			std::cout << "no\n";
		}
		if (dcmp(x, -1) == 0)
			break;
	}
	return 0;
}
判断一个是否在多边形内部,可以使用射线法。 射线法的基本思路是从该向任意方向发射一条射线,然后统计与多边形的交数量。如果交数量为奇数,则该多边形内部,否则在多边形外部。 以下是一段用 C 语言实现的代码: ```c #include <stdio.h> #include <stdlib.h> typedef struct { float x; float y; } Point; typedef struct { int n; // 边数 Point *points; // 多边形的顶数组 } Polygon; // 计算两之间的距离 float distance(Point p1, Point p2) { return sqrt(pow(p1.x - p2.x, 2) + pow(p1.y - p2.y, 2)); } // 判断两条线段是否相交 int segmentIntersect(Point p1, Point p2, Point q1, Point q2) { float d1 = (q1.x - p1.x) * (p2.y - p1.y) - (p2.x - p1.x) * (q1.y - p1.y); float d2 = (q2.x - p1.x) * (p2.y - p1.y) - (p2.x - p1.x) * (q2.y - p1.y); float d3 = (p1.x - q1.x) * (q2.y - q1.y) - (q2.x - q1.x) * (p1.y - q1.y); float d4 = (p2.x - q1.x) * (q2.y - q1.y) - (q2.x - q1.x) * (p2.y - q1.y); if ((d1 > 0 && d2 < 0 || d1 < 0 && d2 > 0) && (d3 > 0 && d4 < 0 || d3 < 0 && d4 > 0)) { return 1; } return 0; } // 判断是否在多边形内部 int pointInPolygon(Polygon polygon, Point point) { int count = 0; Point outside = {1e4, 1e4}; // 构造一条射线,射线起外部 for (int i = 0; i < polygon.n; i++) { int j = (i + 1) % polygon.n; if (segmentIntersect(polygon.points[i], polygon.points[j], point, outside)) { count++; } } if (count % 2 == 1) { return 1; } return 0; } int main() { // 构造一个三角形 Polygon triangle; triangle.n = 3; triangle.points = (Point *)malloc(triangle.n * sizeof(Point)); triangle.points[0] = (Point){0, 0}; triangle.points[1] = (Point){2, 0}; triangle.points[2] = (Point){1, 3}; // 判断 (1, 1) 是否在三角形内部 Point point = {1, 1}; if (pointInPolygon(triangle, point)) { printf("Point (%.2f, %.2f) is inside the polygon.\n", point.x, point.y); } else { printf("Point (%.2f, %.2f) is outside the polygon.\n", point.x, point.y); } free(triangle.points); return 0; } ``` 这段代码中,我们定义了一个 `Point` 结构体表示二维坐标,定义了一个 `Polygon` 结构体表示多边形,包含了边数和所有顶坐标的数组。`distance` 函数用于计算两之间的距离,`segmentIntersect` 函数用于判断两条线段是否相交。最重要的是 `pointInPolygon` 函数,该函数用于判断一个是否在多边形内部。该函数使用一条射线从该向外发射,统计与多边形的交数量,最后判断数量的奇偶性即可。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_Yi_Xiao

来瓶可乐

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值