admin1 发表于 2024-4-4 08:35:51

[函数] 判断点在封闭曲线内,跟随黄总的步伐



;测试
(defun c:tt (/ en pt pts)
      (and
                (setq pt (getpoint))
                (setq en (car (entsel "\n选闭合曲线")))
                (setq pts (mapcar '(lambda (x) (trans (cdr x) 0 1)) (vl-remove-if-not '(lambda (x) (= 10 (car x))) (entget en))))
                (princ "\n第一种(不支持弧线):")
                (princ (JudPtinPts pt pts 1e-6))
                (princ "\n第二种(支持弧线):")
                (princ (JudPtinCurr pt en 1e-6))
      )
      (princ)
)








;第一种
;判断点是否在非自交多边形内,使用射线交叉法,从要测试的点向任意方向引一条射线,统计射线与多边形边界的交点数量。如果交点数目是奇数,则点位于多边形内部;如果是偶数,则点位于多边形外部。如果交点为多边形顶点可能无法正确判断,此时旋转射线重新判断。
;参数:pt判断的点、pts多边形点表、fz误差
;返回:1在内部、0在线上、-1在外部
(defun JudPtinPts (pt pts fz / box d i inter k line lines lines-tmp memberfz ray)
(defun MemberFz (pt lst fz);带误差的member
    (vl-some (function (lambda(x) (equal pt x fz))) lst)
)

(setq lines (mapcar (function list) pts (append (cdr pts) (list (car pts)))))
(if (vl-some ;判断点在线上
      (function (lambda (x / ang1 ang2 p1 p2)
                  (setq p1 (car x))
                  (setq p2 (cadr x))
                  (or
                      (or
                        (equal pt p1 fz)
                        (equal pt p2 fz)
                      )
                      (and
                        (setq ang1 (angle p1 pt))
                        (setq ang2 (angle pt p2))
                        (or (equal ang1 ang2 1e-6)
                        (equal (abs (- ang1 ang2)) (* pi 2) 1e-6)
                        )
                      )
                  )
                  )
      )
      lines
      )
    0;在线上
    (progn;判断交点数量
      (setq box (mapcar (function (lambda (a b) (apply (function mapcar) (cons a b)))) '(min max) (list pts pts)))
      (setq d (+ (apply 'distance box) (distance pt (car pts))))
      (setq ray (list pt (polar pt 0 d)));虚拟一条足够长的射线
      (setq lines-tmp lines)
      (setq i 0 k 0)
      (while (and lines-tmp (< k 360))
      (setq line (car lines-tmp))
      (setq lines-tmp (cdr lines-tmp))
      (if (setq inter (apply 'inters (append ray line)));有交点
          (if (not (MemberFz inter pts fz));且交点不为顶点
            (setq i (1+ i));交点数量
            (setq i 0;归零
            k (1+ k)
            ray (list pt (polar pt (* (/ pi 180) k) d));射线旋转1°
            lines-tmp lines;重新判断
            )
          )
      )
      )
      (cond
      ((zerop (rem i 2)) -1);偶数个交点,在线外
      (t 1);奇数,在线内
      )
    )
)
)














;第二种
;判断点是否在封闭曲线内,生成图元射线找与封闭曲线交点(判断原理同上),支持多段线、圆、椭圆、样条曲线等封闭曲线
;参数:pt判断的点、e曲线图元名、fz误差
;返回:1在内部、0在线上、-1在外部
(defun JudPtinCurr (pt e fz / *error* ang cp ed getinter i islock isvertex its k la layobj list->3pair loop mkray obj-cur obj-ray ray vlay)
;错误处理
(defun *error* (msg)
    (if (not (vlax-erased-p obj-ray))
      (vla-Delete obj-ray)
    )
    (princ msg)
)
;表转3D点表
(defun list->3pair (old / new)
    (while (setq new (cons (list (car old) (cadr old) (caddr old)) new) old (cdddr old)))
    (reverse new)
)
;找2个对象的交点 不延长 返回:交点列表
(defun getinter (obj1 obj2 / inter iplist re)
    (if (not (vl-catch-all-error-p
               (setq iplist (vl-catch-all-apply 'vlax-safearray->list
                              (list (vlax-variant-value (vla-intersectwith obj1 obj2 acextendnone)))
                            ))))
      (list->3pair iplist)
    )
)
;判断交点是否为曲线顶点或在射线角度上的切点
(defun IsVertex (obj pt ang / ang-de de n name)
    (if (and
          (setq name (vla-get-ObjectName obj))
          (setq n (vlax-curve-getParamAtPoint obj pt))
      )
      (if (and
            (or
            (= name "AcDbPolyline")
            (= name "AcDb2dPolyline")
            (= name "AcDb3dPolyline")
            (= name "AcDbSpline")
            )
            (equal (fix n) n 1e-8)
          )
      t ;为顶点
      (and ang
          (setq de (vlax-curve-getFirstDeriv obj n))
          (setq ang-de (angle '(0 0 0) de))
          (or ;为切点
            (equal ang-de ang 1e-8)
            (equal ang-de (+ pi ang) 1e-8)
            (equal ang-de (+ (* pi 2) ang) 1e-8)
          )
      )
      )
    )
)
;生成射线 返回图元名
(defun MKRay (p1 p2)
    (entmakeX
      (list
      '(0 . "RAY")
      '(100 . "AcDbEntity")
      '(100 . "AcDbRay")
      (cons 10 p1)
      (cons 11 (mapcar '- p2 p1))
      )
    )
)

(setq obj-cur (vlax-ename->vla-object e))
(if (and
      (setq cp (vlax-curve-getClosestPointTo obj-cur pt))
      (equal cp pt fz)
      )
    0;在线上
    (progn
      (if (and ;解锁当前图层
            (setq la (getvar "CLAYER"))
            (setq layobj (vla-get-Layers (vla-get-activedocument (vlax-get-acad-object))))
            (setq vlay (vla-item layobj la))
          )
      (if (= (vla-get-lock vlay) :vlax-true)
          (progn
            (vla-put-lock vlay :vlax-false)
            (setq islock t)
          )
      )
      )
      (setq ang 0)
      (setq pt (trans pt 1 0))
      (setq ray (MKRay pt (polar pt ang 10)))
      (setq ed (entget ray))
      (setq obj-ray (vlax-ename->vla-object ray))
      (setq k 0 loop t)
      (while (and loop (< k 360))
      (if (setq its (getinter obj-cur obj-ray));有交点
          (progn
            (if (vl-every (function (lambda(p) (not (IsVertex obj-cur p ang)))) its)
            (setq i (length its);交点数量
                loop nil
            )
            (progn;交点为顶点或切点
                (setq k (1+ k) ang (* (/ pi 180) k))
                (entmod (subst (cons 11 (mapcar '- (polar pt ang 10) pt)) (assoc 11 ed) ed));射线旋转1°
            )
            )
          )
          (setq loop nil)
      )
      )
      (if (not (vlax-erased-p obj-ray))
      (vla-Delete obj-ray)
      )
      (if islock ;恢复锁定
      (vla-put-lock vlay :vlax-true)
      )
      (cond
      ((or (not i)(zerop (rem i 2))) -1);偶数个交点,在线外
      (t 1);奇数,在线内
      )
    )
)
)

页: [1]
查看完整版本: [函数] 判断点在封闭曲线内,跟随黄总的步伐