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

Cad c# 射线法判断点在多边形内外

1、向量叉乘法

2、射线法原理

 

射线法是判断点与多边形位置关系的经典算法,核心思想是:

从目标点发出一条水平向右的射线(数学上可视为 y = p_y, x \geq p_x 的射线),统计该射线与多边形边的交点数量:

 

- 偶数次(含0次)相交:点在多边形外部

 

- 奇数次相交:点在多边形内部

 

- 点在边上:直接判定为内部或边界(根据需求处理)

 

关键边界处理

 

1. 边为水平线段( y_1 = y_2 = p_y ):

射线与边重合,若点在边上则直接判定为边界,否则忽略(不计数)。

 

2. 点正好是多边形顶点:

若顶点的两个相邻边分别在射线上下两侧,则计为1次交点;否则不计(避免重复计数)。

 

3. 射线经过边的顶点(非目标点):

仅当该顶点是边的“下端点”(即另一顶点 y > p_y )时,计为1次交点(采用“左闭右开”规则避免重复)。

 

CAD环境下的实现(基于AutoCAD API)

 

假设使用 Autodesk.AutoCAD.DatabaseServices 中的  Polyline  和  Point3d  类型,且所有点的 Z=0 (XY平面)。

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.Geometry;

using System;

 

public static class PointInPolylineChecker

{

    /// <summary>

    /// 射线法判断点是否在闭合Polyline内部(处理直线段,忽略凸度/圆弧,如需处理圆弧需额外交点计算)

    /// </summary>

    /// <param name="point">目标点(Z=0)</param>

    /// <param name="polyline">闭合Polyline(顶点按顺序排列,需闭合,最后一点可与第一点重复)</param>

    /// <param name="includeBoundary">是否包含边界(点在边上时返回true)</param>

    /// <returns>true=内部或边界,false=外部</returns>

    public static bool IsPointInside(Point3d point, Polyline polyline, bool includeBoundary = true)

    {

        double px = point.X;

        double py = point.Y;

        int vertexCount = polyline.NumberOfVertices;

        int intersectionCount = 0;

 

        for (int i = 0; i < vertexCount; i++)

        {

            // 获取当前边的两个端点(闭合,最后一个顶点连接到第一个顶点)

            Point3d p1 = polyline.GetPoint3dAt(i);

            Point3d p2 = polyline.GetPoint3dAt((i + 1) % vertexCount);

 

            // 处理点在边上的情况(优先判断边界)

            if (includeBoundary && IsPointOnSegment(point, p1, p2))

                return true;

 

            double y1 = p1.Y;

            double y2 = p2.Y;

 

            // 边为水平线段(与射线共线),跳过(不计入交点)

            if (Math.Abs(y1 - py) < 1e-8 && Math.Abs(y2 - py) < 1e-8)

                continue;

 

            // 边的两个端点都在射线下方或上方,不相交

            if ((y1 < py - 1e-8 && y2 < py - 1e-8) || (y1 > py + 1e-8 && y2 > py + 1e-8))

                continue;

 

            // 计算交点的x坐标(射线为y=py,x≥px)

            double xIntersect;

            double dx = p2.X - p1.X;

            double dy = p2.Y - p1.Y;

 

            // 处理垂直边(避免除零)

            if (Math.Abs(dy) < 1e-8)

                continue; // 已处理水平边,此处为垂直边但y不相等,不可能与射线相交

 

            double t = (py - y1) / dy; // 参数t∈[0,1]表示交点在边上的位置

            xIntersect = p1.X + t * dx;

 

            // 交点必须在射线右侧(xIntersect ≥ px - 1e-8,允许微小误差)且在边的范围内(t∈[0,1])

            if (xIntersect >= px - 1e-8 && t >= -1e-8 && t <= 1 + 1e-8)

            {

                // 处理射线经过顶点的情况(左闭右开规则:仅当顶点是边的“下端点”时计数)

                if ((y1 < py + 1e-8 && y2 >= py + 1e-8) || (y2 < py + 1e-8 && y1 >= py + 1e-8))

                {

                    // 排除顶点在射线上且相邻边同向的情况(避免重复计数)

                    if (!(Math.Abs(y1 - py) < 1e-8 && Math.Abs(y2 - py) < 1e-8))

                        intersectionCount++;

                }

            }

        }

 

        // 奇数次相交则在内部,边界情况已提前处理

        return intersectionCount % 2 == 1;

    }

 

    /// <summary>

    /// 判断点是否在线段上(包含端点,允许1e-8精度误差)

    /// </summary>

    private static bool IsPointOnSegment(Point3d point, Point3d p1, Point3d p2)

    {

        double cross = (point.X - p1.X) * (p2.Y - p1.Y) - (point.Y - p1.Y) * (p2.X - p1.X);

        if (Math.Abs(cross) > 1e-8) return false; // 点不在直线上

 

        double minX = Math.Min(p1.X, p2.X) - 1e-8;

        double maxX = Math.Max(p1.X, p2.X) + 1e-8;

        double minY = Math.Min(p1.Y, p2.Y) - 1e-8;

        double maxY = Math.Max(p1.Y, p2.Y) + 1e-8;

 

        return point.X >= minX && point.X <= maxX && point.Y >= minY && point.Y <= maxY;

    }

}

相关文章:

  • 淘宝店铺详情API接口返回数据说明
  • 精益数据分析(10/126):深度剖析数据指标,驱动创业决策
  • EXCEL学习
  • 天元证券|AI驱动需求井喷 光模块上市公司业绩爆发
  • Oracle for Linux安装和配置(11)——Linux配置
  • 深入理解 DML 和 DQL:SQL 数据操作与查询全解析
  • Spring Boot 集成 Redis 实战总结
  • 智能对讲机:通信技术的革新与“危急特”场景的守护者
  • 【KWDB创作者计划】_针对KWDB时序数据库(多副本集群环境)进行压力测试
  • C++如何处理多线程环境下的异常?如何确保资源在异常情况下也能正确释放
  • 【scikit-learn基础】--『监督学习』之 均值聚类
  • Android 15强制edge-to-edge全面屏体验
  • docker部署ruoyi-vue-pro前后端详细笔记
  • Linux:权限相关问题
  • 一款支持多线程的批量任务均衡器
  • AI日报 - 2024年04月22日
  • 实验四-用户和权限管理
  • Uniapp:view容器(容器布局)
  • 微硕WSP4407A MOS管在智能晾衣架中的应用与市场分析
  • 时序逻辑入门指南:LTL、CTL与PTL的概念介绍与应用场景
  • 致敬劳动者!今年拟表彰2426名全国劳动模范和先进工作者
  • 又一名被拐孩子找到!29年后,在警方帮助下云南男子寻子成功
  • 普京宣布临时停火30小时
  • 美国国务卿:乌克兰问题谈判不能一直停滞不前
  • 潮州官方回应女婴事件:尚未发现虐待,各种原因导致营养不良
  • 河北衡水中学再换校长