C++ 计算几何 判断一个点是否在多边形内

多边形由多个线段确定,在多边形内部可能有0或多个挖孔。
判断一个点是否在多边形内部,但不位于挖孔内部。

思路:

从点出发作向右延伸的射线,判断射线经过的线段个数。
交点为奇数则在内部,偶数则在外部。
需要用到直线方程的两点式
在这里插入图片描述

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

template<class T>
struct Point
{
	T x;
	T y;
};

template<class T>
class Polygon
{
private:
	list<Point<T>> points;       // 外环点集合
	vector<list<Point<T>>> inners;  // 内环点集合

public:
	void AddPoint(const Point<T>& point)
	{
		points.push_back(point);
	}

	void AddInnerPolygon(const list<Point<T>>& innerPolygon)
	{
		inners.push_back(innerPolygon);
	}
	
	// 列出所有边
	void ListEdges()
	{
		cout << "多边形的边:" << endl;
		auto nextPoint = points.begin();
		for (const auto& point : points)
		{
			nextPoint++;
			if (nextPoint == points.end())
				nextPoint = points.begin();
			cout << "(" << point.x << ", " << point.y << ") - (" << nextPoint->x << ", " << nextPoint->y << ")" << endl;
		}
	}


	bool IsInPolygon(const Point<T>& targetPoint)
	{
		bool isInOuterPolygon = IsInPolygonHelper(points, targetPoint);
		if (!isInOuterPolygon)
			return false;

		for (const auto& inner : inners)
		{
			if (IsInPolygonHelper(inner, targetPoint))
				return false;
		}

		return true;
	}

private:
	bool IsInPolygonHelper(const list<Point<T>>& polygon, const Point<T>& targetPoint)
	{
		int intersectCount = 0;
		auto toPoint = polygon.begin();
		for (const auto& fromPoint : polygon)
		{
			toPoint++;
			if (toPoint == polygon.end())
				toPoint = polygon.begin();

			// 检查射线与多边形的边是否相交
			// 仅当检测点的垂直坐标位于线段之前才有可能相交
			if ((fromPoint.y <= targetPoint.y) && (toPoint->y >= targetPoint.y) || 
				(fromPoint.y >= targetPoint.y) && (toPoint->y <= targetPoint.y)  )
			{
				// 根据直线方程的两点式,代入射线(向右延伸)的方程,得到交点的X坐标
				double interSecX = (toPoint->x - fromPoint.x) / (toPoint->y - fromPoint.y)
					* (targetPoint.y - fromPoint.y) + fromPoint.x;
				if (targetPoint.x < interSecX)
					intersectCount++;
			}

		}
		return (intersectCount % 2) == 1;
	}
};

int main()
{
	// 创建一个多边形
	Polygon<double> polygon;

	// 添加外环的点
	polygon.AddPoint({ 1.0, 1.0 });
	polygon.AddPoint({ 5.0, 1.0 });
	polygon.AddPoint({ 5.0, 4.0 });
	polygon.AddPoint({ 3.0, 5.0 });
	polygon.AddPoint({ 1.0, 4.0 });

	// 添加一个内环
	list<Point<double>> innerPolygon;
	innerPolygon.push_back({ 2.0, 2.0 });
	innerPolygon.push_back({ 4.0, 2.0 });
	innerPolygon.push_back({ 4.0, 3.0 });
	polygon.AddInnerPolygon(innerPolygon);

	// 列出多边形的边
	polygon.ListEdges();

	// 测试一个点是否在多边形内部
	Point<double> testPoint = { 0, 1 };
	bool isInPolygon = polygon.IsInPolygon(testPoint);
	if (isInPolygon)
		cout << "点在多边形内部。" << endl;
	else
		cout << "点在多边形外部。" << endl;

	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Ethan Wilson

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值