明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 1744|回复: 12

[讨论] 判断:一个点在封闭曲线内

[复制链接]
发表于 2024-3-28 08:30:15 | 显示全部楼层 |阅读模式
本帖最后由 自贡黄明儒 于 2024-3-28 08:34 编辑

判断:一个点在封闭曲线内
在acad中,使用bloy,效果不错,基本上是万能的。不仅仅是封闭曲线,任何选择集都可以。
但在bcad中就不行了。我按照老迈的办法,使用(command "_.boundary" "a" "i" "y" "b" "n" ss "" "" "non" p "")
效果不好,改为caoyin版主的办法,效果也不好
  1. (defun HH_PtInCurve
  2.    (PT CURVE / GetInters OBJ MINPT MAXPT E PS LST X Y)
  3.     (defun GetInters (OBJ1 OBJ2 / PS LST)
  4.       (setq PS (vla-intersectwith OBJ1 OBJ2 0)
  5.       PS (vl-catch-all-apply
  6.      'vlax-safearray->list
  7.      (list (vlax-variant-value PS))
  8.          )
  9.       )
  10.       (if (and PS (not (vl-catch-all-error-p PS)))
  11.   (while (setq LST (cons (list (car PS) (cadr PS)) LST)
  12.          PS   (cdddr PS)
  13.          )
  14.   )
  15.       )
  16.       LST
  17.     )
  18.     (if  (equal (vlax-curve-getClosestPointTo CURVE PT) PT 1E-6)
  19.       0
  20.       (progn
  21.   (setq OBJ (vlax-ename->vla-object CURVE))
  22.   (vla-getboundingbox OBJ 'MINPT 'MAXPT)
  23.   (mapcar  '(lambda (X) (set X (vlax-safearray->list (eval X))))
  24.     '(MINPT MAXPT)
  25.   )
  26.   (entmake
  27.     (list  '(0 . "LINE")
  28.     (list 10 (car MINPT) (cadr PT))
  29.     (list 11 (car MAXPT) (cadr PT))
  30.     '(60 . 1)
  31.     )
  32.   )
  33.   (setq E     (entlast)
  34.         LST1 (GetInters OBJ (vlax-ename->vla-object E))
  35.   )
  36.   (entdel E)
  37.   (if LST1
  38.     (setq  LST1 (vl-remove-if
  39.            '(lambda  (X / PP A)
  40.         (setq  PP (vlax-curve-getParamAtPoint CURVE X)
  41.         A  (angle '(0 0)
  42.             (vlax-curve-getFirstDeriv CURVE PP)
  43.            )
  44.         )
  45.         (or (equal A 0 1E-6)
  46.             (equal A PI 1E-6)
  47.             (equal A (* PI 2) 1E-6)
  48.             (equal (fix PP) PP 1E-6)
  49.         )
  50.       )
  51.            LST1
  52.          )
  53.     )
  54.   )
  55.   (entmake
  56.     (list  '(0 . "LINE")
  57.     (list 10 (car PT) (cadr MAXPT))
  58.     (list 11 (car PT) (cadr MINPT))
  59.     '(60 . 0)
  60.     )
  61.   )
  62.   (setq E     (entlast)
  63.         LST2 (GetInters OBJ (vlax-ename->vla-object E))
  64.   )
  65.   (entdel E)
  66.   (if LST2
  67.     (setq  LST2 (vl-remove-if
  68.            '(lambda  (X / PP A)
  69.         (setq  X  (vlax-curve-getClosestPointTo CURVE X)
  70.         PP (vlax-curve-getParamAtPoint CURVE X)
  71.         A  (angle (vlax-curve-getFirstDeriv CURVE PP)
  72.             '(0 0)
  73.            )
  74.         )
  75.         (or (equal A (/ PI 2) 1E-6)
  76.             (equal A (* PI 1.5) 1E-6)
  77.             (equal (fix PP) PP 1E-6)
  78.         )
  79.       )
  80.            LST2
  81.          )
  82.     )
  83.   )
  84.   (and
  85.     LST1
  86.     LST2
  87.     (progn (setq X (vl-sort-i (mapcar 'car (cons PT LST1)) '<)
  88.            Y (length (member 0 X))
  89.      )
  90.      (and (zerop (rem Y 2)) (= (rem (- (length X) Y) 2) 1))
  91.     )
  92.     (progn (setq X (vl-sort-i (mapcar 'cadr (cons PT LST2)) '<)
  93.            Y (length (member 0 X))
  94.      )
  95.      (and (zerop (rem Y 2)) (= (rem (- (length X) Y) 2) 1))
  96.     )
  97.   )
  98.       )
  99.     )
  100.   )


找度娘,搜到结果如下
;;;1,如果该直线与封闭图形无交点或只有一个交点(切点),则此点在封闭图形外面;
;;;2,如果该直线与封闭图形有2个交点,且此点在这两个交点之间,则此点在封闭图形
;;;里面;在这两个交点之外,则此点在封闭图形外面;
;;;3,如果该直线与封闭图形有多个交点(不含切点),此点在这些交点之间时,此点
;;;任一侧的交点数为奇数则此点在封闭图形里面;此点任一侧的交点数为偶数则此点
;;;在封闭图形外面;此点不在这些交点之间时此点在封闭图形外面


动手写一个,效果好像还可以,如下
  1. ;;(MakeXray (setq p(getpoint)) '(0 1))
  2. ;;'(-1 0) 向左  '(0 1)向上 '(1 0)向右 '(0 -1)向下
  3. (defun MakeXray  (p vector)
  4.   (entmakeX
  5.     (list
  6.       '(0 . "RAY")
  7.       '(100 . "AcDbEntity")
  8.       '(100 . "AcDbRay")
  9.       (cons 10 p)
  10.       (cons 11 vector)
  11.     )
  12.   )
  13. )

  14. ;;偶数判断
  15. ;;(IsEven 2)=>T
  16. (defun IsEven (x)
  17.   (/= 1 (logand x 1))
  18. )

  19. ;;向左产生一条射线ray
  20. ;; (setq ray (MakeXray p '(-1 0)))
  21. (defun HH_PtInCurve (p curve ray / A B FLAG IN L PTS)
  22.   (setq Flag T)
  23.   (setq in nil)
  24.   (setq L '(((-1 0) (1 0)) ((0 1) (0 -1))))
  25.   ;;射线移位
  26.   (entmod (append (entget ray) (list (cons 10 p))))
  27.   ;;旋转射线
  28.   (while (and (setq a (car L)) Flag)
  29.     (setq L (cdr L))
  30.     (setq b (car a))
  31.     (setq a (cadr a))
  32.     (entmod (append (entget ray) (list (cons 11 b))))
  33.     (setq pts (HH:TwoEntsInters ray curve 0))
  34.     (cond ((not pts) (setq Flag nil))
  35.     ((IsEven (length pts)) (setq Flag nil)) ;不严谨
  36.     (T
  37.      (entmod (append (entget ray) (list (cons 11 a))))
  38.      (setq pts (HH:TwoEntsInters ray curve 0))
  39.      (cond
  40.        ((not pts) (setq Flag nil))
  41.        ((IsEven (length pts)) (setq Flag nil)) ;不严谨
  42.        (T (setq in T))
  43.      )
  44.     )
  45.     )
  46.   )
  47.   in
  48. )

  49. ;;判断准则
  50. ;;1 如果所有端点首尾相连,则直接联接成多段线
  51. ;;2 如果只有一个端点是孤立的,则奇怪,可掉这条线
  52. ;;3 如果有两个端点孤立:是同一条线,奇怪,可去掉;如果是不同的线,可直接联接成多段线
  53. ;;4 如果大于两个端点孤立的,则相互延伸剪切,然后组成多段线。从一条线端点到另一条线最近的距离开始
  54. ;;0 [功能] 两对象交点
  55. ;;[功能] 两对象交点列表
  56. ;;acextendnone 0 不延伸
  57. ;;acextendthisentity 1 延伸基准对象
  58. ;;acextendotherentity 2
  59. ;;acextendboth 3
  60. ;;示例(HH:TwoEntsInters (car(entsel)) (car(entsel)) acextendboth)
  61. (defun HH:TwoEntsInters        (e1 e2 Flag / PTL PTS)
  62.   (if (equal 'ENAME (type e1))
  63.     (setq e1 (vlax-ename->vla-object e1))
  64.   )
  65.   (if (equal 'ENAME (type e2))
  66.     (setq e2 (vlax-ename->vla-object e2))
  67.   )
  68.   (setq pts (vlax-invoke e1 'Intersectwith e2 Flag))
  69.   (while pts
  70.     (setq ptl (cons (list (car pts) (cadr pts)) ptl))
  71.     (setq pts (cdddr pts))
  72.   )
  73.   ptl
  74. )




;;;;;测试
(defun C:t1 (/ CURVE P RAY)
  (setq ray (MakeXray '(0 0) '(-1 0)))
  (setq curve (car (entsel "\n封闭曲线")))
  (setq p (getpoint "\n点"))
  (if (HH_PtInCurve p curve ray)
    (alert "点在曲线内")
    (alert "外")
  )
  (entdel ray)
  (princ)
)


评分

参与人数 7明经币 +7 金钱 +10 收起 理由
USER2128 + 1 很给力!
tigcat + 1 + 10
dtucad + 1 赞一个!
ssyfeng + 1 很给力!
xshrimp + 1 赞一个!
天天问 + 1
飞雪神光 + 1 我觉得boundary 局限性也很大 视口中图元越.

查看全部评分

"觉得好,就打赏"
还没有人打赏,支持一下
发表于 2024-3-29 16:36:31 | 显示全部楼层
(defun PtInPoly (/ clst apt delta ints oLine oPline pl pline someAngle)
  (vl-load-com)
  (cond
    ((setq pline (car (entsel "\nPolyline: ")))
     ;; NO error checking .. assume a lwpoly is selected!
     (setq oPline (vlax-ename->vla-object pline)
           ;; pick point to investigate
           aPt       (getpoint "\nPick point: ")
           ;; initialize starting angle for "ray"
           someAngle 0.0
           ;; set delta angle for rotation of "ray"
           delta     (/ (* 2 pi) 8)
     )
     (cond
       ;; start by making a "ray" shooting out from aPt
       ;; (should use vla-add but what the heck)
       ;; (should also use a real RAY and manipulate
       ;;  unit vector .. but what the heck)
       ((entmake (list '(0 . "LINE") (cons 10 aPt)
                       (cons 11 (polar aPt 0.0 100.0))
                 )
        )
        (setq oline (vlax-ename->vla-object (entlast)))
        (repeat 8
          (cond
            ;; get intersection points with pline and "ray"
            ((setq ints (vla-intersectwith oPline oLine acExtendNone))
             ;; should be using vlax-...-u-bounds and all that to check
             ;; safearray (but what the heck, this is quicker to write)
             (if (not (vl-catch-all-error-p (setq ints (vl-catch-all-apply
                                     'vlax-safearray->list
                                     (list (vlax-variant-value ints)))
                        )
                      )
                 )
               ;; just put nil for uneven number of hits and T for even
               (setq clst (cons (not (zerop (rem (length ints) 2.0))) clst))
             )
            )
          )
          ;; pause to see the "ray" move around
          (while (not (grread nil 10)))
          ;; move endpoint of "ray"
          (vla-put-endpoint oLine (vlax-3D-point
              (polar aPt (setq someAngle (+ delta someAngle)) 100.0)
            )
          )
        )
        (vla-delete oLine)
        (vlax-release-object oLine)
        (vlax-release-object oPline)
       )
     )
    )
  )
  ;; .. and a lazy decoding of result:
  (cond ((not (member 'nil clst))(princ "Inside"))
        ((not (member 'T clst))(princ "Outside"))
        ((princ "Probably on an edge or vertex")))
  (terpri)
  clst
)

info from:
https://www.theswamp.org/index.php?topic=1890.0
 楼主| 发表于 2024-3-28 10:38:58 | 显示全部楼层
4条ray,交点出现一奇一偶,或者一偶一奇,概率相当小了
  1. (defun HH_PtInCurve (p curve ray / A B FLAG IN L PTS)
  2.   (setq Flag T)
  3.   (setq in nil)
  4.   (setq L '(((-1 0) (1 0)) ((0 1) (0 -1))))
  5.   ;;射线移位
  6.   (entmod (append (entget ray) (list (cons 10 p))))
  7.   ;;旋转射线
  8.   (while (and (setq a (car L)) Flag)
  9.     (setq L (cdr L))
  10.     (setq b (car a))
  11.     (setq a (cadr a))
  12.     (entmod (append (entget ray) (list (cons 11 b))))
  13.     (setq pts (HH:TwoEntsInters ray curve 0))
  14.     (cond ((not pts) (setq Flag nil))
  15.           ((IsEven (length pts))
  16.             (entmod (append (entget ray) (list (cons 11 a))))
  17.             (setq pts (HH:TwoEntsInters ray curve 0))
  18.             (cond
  19.               ((not pts) (setq Flag nil))
  20.               ((IsEven (length pts)) (setq Flag nil)) ;2次偶数,判断点在曲线外,这比较合理
  21.               ;;一偶一奇,不好判断,让程序继续运行,从另外两个方向判断
  22.               ;;如果还是出现一偶一奇,in仍为nil,表示点在封闭曲线外
  23.             )
  24.           )
  25.           (T
  26.            (entmod (append (entget ray) (list (cons 11 a))))
  27.            (setq pts (HH:TwoEntsInters ray curve 0))
  28.            (cond
  29.              ((not pts) (setq Flag nil))
  30.              ((IsEven (length pts)))
  31.              ;;一奇一偶,不好判断,让程序继续运行,从另外两个方向判断
  32.              ;;如果还是出现一奇一偶,in仍为nil,表示点在封闭曲线外
  33.              (T (setq in T));至少2次奇数,判断点在封闭曲线内,这比较合理
  34.            )
  35.           )
  36.     )
  37.   )
  38.   in
  39. )
 楼主| 发表于 2024-3-29 11:37:40 | 显示全部楼层
dtucad 发表于 2024-3-28 23:22
黄总666 以前有个射线法 好像不够精确

多旋转一下射线,应该更可靠。从我使用来看,旋转4次,就足够了。
发表于 2024-3-28 09:36:44 | 显示全部楼层
多谢大佬示范
发表于 2024-3-28 15:10:33 | 显示全部楼层
谢谢分享,赞一个!
发表于 2024-3-28 15:14:51 来自手机 | 显示全部楼层
赞一个!!学习学习。
发表于 2024-3-28 20:54:25 | 显示全部楼层
谢谢分享,学习了
发表于 2024-3-28 20:55:58 | 显示全部楼层
谢谢黄总分享代码,黄老的cad国产了?

点评

荷兰bricscad,acad的高仿  发表于 2024-3-29 07:56
发表于 2024-3-28 23:22:16 | 显示全部楼层
本帖最后由 dtucad 于 2024-3-28 23:31 编辑

黄总666 以前有个射线法 好像不够精确
您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|CAD论坛|CAD教程|CAD下载|联系我们|关于明经|明经通道 ( 粤ICP备05003914号 )  
©2000-2023 明经通道 版权所有 本站代码,在未取得本站及作者授权的情况下,不得用于商业用途

GMT+8, 2024-11-25 10:07 , Processed in 0.195982 second(s), 28 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表