;;说明:判断点在多段线构成的多边形内侧还是外侧
;;参数:pt:点
;;参数:var:多段线构成的多边形图元名或者多边型点表
;;参数:flag:如果为T,则点在多边形上时,则判断为多边形内侧,否则则判断为外侧
;;返回:内侧为:T,外侧为:nil
;;(PtIsInPoly (getpoint) (car (entsel)) t)
;;(PtIsInPoly (getpoint) (list (getpoint) (getpoint)) t)
(defun PtIsInPoly(pt var flag / getptlst judgestart vlist)
(defun getptlst(e) (mapcar 'cdr (vl-remove-if-not (function (lambda(x) (= 10 (car x)))) (entget e))))
(defun judgestart(vlist / cnt diff idx len numints online p1 p1code p1x p1y p2 p2code p2x p2y vlist x xdiff xx y ydiff)
(if (not (equal (car vlist) (last vlist)))
(setq vlist (append vlist (list (car vlist))))
)
(setq X (car pt)
Y (cadr pt)
len (length vlist)
cnt 0
Idx 0
NumInts 0
OnLine nil
)
(while (and (not OnLine) (< cnt len))
(setq
p2 (nth cnt vlist)
p2x (car p2)
p2y (cadr p2)
p2code (if (>= p2y y) 2 0)
p2code (if (>= p2x x) (1+ p2code) p2code)
)
(if p1
(setq diff (boole 6 p1code p2code)
ydiff (boole 1 diff 2)
xdiff (boole 1 diff 1)
p1x (car p1)
p1y (cadr p1)
)
)
(if (= ydiff 2)
(progn
(setq xx (+ p1x (* (/ (- p2x p1x) 1. (- p2y p1y)) (- y p1y))))
(cond
((equal xx x 0.0001) (setq online T))
((> xx x) (setq NumInts (1+ NumInts)))
)
)
)
(if (and (= xdiff 1) (= y p1y p2y)) (setq OnLine T))
(setq p1code p2code p1 p2 cnt (1+ cnt))
)
(if Online flag (= (boole 1 NumInts 1) 0001))
)
(if (equal (type var) 'ENAME)
(judgestart (getptlst var))
(if (and var (listp var) (> (length var) 1)) (judgestart var) (progn (princ "\n点表输入有误!") (prin1)))
)
)
=======================================================================================
以下原文链接
矩形只是多段线的一种解,但是矩形可以利用叉乘做到快速求解,这方面可以自行去搞搞.
这里提供一个最通用的.
测试命令:
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;
}
var peo = new PromptEntityOptions(Environment.NewLine + "点选多段线")
{
AllowObjectOnLockedLayer = false,
AllowNone = false
};
var res = ed.GetEntity(peo);
if(res.Status != PromptStatus.OK) return;
db.Action(tr=>
{
var ent2 =res.ObjectId.ToEntity(tr);
if (ent is Polyline pl && MathTool.IsPointInPL(ppr.Value, pl.GetPoint3ds()))
{
ed.WriteMessage(Environment.NewLine + "内内内内内内内内");
}
else
{
ed.WriteMessage(Environment.NewLine + "外外外外外外外外外外外");
}
});
}
}
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;
}
射线法:
/// <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;
}