数学篇 cad.net 判断点在多段线内-射线法

矩形只是多段线的一种解,

但是矩形可以利用叉乘做到快速求解.

这方面可以自行去搞搞.

这里提供一个最通用的.

测试命令:

    public class JJ_test_ckk
    {
        [CommandMethod("JJ_test_ckk")]
        public void TT()
        {
            Editor ed = Acap.DocumentManager.MdiActiveDocument.Editor;
            Database db = Acap.DocumentManager.MdiActiveDocument.Database;
            ed.WriteMessage(Environment.NewLine + "惊惊net测试区:");

            var ppo = new PromptPointOptions(Environment.NewLine + "测试点:")
            {
                AllowArbitraryInput = true,//任意输入
                AllowNone = true//允许回车
            };
            var ppr = ed.GetPoint(ppo);//用户点选
            if (ppr.Status != PromptStatus.OK)
            {
                return;
            }

            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                var peo = new PromptEntityOptions(Environment.NewLine + "点选多段线")
                {
                    AllowObjectOnLockedLayer = false,
                    AllowNone = false
                };

                var ent2 = ed.WhileEntsel(tr, peo, null, new EntityType[] { EntityType.Polyline });
                if (ent2 is ObjectId idv && idv.IsOk())
                {
                    Entity ent = idv.ToEntity(tr);
                    if (ent is Polyline pl && MathTool.IsPointInPL(ppr.Value, pl.GetPoint3ds())) 
                    {
                        ed.WriteMessage(Environment.NewLine + "内内内内内内内内");
                    }
                    else
                    {
                        ed.WriteMessage(Environment.NewLine + "外外外外外外外外外外外");
                    }
                }
                else
                {
                    return;
                }
                tr.Commit();
            }
        }
    }
View Code

点选多段线函数:

   /// <summary>
        /// 点选直到满足条件
        /// </summary>
        /// <param name="ed">图形数据库</param> 
        /// <param name="entType">过滤类型,数组</param> 
        /// <param name="peo">块外</param>
        /// <param name="opt">块内</param>
        /// <returns>点选到的图元的ObjectId</returns>
        public static object WhileEntsel(this Editor ed, Transaction tr,
        PromptEntityOptions peo = null, PromptNestedEntityOptions opt = null, IEnumerable<EntityType> entType = null)
        {
            ed.SetImpliedSelection(new ObjectId[0]);  //清空当前选择集
            object idOrKeyword = null;
            ObjectId idget = ObjectId.Null;
            bool flag = true;
            PromptEntityResult res;
            PromptNestedEntityResult pnes;
            while (flag)
            {
                if (peo != null)
                {
                    res = ed.GetEntity(peo);
                    switch (res.Status)
                    {
                        case PromptStatus.Keyword:
                            idOrKeyword = res.StringResult;
                            flag = false;
                            break;
                        case PromptStatus.Cancel:
                        case PromptStatus.None:
                        case PromptStatus.Error:
                            flag = false;
                            break;
                        case PromptStatus.OK:
                            idget = res.ObjectId;
                            break;
                    }
                }
                else if (opt != null)
                {
                    pnes = ed.GetNestedEntity(opt);
                    switch (pnes.Status)
                    {
                        case PromptStatus.Cancel:
                            flag = false;
                            break;
                        case PromptStatus.None:
                            flag = false;
                            break;
                        case PromptStatus.Error:
                            flag = false;
                            break;
                        case PromptStatus.OK:
                            idget = pnes.ObjectId;
                            break;
                    }
                }
                var listtype = new List<string>();
                //类型要求为空,代表任何类型都接受,否则加入表内判断.
                if (entType != null)
                {
                    foreach (var item in entType)
                    {
                        listtype.Add(item.ToString());
                    }
                }
                if (idget.IsOk())
                {
                    //图元类型匹配
                    Entity ent = idget.ToEntity(tr);
                    if (entType == null || entType.Count == 0)
                    {
                        flag = false;
                        idOrKeyword = idget;
                    }
                    else if (listtype.Contains(ent.GetType().Name))
                    {
                        flag = false;
                        idOrKeyword = idget;
                    }
                }
                else
                {
                    break;
                }
            }
            CadSystem.Setvar("errno", "0");//空格结束产生的错误系统变量,会影响到下一次使用错误系统变量的判断.
            return idOrKeyword;
        }
View Code

id.isok

        /// <summary>
        /// id有效,未被删除
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public static bool IsOk(this ObjectId id)
        {
            return !id.IsNull && id.IsValid && !id.IsErased && !id.IsEffectivelyErased && id.IsResident;
        }
View Code

射线法:  

        /// <summary>
        /// 判断点在闭合多段线内(线上也是内)射线法
        /// </summary>
        /// <param name="p">判断的点</param>
        /// <param name="pts">边界点集</param>
        /// <returns></returns> 
        public static bool IsPointInPL(Point3d p, IEnumerable<Point3d> pts)
        {
            var px = p.X;
            var py = p.Y;
            var flag = false;

            var poly = pts.ToArray();
            int l = poly.Length;
            int j = l - 1;

            for (var i = 0; i < l; i++)
            {
                var pt1x = poly[i].X;//
                var pt1y = poly[i].Y;
                var pt2x = poly[j].X;//
                var pt2y = poly[j].Y;

                // 点与多边形顶点重合
                if ((pt1x.Eq(px) && pt1y.Eq(py)) || (pt2x.Eq(px) && pt2y.Eq(py)))
                {
                    return true;
                }
                // 判断线段两端点是否在射线两侧
                if ((pt1y < py && pt2y >= py) || (pt1y >= py && pt2y < py))
                {
                    // 线段上与射线 Y 坐标相同的点的 X 坐标
                    var x = pt1x + (py - pt1y) * (pt2x - pt1x) / (pt2y - pt1y);

                    // 点在多边形的边上
                    if (x.Eq(px))
                    {
                        return true;
                    }
                    // 射线穿过多边形的边界
                    if (x > px)
                    {
                        flag = !flag;
                    }
                }
                j = i;
            }
            // 射线穿过多边形边界的次数为奇数时点在多边形内
            return flag;
        }
View Code

(完)

原文地址:https://www.cnblogs.com/JJBox/p/14062009.html