Aller au contenu

Point à l\'intérieur d\'une polyligne


Messages recommandés

Posté(e)

La question revenant souvent, j'ai essayé d'aboutir une routine pour évaluer si un point est à l'intérieur d'une polyligne fermée.

J'ai repris la méthode de _zebulon (ici) consistant à consistant à compter le nomre d'intersections entre une ligne partant du point spécifié et la polyligne : si le nombre est impair, le point est à l'intérieur de la polyligne.

Pour parer à toute éventualité, les points d'intersection correspondant à un sommet ou un point tangent à un arc sont écartés.

 

La routine fonctione quelque soient le SCU courant et le SCO de la polyligne.

 

EDIT : Les polylignes croisées (auto-intersection) posant encore des problèmes, j'ai supprimé les parties de code qui tentaient de les traiter.

 

;; INSIDE-P (gile) -version 2.1-
;; Evalue si le point est à l'intérieur d'une polyligne fermée
;;
;;Arguments
;; pt : le point (coordonnées SCG)
;; pl : la polyligne fermée (ename ou vla-object)
;;
;; Retour
;; T si le point est à l'intérieur de la polyligne
;; nil si le point est à l'extérieur ou sur la polyligne

(defun inside-p	(pt pl / space norm line int self)
 (vl-load-com)
 (or (= (type pl) 'VLA-OBJECT)
     (setq pl (vlax-ename->vla-object pl))
 )
 (setq	space (if (= (getvar "CVPORT") 1)
	(vla-get-PaperSpace
	  (vla-get-activedocument (vlax-get-acad-object))
	)
	(vla-get-ModelSpace
	  (vla-get-activedocument (vlax-get-acad-object))
	)
      )
norm  (vlax-get pl 'Normal)
line  (vla-addLine
	space
	(vlax-3d-point pt)
	(vlax-3d-point
	  (mapcar '+
		  pt
		  (trans (list (vla-get-Length pl) 0.0 0.0) norm 0)
	  )
	)
      )
int   (3d-coord->pt-lst
	(vlax-invoke pl 'IntersectWith line acExtendNone)
      )
 )
 (vla-delete line)
 (and
   int
   (not (vlax-curve-getParamAtPoint pl pt))
   (=
     1
     (rem
(length
  (vl-remove-if
    '(lambda (x / pa p0 p- p+ s1 s2)
       (setq pa (vlax-curve-getParamAtPoint pl x))
       (or
	 (and
	   (equal (round pa) pa 1e-9)
	   (setq p- (cond
		      ((setq p-
			      (vlax-curve-getPointAtParam pl (- pa 1e-8))
		       )
		       (trans p- 0 norm)
		      )
		      (T
		       (trans (vlax-curve-getPointAtParam
				pl
				(- (vlax-curve-getEndParam pl) 1e-8)
			      )
			      0
			      norm
		       )
		      )
		    )
		 p+ (trans (vlax-curve-getPointAtParam pl (+ pa 1e-8))
			   0
			   norm
		    )
		 p0 (trans pt 0 norm)
		 s1 (sin (angle p0 p-))
		 s2 (sin (angle p0 p+))
	   )
	   (or (and (		 )
	 (and
	   (/= 0.0 (vla-getBulge pl (fix pa)))
	   (equal
	     '(0.0 0.0)
	     (cdr (trans (vlax-curve-getFirstDeriv pl pa) 0 norm))
	     1e-9
	   )
	 )
       )
     )
    int
  )
)
2
     )
   )
 )
)

;;; 3d-coord->pt-lst Convertit une liste de coordonnées 3D en liste de points
;;; (3d-coord->pt-lst '(1.0 2.0 3.0 4.0 5.0 6.0)) -> ((1.0 2.0 3.0) (4.0 5.0 6.0))

(defun 3d-coord->pt-lst	(lst)
 (if lst
   (cons (list (car lst) (cadr lst) (caddr lst))
  (3d-coord->pt-lst (cdddr lst))
   )
 )
)

;;; ROUND Arrondit à l'entier le plus proche
(defun round (num)
 (fix ((if (minusp num) - +) num 0.5))
)

[Edité le 2/8/2007 par (gile)][Edité le 2/8/2007 par (gile)]

 

[Edité le 4/8/2007 par (gile)]

Gilles Chanteau - gileCAD - GitHub
Développements sur mesure pour AutoCAD

Posté(e)

J'ai modifié/amélioré le code ci-dessus.

Je pense avoir maintenant cerné tous les cas de figure particuliers.

 

Pour ceux qui voudraient tester :

 

(defun c:test ()
 (and
   (setq ent (car (entsel "\nSélectionnez une polyligne: ")))
   (setq ent (vlax-ename->vla-object ent))
   (= (vla-get-ObjectName ent) "AcDbPolyline")
   (= (vla-get-Closed ent) :vlax-true)
   (setq pt (trans (getpoint "\nSpécifiez un point: ") 1 0))
   (if	(inside-p pt ent)
     (alert "Dedans")
     (alert "Dehors")
   )
 )
 (princ)
) 

 

[Edité le 2/8/2007 par (gile)]

Gilles Chanteau - gileCAD - GitHub
Développements sur mesure pour AutoCAD

Posté(e)

 

Bonjour

 

Je tiens tout particulièrement à remercier tous ceux comme (Gile), Patrick_35, Bred, etc et bien d'autres ... pour leur "dévouement" et aussi la qualité des programmes qu'ils écrivent à partir des demandes des différents membres de Cadxp :) :D :cool:

 

Longue vie et bonne santé à tous ces vaillants développeurs !

 

Le Decapode "reconnaissant"

 

Autodesk Expert Elite Team

Posté(e)

Merci lecrabe, mais la publication de codes n'est pas que "désintéressée", ce faisant, de vaillants testeurs apportent leur aide débusquant les dysfonctionnements et en proposant des améliorations. ;)

 

Trouver toutes les situations qui peuvent faire échouer une routine est souvent le plus difficile.

Dans le cas présent, je continue à trouver des situations, peu probables mais éventuelles.

 

Je vais essayer d'expliquer un peu mieux comment fonctionne la routine.

 

À partir du point spécifié, un ligne parallèle à l'axe des X du système de coordonnées de l'objet est dessinée et le nombre de points d'intersection entre la ligne et la polyligne, selon qu'il est pair ou impair, indique si le point est à l'intérieur de la polyligne

 

http://img390.imageshack.us/img390/6286/inside1qe0.png

 

Ensuite, il s'agit de trouver tous les cas qui pourraient fausser le résultat, et écarter ces points du comptage.

Présentement, sont écartés :

1 - la ligne passe par un sommet saillant de la polyligne

2 - la ligne tangente avec un arc de la polyligne

3 - la ligne se confond avec un segment (un des sommets est écarté)

4 - la ligne passe par un point "d'auto-intersection" de la polyligne

 

http://img470.imageshack.us/img470/2460/inside2ea0.png

 

Si certains envisagaient d'autres cas de figure, merci d'avance de les signaler.

Gilles Chanteau - gileCAD - GitHub
Développements sur mesure pour AutoCAD

Posté(e)

Très bien la routine!Grand merci

Bon j'avoue avec un peu de mal a comprends son fonctionnement vu qu'elle est truffé de vla,et c'est pour ça que je vais poser la question suivante:

Peut elle etre modifié pour savoir un objet est a l'intérieur d'un autre(ployligne bien sur) a la place d'un point?

Posté(e)

Salut,

 

Peut elle etre modifié pour savoir un objet est a l'intérieur d'un autre(ployligne bien sur)

 

Pour ça, il me semble plus rationnel d'utiliser la routine SelByObj (ou encore sur cette page dans Spécial Sélections), qui crée un jeu de sélection (Fenêtre ou capture) à partir d'un objet (polyligne, cercle ou ellipse).

 

un exemple d'expression ou rech est le nom d'entité (ename) de l'objet recherché et selobj celui de l'objet utilisé pour la sélection qui retourne T si l'objet est complètement à l'intérieur, nil sinon.

 

(= 'ENAME (type (ssmemb (car (entsel)) (selbyobj (car (entsel)) "WP" nil)))) 

 

NOTA : en vue 3d, SelByObj fonctionne en fonction de la vue courante.

 

[Edité le 7/8/2007 par (gile)]

Gilles Chanteau - gileCAD - GitHub
Développements sur mesure pour AutoCAD

Posté(e)
J'ai repris la méthode de _zebulon

Tiens, on parle de moi ?

 

Je tiens à préciser que ma petite tête n'est pas assez intelligente pour inventer une telle méthode. Je la dois à mon premier maitre lisp (martin, si tu te reconnais...) qui, lui aussi, la doit sans doute à quelqu'un...

J'ai seulement tenté de répondre aux cas qui font échouer la méthode, en me basant sur une méthode faisant appel à la chance. (Gile) est plus mathématique dans sa démarche.

 

Amicalement

Zebulon_

 

C'est au pied du mur que l'on reconnaît le maçon ! (Anonyme)

C’est en restant au pied du mur qu’on ne voit que le mur (Anonyme aussi)

Créer un compte ou se connecter pour commenter

Vous devez être membre afin de pouvoir déposer un commentaire

Créer un compte

Créez un compte sur notre communauté. C’est facile !

Créer un nouveau compte

Se connecter

Vous avez déjà un compte ? Connectez-vous ici.

Connectez-vous maintenant
×
×
  • Créer...

Information importante

Nous avons placé des cookies sur votre appareil pour aider à améliorer ce site. Vous pouvez choisir d’ajuster vos paramètres de cookie, sinon nous supposerons que vous êtes d’accord pour continuer. Politique de confidentialité