Cette question de sommets de polyligne est récurrente sur les forums
et autres lieux de discussions et je présente ici une façon d'extraire les coordonnées des sommets.
Le but est de créer une liste (list) de tous les sommets d'une polyligne 2D.
Dans le titre j'ai précisé "à l'ancienne" car avec les nouvelles fonctions dont vous trouverez des explications avec les fonctions VL ce code est devenu obsolète et il est plus court de nos jours, malgré tout il fonctionne et on obtient ce qui est attendu et c'est un bon exercice de boucle et de liste il aura a minima valeur d'exemple.
J'utilise le principe utilisé dans les chapitres précédents en parcourant la liste DXF de la polyligne et j'extrais de cette dernière les valeurs des codes 10, en effet c'est le code 10 qui stocke les coordonnées des sommets.
Ce qui en langage naturel s'exprimerait :
Parcours de tous les éléments de la liste (list) de définition de l'entité et si cet élément a un code 10 (coordonnée de sommet) en extraire le contenu et le concaténer à la liste des sommets.
Le code en texte :
1 2 3 4 5 6 7 8 9 10 11 | (setq liste-sommets '() ent (car (entsel"\nChoix de la polyligne\n")) ent-liste (entget ent) n 0) (repeat (length ent-liste) (if (= 10 (car (nth n ent-liste))) (setq liste-sommets (cons (cdr (nth n ent-liste)) liste-sommets)) ) (setq n (+ 1 n)) ) (setq liste-sommets (reverse liste-sommets)) |
Quelques explications :
- Création d'une liste vide (optionnel mais pour la compréhension)
- Choix de l'entité et mémorisation de son nom d'entité (ename)
- Mise à zéro du compteur de position dans la liste (n sous forme d'entier (integer))
- Lancement d'une boucle qui se répètera un certain nombre de fois en fonction de la longueur de la liste.
- Test de code 10, si oui (code 10) on concatène la valeur à la liste existante (vide au premier tour, puis avec les coordonnées déjà extraites ensuite)
- Incrémentation du compteur qui sert à positionner le (nth)
- À la fin il est nécessaire de retourner la liste (reverse) pour trouver les sommets dans l'ordre du dessin de la polyligne, parce que la liste se concatène lors de la construction, dans l'ordre (point1) puis (point2 point1) puis (point3 point2 point1) et la fonction (reverse) va remettre la liste dans l'ordre attendu, soit (point1 point2 point3 point4..).
Simple, rapide, fonctionnel, tout le monde a compris ?
Améliorations :
Et si ce n'est pas une polyligne qui est cliquée à l'écran, que va-t'il se passer ?
RIEN dans la première version proposée, pas même un message vous en prévenant..., frustrant, incompréhensible et surtout pas très "propre" ni très "robuste".
Donc je vous propose deux façons de rendre plus robuste le code en testant si l'entité sélectionnée correspond bien à ce qu'attend le programme pour extraire les sommets, en l'occurrence une polyligne, LWPOLYLINE dans l'acception AutoCAD, car les anciennes polylignes (version 14) ne se rencontrent que très rarement de nos jours.
La première version ne va lancer la boucle que si (et seulement si) le test révèle que l'entité choisie est une LWPOLYLINE :
Le code en image :
Le code en texte :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | (setq ent (car (entsel "\nChoix de la polyligne\n"))) (if (= "LWPOLYLINE" (cdr (assoc 0 (entget ent)))) (progn (setq ent-liste (entget ent) n 0 ) ;_ Fin de setq (repeat (length ent-liste) (if (= 10 (car (nth n ent-liste))) (setq liste-sommets (cons (cdr (nth n ent-liste)) liste-sommets)) ) ;_ Fin de if (setq n (+ 1 n)) ) ;_ Fin de repeat ) ;_ Fin de progn (alert "\nNe fonctionne qu'avec une POLYLIGNE") ) ;_ Fin de if (setq liste-sommets (reverse liste-sommets)) |
Comme vous le notez en deuxième ligne il y a un IF,
(if (= "LWPOLYLINE" (cdr (assoc 0 (entget ent)))) |
Si ce IF renvoie une valeur vraie T (true) le programme continue, et puisqu'il y a plusieurs instructions à traiter on les regroupe en commençant ces instructions par un (progn) (ce qui permet de mettre plusieurs expressions après un IF)
Si ce IF renvoie une valeur fausse (false) ou une valeur nil, le programme saute les lignes du (progn) et va lire la ligne où il y a une instruction d'afficher une case d'alerte.
La deuxième version va faire le test de sélection AU MOMENT de la sélection, et au lieu de choisir if j'ai choisi while, c'est à dire que l'entité ne se sélectionnera pas tant que ce n'est pas une LWPOLYLINE, c'est une boucle sans message autre que "Choix de la polyligne".
Bien sûr une fois que le code a vérifié que la qualité de l'entité correspond à l'attente du programme, il sort de sa boucle (while) continue...
Le code en texte :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | (while (/= "LWPOLYLINE" (cdr (assoc 0 (entget (setq ent (car (entsel "\nChoix de la polyligne\n"))) ) ) ) ) ) ;_ Fin de while (setq ent-liste (entget ent) n 0 ) (repeat (length ent-liste) (if (= 10 (car (nth n ent-liste))) (setq liste-sommets (cons (cdr (nth n ent-liste)) liste-sommets)) ) ;_ Fin de if (setq n (+ 1 n)) ) ;_ Fin de repeat (setq liste-sommets (reverse liste-sommets)) |
Simple, rapide, fonctionnel, et un peu plus efficace, tout le monde a compris ?
d'autres améliorations sont encore possibles, on commence petit et on devient gourmand, par exemple on peut avoir besoin de faire cette liste sur plusieurs polylignes, on utilisera (ssget), entraînez-vous et en cas d'échec ou de questions prenez contact avec moi...
retour aux exercices sur polylignes
10 mars 2018,
mise à jour le 14 mars 2018
mise à jour le 23 mars 2018