平面中,判断一个点与不规则封闭区域的位置关系

        近期,工作中遇到一个需求:判断一个点是否在一个不规则封闭区域内,根据判断结果进行相应处理。

        在网上搜索相关内容后,确定了以射线法来实现点与不规则封闭区域的位置关系,如下图:

图中:以某点为端点做射线(向任何方向做射线都可以,本例中为实现简单,则选择向右做射线),与不规则封闭区域的边存在若个交点。

A点:2个交点(外部);

B点:1个交点(内部);

C点:4个交点(外部);

D点:2个交点(外部);

E点:3个交点(内部);

通过以上数据,我们可以得出一个结论:凡交点是奇数的,则点在内部;否则,点在外部。

不过,本例存在以下两个特殊情况:

  1. 区域的边是水平方向,即两个节点的X坐标相同,则不计算交点;
  2. 每条边都有上下两个端点(上端点和下端点),为防止射线经过了两条边的交点而重复计算,我们规定射线只与边的上端点相交为有效交点。

如何判断与不规则区域的边有交点呐?如下图:

以向右做水平射线为例

         线段P1P2为不规则区域的一条边。如果点Pt.Y坐标大于P1P2两点的最大Y坐标或者小于P1P2两点最小Y坐标,那么P1P2与射线无交点;如果点Pt.X坐标大于P1P2两点最大X坐标,则P1P2与射线无交点。在有焦点的情况下,如果Pt.X坐标小于射线与P1P2交点的X坐标,则有交点且有效,否则是Pt点向右水平射线的反向延长线上有交点,则交点无效。(此处计算射线与P1P2交点的X坐标用的是相似三角形的性质即对应边长成正比例)

根据上述研究可得如下方法(C#语言实现):

private bool IsInnerNew(Point pt,Point[] points)
        {
            Point p1, p2;
            int crossPointCounter=0;
            for(int i = 0; i < points.Length; i++)
            {
                //向右做X轴的水平射线
                p1=points[i];
                p2=points[(i + 1) % points.Length];
                if(p1.Y==p2.Y) continue;
                if (pt.Y < Math.Min(p1.Y, p2.Y)) continue;
                if (pt.Y >= Math.Max(p1.Y, p2.Y)) continue;
                if (pt.X >= Math.Max(p1.X, p2.X)) continue;
                double x = (double)(pt.Y - p1.Y) * (double)(p2.X - p1.X) / (double)(p2.Y - p1.Y) + p1.X;
                if (x>pt.X)
                {
                    crossPointCounter++;
                }
            }
            if (crossPointCounter%2==1)
                return true;
            else
                return false;
        }

根据此方法判断结果,绘制一个点的矩阵,得到结果如下图:

符合预期效果!!!

本文参考如下内容:

 如何判定一点是否在给定顶点的不规则封闭区域内? - 知乎

计算机图形学:传统函数方法判定点在不规则封闭区域内的判定方法_判断点在不规则区域内_星空_MAX的博客-CSDN博客

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
下面是一个简单的 C++ 代码实现: ```c++ #include <iostream> #include <cmath> using namespace std; struct Vector3 { double x, y, z; Vector3() {} Vector3(double x, double y, double z) : x(x), y(y), z(z) {} Vector3 operator+(const Vector3& other) const { return Vector3(x + other.x, y + other.y, z + other.z); } Vector3 operator-(const Vector3& other) const { return Vector3(x - other.x, y - other.y, z - other.z); } Vector3 operator*(double scalar) const { return Vector3(x * scalar, y * scalar, z * scalar); } double dot(const Vector3& other) const { return x * other.x + y * other.y + z * other.z; } Vector3 cross(const Vector3& other) const { return Vector3(y * other.z - z * other.y, z * other.x - x * other.z, x * other.y - y * other.x); } double length() const { return sqrt(x * x + y * y + z * z); } }; struct Ray { Vector3 origin, direction; Ray() {} Ray(const Vector3& origin, const Vector3& direction) : origin(origin), direction(direction) {} }; struct Plane { Vector3 point, normal; Plane() {} Plane(const Vector3& point, const Vector3& normal) : point(point), normal(normal) {} }; bool intersect(const Ray& ray, const Plane& plane, double& t) { double denom = plane.normal.dot(ray.direction); if (abs(denom) < 1e-6) // 判断是否平行 return false; t = plane.normal.dot(plane.point - ray.origin) / denom; return t >= 0; } int main() { // 示例:射线由点(0, 0, 0)出发,方向为(1, 1, 1);平面上的一点为(0, 0, 1),法向量为(0, 0, 1) Ray ray(Vector3(0, 0, 0), Vector3(1, 1, 1)); Plane plane(Vector3(0, 0, 1), Vector3(0, 0, 1)); double t; if (intersect(ray, plane, t)) { Vector3 intersection = ray.origin + ray.direction * t; cout << "Intersection point: (" << intersection.x << ", " << intersection.y << ", " << intersection.z << ")" << endl; } else { cout << "No intersection." << endl; } return 0; } ``` 这里我们定义了三个结构体:`Vector3` 表示三维向量,`Ray` 表示射线,`Plane` 表示平面。`intersect` 函数判断射线与平面是否相交,并返回相交参数t。在主函数,我们给出了一个示例并输出相交点的坐标。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值