Aller au contenu

[Challenge] Get-pt-list


Luna

Messages recommandés

Coucou,

Un exercice sans difficulté de programmation en tant que tel, mais le but étant de réfléchir "autrement". On a tous eu besoin à un moment donné eu besoin de récupérer la liste des sommets d'une polyligne et pour ce faire, on a chacun(e) sa méthode :3
Cependant je me suis bien souvent demandé, existe-t-il une solution plus rapide ?

Pour simplifier le challenge, l'exercice se porte uniquement sur les LWPOLYLINE, car les SPLINE, LINE, POLYLINE, ARC, etc ne possède pas les mêmes approches de programmation selon les objets. On peut prendre n'importe quel langage (en revanche je ne sais pas s'il existe un moyen d'utiliser un BenchMark sur plusieurs type de langage différent...?) histoire de comparer également les simplicités d'écriture selon les langages.

La liste retournée doit contenir l'ensemble des sommets de la polyligne, dans le sens de lecture de la polyligne (donc le sommet de départ au début, le dernier à la fin) et le but étant de trouver une version qui permet d'aller suffisamment vite en fonction du nombre de sommets.

J'ai généré sur le fichier ci-joint 4 polylignes ayant respectivement 10, 100, 1 000 et 10 000 sommets qui serviront de base (pour que tout le monde est la même). Le nombre de lignes importe peu, la vitesse d'exécution servira de comparaison. Concernant le Benchmark, j'utilise le BenchMark de Michael Puckett mais si vous en avez un autre, dite le histoire de maximiser les points communs pour la comparaison. Pour le temps de réponse, disons que je posterais mes versions ce we mais il n'y a pas de limite de temps 😜

Bisous,
Luna

get-pt-list.dwg BenchMark (Michael Puckett).lsp

Lien vers le commentaire
Partager sur d’autres sites

Salut,

Pour pouvoir faire des comparaisons, il faut que les fonctions soient similaires.
Tu devrais préciser la "signature" de la fonction à définir : argument(s) et type de retour, par exemple en AutoLISP l'argument serait le ename ou le vla-object de la polyligne et le type de retour une liste de "points". Je précise ça parce que si la fonction nécessite de sélectionner la polyligne toute comparaison en terme de rapidité devient caduque.

PS : ce type de fonction a été fait tellement de fois, j'ai retrouvé sur CADxp des messages dans lesquels je montre 6 façons différentes en "pur AutoLISP".

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

Lien vers le commentaire
Partager sur d’autres sites

Vui en effet je pensais avoir clarifier ce point ^^"
Donc dans l'idée il faut une fonction avec un seul argument correspondant à l'ename ou vla-object de la polyligne et le retour doit être sous forme de liste de point :
( (X1 Y1) (X2 Y2) ... (Xn-1 Yn-1) (Xn Yn) )avec n le nombre de sommets, l'indice 1 correspondant au point de départ de la polyligne, l'indice n correspondant au point d'arrivée de la polyligne.
La sélection de la polyligne sera donc fait en amont par le biais d'une variable pour tester :3

9 minutes ago, (gile) said:

PS : ce type de fonction a été fait tellement de fois, j'ai retrouvé sur CADxp des messages dans lesquels je montre 6 façons différentes en "pur AutoLISP".

En effet, le but de ce challenge c'est d'essayer de trouver plusieurs façons de faire en cherchant à approfondir les recherches au maximum. Chacun de nous à une manière de penser qui nous est propre (méthode itérative ou récursive par exemple), des fonctions de prédilection, etc. Donc ici le but étant de sortir des sentiers battus justement pour forcer les développeurs à se renseigner sur d'autres fonctions qu'ils n'ont pas l'habitude d'utiliser, de chercher les optimisations pour limiter les boucles, etc.
Donc quoi de mieux pour cela que de prendre une fonction très simple qui permet un nombre d'alternatives très important ! Bien trop souvent on a nos habitudes de langage et on reste dans notre zone de confort, j'aimerais juste en sortir de cette zone pour apprendre différentes logiques, fonctions, réflexions, ...

Après je me pose tout de même la question si en terme de retour on ne peut pas élargir un peu les possibilités comme des SafeArray (certains programmes, selon qu'ils soient en AutoLISP vanilla, en Visual LISP ou même VBA ne gèrent pas les listes de la même manières) donc il se peut que pour un programme en Visual, la conversion d'un SafeArray en liste pour ensuite convertir cette liste en SafeArray pour continuer un autre programme ne fasse pas grand sens... >w<

Donc en résumé on va dire :

(defun func_name (ObjName / ...)
	...
)

command: (setq name (car (entsel))) ; ou (vlax-ename->vla-object (car (entsel)))
command: (func_name name)
((12.4 584.5) (123.8 1.7) (12.8 967.4))
; ou #<safearray...> équivalent à (vlax-safearray->list #<safearray...>) = ((12.4 584.5) (123.8 1.7) (12.8 967.4))

Bisous,
Luna

Lien vers le commentaire
Partager sur d’autres sites

Yop

C'est vrai que c'est un peux redondant comme sujet.

J'ai recherché parmi mes fonctions celle qui me semble la plus virulente

(defun vgetpoint ( obj)
  (pair (vlax-get obj 'coordinates ))
)
(defun pair (l)
  (if l
    (cons (list (car l) (cadr l)) (pair (cddr l)))
  )
)

donc un vlaobjet en argument

Lien vers le commentaire
Partager sur d’autres sites

28 minutes ago, Curlygoth said:

via vba :

Poly.coordinates

où poly est une polyligne..

retourne la liste des points a chque sommet du debut a la fin de la polyligne

Si tu veux jouer, il faut respecter les consignes Poly.Coordinates renvoie un Variant (array of doubles) de type [x0, y0, x1, y1, x2, y2, ...] et il s'agit ici de renvoyer une liste points. En LISP un "point" est une liste de 2 ou 3 nombres réels (double), l'équivalent VBA est un Variant (array of doubles) de 2 ou 3 doubles. Il faudrait donc que la fonction renvoie un Variant (array of Variants (array of doubles)).
C'est exactement ce que fait la routine LISP donnée par Fraid.

PS : J'ai fait quelques essais en .NET et on ne joue définitivement pas dans la même cour en terme de rapidité, c'est environ 20 fois plus rapide que le LISP.

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

Lien vers le commentaire
Partager sur d’autres sites

MMmmm... ok...

retcoord = returnobj.Coordinates
Dim POINT(0 To 1) As Double
Dim LISTPOINT() As Variant

NOMBREPOINT = (UBound(retcoord) + 1) / 2
ReDim Preserve LISTPOINT(NOMBREPOINT)

k = LBound(retcoord)
L = UBound(retcoord)

For B = k To L Step 2
    POINT(0) = retcoord(B)
    POINT(1) = retcoord(B + 1)
    LISTPOINT(cpt) = POINT
    cpt = cpt + 1
Next B
Quote

PS : J'ai fait quelques essais en .NET et on ne joue définitivement pas dans la même cour en terme de rapidité, c'est environ 20 fois plus rapide que le LISP.

et surement 100 fois plus rapide que le VBA XD

Lien vers le commentaire
Partager sur d’autres sites

1 hour ago, Fraid said:

Je veux bien voir un exemple en C#, si tu veux bien ...😂

La fonction qui répond au challenge :

        private static Point2d[] GetPlinePoints(ObjectId id)
        {
            using (var tr = new OpenCloseTransaction())
            {
                var pline = (Polyline)tr.GetObject(id, OpenMode.ForRead);
                var result = new Point2d[pline.NumberOfVertices];
                for (int i = 0; i < result.Length; i++)
                {
                    result[i] = pline.GetPoint2dAt(i);
                }
                return result;
            }
        }

 

Une commande de test pour sélectionner la polyligne et choisir le nombre d'itération pour le 'benchmark'.

        [CommandMethod("TEST")]
        public static void Test()
        {
            var doc = AcAp.DocumentManager.MdiActiveDocument;
            var db = doc.Database;
            var ed = doc.Editor;

            var entOpts = new PromptEntityOptions("\nSélectionnez une polyligne: ");
            entOpts.SetRejectMessage("\nL'objet séléctionné n'est pas une polyligne.");
            entOpts.AddAllowedClass(typeof(Polyline), true);
            var entRes = ed.GetEntity(entOpts);
            if (entRes.Status != PromptStatus.OK)
                return;
            var id = entRes.ObjectId;

            var kwOpts = new PromptKeywordOptions("\nChoisissez le nombre d'itérations [64/512/4096/32768]: ", "64 512 4096 32768");
            var kwRes = ed.GetKeywords(kwOpts);
            if (kwRes.Status != PromptStatus.OK)
                return;
            int nb = int.Parse(kwRes.StringResult);

            var sw = new System.Diagnostics.Stopwatch();
            sw.Start();
            for (int i = 0; i < nb; i++)
            {
                GetPlinePoints(id);
            }
            sw.Stop();
            ed.WriteMessage($"\nElapsed milliseconds {sw.ElapsedMilliseconds} for {nb} iterations");
        }

Attaché, un ZIP à débloquer contenant la DLL à charger dans AutoCAD avec NETLOAD.

GetPointListChallenge.zip

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

Lien vers le commentaire
Partager sur d’autres sites

En pur lisp (vanilla), c'est certainement le moins efficient (surtout avec de nombreux sommets)

Ça retourne les coordonnées dans le SCG quel que soit le SCU de conception et l'élévation.

((lambda ( / ent dxf_ent)
	(cond
		((setq ent (entsel))
			(setq ent (car ent) dxf_ent (entget ent))
			(mapcar '(lambda (z) (trans (list (car z) (cadr z) (cdr (assoc 38 dxf_ent))) (cdr (assoc 210 dxf_ent)) 0)) (mapcar 'cdr (vl-remove-if '(lambda (x) (/= (car x) 10)) dxf_ent)))
		)
	)
))

 

Choisissez un travail que vous aimez et vous n'aurez pas à travailler un seul jour de votre vie. - Confucius

Lien vers le commentaire
Partager sur d’autres sites

3 hours ago, (gile) said:

PS : ce type de fonction a été fait tellement de fois, j'ai retrouvé sur CADxp des messages dans lesquels je montre 6 façons différentes en "pur AutoLISP".

Bonjour,

Oui je connais ces messages, pour cette raison j'ai mauvaise conscience à proposer la moindre ligne de code sur ce challenge.

Apprendre => Prendre => Rendre

Lien vers le commentaire
Partager sur d’autres sites

Bonsoir

Rapidement pour le jeu et ne pas taper dans les 6 façons différentes en "pur AutoLISP", pas forcément la façon la plus efficiente sur de grande lwp car la fonction ne mémorise pas la liste de définition de l'entité, mais y accède pour chaque sommet extrait.

(defun Get-pt-list (e / f)
  (defun f (i / pt)
    (if	(setq pt (vlax-curve-getPointAtParam e i))
      (cons pt (f (1+ i)))
    )
  )
  (f 0)
)

@Luna Bien que la fonction travail indifféremment avec un argument au format vla-objet ou ename, au jeu des comparaisons elle gagnera à être regardé avec un argument au format ename, la valeur de retour comme la proposition de BonusCAD retournera la coordonnée en Z dans la liste des points, et si la Lwpolyline est close le premier sommet est répété en fin de liste

Apprendre => Prendre => Rendre

Lien vers le commentaire
Partager sur d’autres sites

Bonjour,

 

J'ai repris le code de @(gile) et j'ai fait quelques tests pour comparer (je suis sous Map 3D 2018 et VS 2019) :

- compilation AnyCPU ou x64 => 1% de gain en x64

- accès à l'objet en mode déprécié Open et Close par rapport à OpenCloseTransaction => 1% de gain pour OpenCloseTransaction

- compilation .Net 4.6 (ObjectArx 2018) ou .Net 4.5 (ObjectArx 2015) => pas de différence

Par contre je ne sais pas quelles options de compil sont différentes chez moi, mais avec la DLL de gilles j'obtiens :

15200 millisecondes pour 32768 itérations sur la poly à 10000 sommets alors qu'avec ma DLL, je passe à 10230 millisecondes.

De plus, il y a un certain manque de répétitivité dans les performances, entre différentes sessions d'AutoCAD, peut-être dues à l'activité du PC (hors AutoCAD).

Je suis en général entre 10200 et 10600 milli, et entre 15100 et 15600 (avec la DLL de gilles), mais 1 fois, je suis passé à 9980 et avec a DLL de Gilles, durant cette session, j'étais à 11500.

 

Olivier

Lien vers le commentaire
Partager sur d’autres sites

La DLL que j'ai postée a été compilée avec VS2019 en mode Release (Any CPU) en ciblant le Framework 4.6. Je ne vois pas d'où viennent ces différences. Dans tous les cas, ces chronométrages sont à prendre à titre indicatif avec des pincettes (ils sont influencé par ce qui se passe en même temps sur la machine) et la différence n'est que d'environ 0.15 millisecondes pour le traitement d'une polyligne de 10000 sommets.

La routine écrite en F# (mêmes performances qu le C# puis que les deux sont compilées dans le même IL).

let getPlinePoints (id: ObjectId) =
    use  pl = id.Open(OpenMode.ForRead) :?> Polyline
    Array.init pl.NumberOfVertices (fun i -> pl.GetPoint2dAt(i))

 

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

Lien vers le commentaire
Partager sur d’autres sites

Bonjour,

pour la gestion des sommets de polylignes, j'ai l'habitude de récupérer les données de la polyligne sous forme d'une liste de segments :

((sommet1 Bulge1 sommet2) (sommet2 bulge2 sommet3) ...)

Vous allez me dire que je me répète, mais je trouve que ça a plein d'avantages de pouvoir récupérer le énième segment facilement avec ses extrémités et surtout son bulge.

(defun getpolySegs (ent / PTL I PTB SEG LSEG)
  (if (= (type ent) 'ENAME)
    (setq ent (vlax-ename->vla-object ent))
  )
  ;; collecter la liste des point sous la forme (x1 y1 x2 y2 ... xn yn)
  (setq PTL (vlax-safearray->list (vlax-variant-value (vla-get-Coordinates ENT))))
  ;; collecter la liste des bulges
  (setq I 0) 
  (repeat (/ (length PTL) 2)
    (setq PTB (cons (vla-GetBulge ent I) PTB))
    (setq I (1+ I))
  )
  (setq PTB (reverse PTB))
  ;; polyligne fermée -> rajouter le premier point à la liste de points
  (if (= (vla-get-closed ent) :vlax-true)
    (setq PTL (append PTL (list (car PTL) (cadr PTL))))
  )
  ;; transformer en liste de segments
  (setq I 0)
  (repeat (- (/ (length PTL) 2) 1)
    (setq SEG
      (list
        (list (nth I PTL) (nth (+ I 1) PTL))
        (nth (/ I 2) PTB)
        (list (nth (+ I 2) PTL) (nth (+ I 3) PTL))
      )
    )
    (setq LSEG (cons SEG LSEG))
    (setq I (+ I 2))
  )
  (reverse LSEG)
)

ensuite j'ai une fonction qui détermine le centre et le rayon correspondant au bulge

(defun getArcInfo (segment / a p1 bulge p2 c p3 p4 p r s result)
  ;; assigner variables avec les valeurs de l'argument
  (mapcar 'set '(p1 bulge p2) segment)
  (if (not (zerop bulge))
    (progn
      ;; trouver la corde
      (setq c (distance p1 p2))
      ;; trouver la flèche
      (setq s (* (/ c 2.0) (abs bulge)))
      ;; trouver le rayon par Pythagore
      (setq r (/ (+ (expt s 2.0) (expt (/ c 2.0) 2.0)) (* 2.0 s)))
      ;; distance au centre
      (setq a (- r s))
      ;; coordonnées du milieu de p1 et P2
      (setq P4 (polar P1 (angle P1 P2) (/ c 2.0)))
      ;; coordonnées du centre
      (setq p
        (if (>= bulge 0)
          (polar p4 (+ (angle p1 p2) (/ pi 2.0)) a)
          (polar p4 (- (angle p1 p2) (/ pi 2.0)) a)
        )  
      )
      ;; coordonnées de P3
      (setq p3
        (if (>= bulge 0)
          (polar p4 (- (angle p1 p2) (/ pi 2.0)) s)
          (polar p4 (+ (angle p1 p2) (/ pi 2.0)) s)
        )  
      )
      (setq result (list p r))
    )
    (setq result nil)
  )
  result
)

c'est un peu hors sujet, mais je trouve que récupérer les sommets sans récupérer les bulges semble incomplet.

Amitiés

Vincent

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)

Lien vers le commentaire
Partager sur d’autres sites

Coucou,

Tout dépend de l'utilisation qu'on veut en faire. D'autant plus que si l'on travaille sur des polylignes courbées, je pense qu'il est plus simple de passer par les fonctions (vlax-curve-*) qui sont moins lourdes et ne nécessite pas d'utilisation de listes complexes :3

Mais il est vrai que j'ai trouvé le sujet des bulges de polylignes très intéressant et instructifs surtout !

Bisous,
Luna

Lien vers le commentaire
Partager sur d’autres sites

oui, bien sûr, tout dépend ce qu'on veut faire et les fonctions (vlax-curve-*) sont une mine d'or, on est 100% d'accord, mais ne permettent pas tout.

par exemple, je représente mes aciers de ferraillage sous la forme de polyligne. Si je veux savoir quel est le mandrin de cintrage qui a été utilisé pour dessiner l'acier, il faut que j'aille récupérer le bulge du segment et voir à quel rayon, puis diamètre, ça correspond. Je ne vois pas comment obtenir mon bonheur avec vlax-curve.

si je veux savoir si un segment est courbe ou non, c'est le bulge qui me le dit.

Si je veux connaitre l'angle de pliage entre deux segments droits successifs, c'est le bulge du segment courbe qui fait la liaison entre ces deux segments droits qui me donne la réponse facilement.

Si je veux savoir si le pliage se fait dans le sens horaire ou non, c'est encore le bulge qui me donne la réponse facilement.

Par ailleurs, si on veut "trafiquer" un peu une polylgne existante, par exemple, je veux rajouter un ancrage au bout d'une barre droite - donc rajouter un segment courbe et un segment doit, il faut bien connaitre la définition des bulges pour pouvoir modifier correctement cette polyligne.

Amitiés

Vincent

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)

Lien vers le commentaire
Partager sur d’autres sites

Pour essayer de revenir au challenge (et avant de digresser moi aussi) je dévoile différentes implémentations de la routine générique massoc (pour multiple assoc) qui permet de récupérer toutes les entrées d'un même groupe de code dans une liste DXF.
Ma réponse en "pur AutoLISP" utiliserait l'implémentation que je préfère :

(defun massoc (key alst)
  (if (setq alst (member (assoc key alst) alst))
    (cons (cdar alst) (massoc key (cdr alst)))
  )
)

(defun polyPoints (pl)
  (massoc 10 (entget pl))
)

Pour récupérer les sommets de la polyligne en coordonnées SCG (fonctionne aussi avec le polylignes 2d et 3d) :

(defun vlax-curve-getPolylineCoordinates (pl / i pts)
  (repeat (setq	i (if (vlax-curve-isClosed pl)
		    (fix (vlax-curve-getEndParam pl))
		    (1+ (fix (vlax-curve-getEndParam pl)))
		  )
	  )
    (setq pts (cons (vlax-curve-getPointAtParam pl (setq i (1- i))) pts))
  )
)

 

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

Lien vers le commentaire
Partager sur d’autres sites

La routine de @zebulon_ avec massoc (peut-être pas très efficient) :

(defun getPolySegs (pl / elst pts)
  (setq	elst (entget pl)
	pts  (massoc 10 elst)
  )
  (mapcar 'list
	  pts
	  (massoc 42 elst)
	  (if (= 1 (logand 1 (cdr (assoc 70 elst))))
	    (append (cdr pts) (list (car pts)))
	    (cdr pts)
	  )
  )
)

 

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

Lien vers le commentaire
Partager sur d’autres sites

j'utilise cette version de massoc.

(defun massoc (key alist / x nlist)
  (foreach x alist
    (if (eq key (car x))
      (setq nlist (cons (cdr x) nlist))
    )
  )
  (reverse nlist)
)

Amitiés

Vincent

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)

Lien vers le commentaire
Partager sur d’autres sites

Tellement de méthodes pour un même résultat ! c'est très instructif !

Je gères les courbes différemment mais je pense que je vais m'inspirer de la méthode de Zebulon !

d'ailleurs pour ceux qui comme moi ne connaissais ce "mot" (bulge)

on le retrouve sur le site de Didier ici : https://www.da-code.fr/bulge-theorie/

Donc merci @zebulon_ & Merci @didier

Lien vers le commentaire
Partager sur d’autres sites

Coucou,

32 minutes ago, Curlygoth said:

Tellement de méthodes pour un même résultat ! c'est très instructif !

C'était le but premier du challenge au final ^^"

J'ai fait quelques tests dont voici les résultats :

;; BENCHMARK D'UNE LWPOLYLINE DE 10 SOMMETS
Elapsed milliseconds / relative speed for 8192 iteration(s):
    (GET-PT-LIST-BRUNO NAME).....................1466 / 3.55 <fastest>
    (GET-PT-LIST-CURVE NAME).....................1560 / 3.34
    (VLAX-CURVE-GETPOLYLINECOORDINATES N...).....1701 / 3.06
    (VGETPOINT VNAME)............................1701 / 3.06
    (GET-PT-LIST-RECURSIVE-MEMBER NAME)..........1747 / 2.98
    (POLYPOINTS NAME)............................1763 / 2.96
    (GET-PT-LIST-MEMBER NAME)....................1778 / 2.93
    (GET-PT-LIST-NTH-RECURSIVE NAME).............1825 / 2.85
    (GET-PT-LIST-RECURSIVE-COORDINATES V...).....1825 / 2.85
    (GET-PT-LIST-REPEAT NAME)....................1919 / 2.71
    (GET-PT-LIST-MAPCAR NAME)....................3183 / 1.64
    (GET-PT-LIST-REMOVE NAME)....................3557 / 1.46
    (GET-PT-LIST-SEARCH NAME)....................3572 / 1.46
    (GET-PT-LIST-FOREACH NAME)...................3635 / 1.43
    (GET-PT-LIST-BONUSCAD NAME)..................5101 / 1.02
    (GET-PT-LIST-BRUNO VNAME)....................5210 / 1.00 <slowest>

;; BENCHMARK D'UNE LWPOLYLINE DE 100 SOMMETS
Elapsed milliseconds / relative speed for 2048 iteration(s):
    (VGETPOINT VNAME)............................1107 / 5.19 <fastest>
    (GET-PT-LIST-BRUNO NAME).....................1217 / 4.72
    (GET-PT-LIST-RECURSIVE-COORDINATES V...).....1232 / 4.66
    (GET-PT-LIST-CURVE NAME).....................1389 / 4.13
    (VLAX-CURVE-GETPOLYLINECOORDINATES N...).....1482 / 3.87
    (GET-PT-LIST-MEMBER NAME)....................1498 / 3.83
    (GET-PT-LIST-RECURSIVE-MEMBER NAME)..........1498 / 3.83
    (POLYPOINTS NAME)............................1607 / 3.57
    (GET-PT-LIST-NTH-RECURSIVE NAME).............1809 / 3.17
    (GET-PT-LIST-REPEAT NAME)....................1825 / 3.15
    (GET-PT-LIST-REMOVE NAME)....................2028 / 2.83
    (GET-PT-LIST-MAPCAR NAME)....................2808 / 2.04
    (GET-PT-LIST-FOREACH NAME)...................3790 / 1.51
    (GET-PT-LIST-BRUNO VNAME)....................3868 / 1.48
    (GET-PT-LIST-SEARCH NAME)....................4009 / 1.43
    (GET-PT-LIST-BONUSCAD NAME)..................5741 / 1.00 <slowest>

;; BENCHMARK D'UNE LWPOLYLINE DE 1 000 SOMMETS
Elapsed milliseconds / relative speed for 128 iteration(s):
    (GET-PT-LIST-RECURSIVE-COORDINATES V...)......1045 / 14.48 <fastest>
    (VGETPOINT VNAME).............................1061 / 14.26
    (GET-PT-LIST-BRUNO NAME)......................1077 / 14.05
    (VLAX-CURVE-GETPOLYLINECOORDINATES N...)......1248 / 12.13
    (GET-PT-LIST-CURVE NAME)......................1295 / 11.68
    (GET-PT-LIST-RECURSIVE-MEMBER NAME)...........1388 / 10.90
    (GET-PT-LIST-MEMBER NAME).....................1435 / 10.54
    (POLYPOINTS NAME).............................1513 / 10.00
    (GET-PT-LIST-REMOVE NAME).....................1560 / 9.70
    (GET-PT-LIST-REPEAT NAME).....................1654 / 9.15
    (GET-PT-LIST-MAPCAR NAME).....................2684 / 5.64
    (GET-PT-LIST-BRUNO VNAME).....................2730 / 5.54
    (GET-PT-LIST-NTH-RECURSIVE NAME)..............3074 / 4.92
    (GET-PT-LIST-FOREACH NAME)....................4290 / 3.53
    (GET-PT-LIST-SEARCH NAME).....................4446 / 3.40
    (GET-PT-LIST-BONUSCAD NAME)..................15132 / 1.00 <slowest>

;; BENCHMARK D'UNE LWPOLYLINE DE 10 000 SOMMETS
Elapsed milliseconds / relative speed for 32 iteration(s):
    (VGETPOINT VNAME)..............................1372 / 230.03 <fastest>
    (GET-PT-LIST-RECURSIVE-COORDINATES V...).......1420 / 222.26
    (GET-PT-LIST-BRUNO NAME).......................1591 / 198.37
    (VLAX-CURVE-GETPOLYLINECOORDINATES N...).......1887 / 167.25
    (GET-PT-LIST-CURVE NAME).......................1903 / 165.85
    (POLYPOINTS NAME)..............................2138 / 147.62
    (GET-PT-LIST-MEMBER NAME)......................2152 / 146.66
    (GET-PT-LIST-RECURSIVE-MEMBER NAME)............2200 / 143.46
    (GET-PT-LIST-REMOVE NAME)......................2464 / 128.09
    (GET-PT-LIST-REPEAT NAME)......................2605 / 121.15
    (GET-PT-LIST-MAPCAR NAME)......................3884 / 81.26
    (GET-PT-LIST-FOREACH NAME).....................5429 / 58.13
    (GET-PT-LIST-BRUNO VNAME)......................5679 / 55.57
    (GET-PT-LIST-SEARCH NAME)......................5819 / 54.24
    (GET-PT-LIST-NTH-RECURSIVE NAME)..............42682 / 7.39
    (GET-PT-LIST-BONUSCAD NAME)..................315606 / 1.00 <slowest>

Le plus étonnant c'est la différence d'efficacité entre l'utilisation de l'ename ou du VLA-Object sur les fonctions (vlax-curve-*) ! °o° 
Les durées pour la fonction proposée par BonusCAD me semble quelque peu exagéré mais bon...
A savoir que les fonctions (vgetpoint) et (get-pt-list-recursive-coordinates) sont strictement les mêmes, pour le coup @Fraid on a pensé à la même chose ^^"
La fonction (get-pt-list-recursive-member) correspond à la fonction (massoc) utilisant la fonction (member), à savoir que j'utilise personnellement la fonction (get-pt-list-member) qui correspond à la version itérative de (massoc) :3

Evidemment, les fonctions qui vérifie chaque paire DXF au lieu de "sauter" les paires inutiles semblent plus lentes (plus de passage dans la boucle ?). Les fonctions (vlax-curve-*) semblent plus rapides que la gestion de la liste DXF de l'entité et la propriété 'Coordinates semble également un peu plus rapide que les fonctions (vlax-curve-*), bien que se soit dommage que les coordonnées ne soient pas ranger 2 à 2 directement (cela éviterait la boucle et donc il existerait une fonction existante capable de renvoyer les coordonnées d'une polyligne directement).

Voici les différentes versions que j'avais essayé au fil du temps (la fonction (get-pt-list-curve) est très récente, merci @Olivier Eckmann pour m'avoir appris la signification des paramètres pour les (vlax-curve-*) ! ♥) :

(defun get-pt-list-curve (name / pt-list n)

	(repeat (fix (setq n (1+ (vlax-curve-getEndParam name))))
		(setq pt-list
			(cons
				(vlax-curve-getPointAtParam name (setq n (1- n)))
				pt-list
			)
		)
	)
	pt-list

)

(defun get-pt-list-member (name / pt-list entlist)

	(setq entlist (entget name))
	(while	(setq entlist (member (assoc 10 entlist) entlist))
		(setq pt-list (cons (cdar entlist) pt-list)
		      entlist (cdr entlist)
		)
	)
	(reverse pt-list)

)

(defun get-pt-list-recursive-member (name / f entlist)

	(defun f (entlist)

		(if (setq entlist (member (assoc 10 entlist) entlist))
			(cons (cdar entlist) (f (cdr entlist)))
		)

	)
	(f (entget name))

)

(defun get-pt-list-search (name / pt-list entlist)

	(setq entlist (entget name))
	(while entlist
		(if (= (caar entlist) 10)
			(setq pt-list (cons (cdar entlist) pt-list))
		)
		(setq entlist (cdr entlist))
	)
	(reverse pt-list)

)

(defun get-pt-list-repeat (name / pt-list entlist)

	(repeat (cdr (assoc 90 (setq entlist (entget name))))
		(setq entlist (member (assoc 10 entlist) entlist)
		      pt-list (cons (cdar entlist) pt-list)
		      entlist (cdr entlist)
		)
	)
	(reverse pt-list)

)

(defun get-pt-list-remove (name / pt-list)

	(mapcar	'cdr
		(vl-remove-if-not
			'(lambda (x) (= (car x) 10))
			(entget name)
		)
	)

)

(defun get-pt-list-mapcar (name / pt-list)

	(vl-remove
		nil
		(mapcar
			'(lambda (x)
				(if (= (car x) 10) (cdr x))
			 )
			(entget name)
		)
	)

)

(defun get-pt-list-nth-recursive (name / f)

	(defun f (lst i / x)

		(if (= (car (setq x (nth i lst))) 10)
			(cons (cdr x) (f lst (+ i 5)))
		)

	)
	(setq entlist (entget name))
	(f entlist (vl-position (assoc 10 entlist) entlist))

)

(defun get-pt-list-recursive-coordinates (vname / f)

	(defun f (lst)

		(if lst
			(cons (list (car lst) (cadr lst)) (f (cddr lst)))
		)

	)
	(f (vlax-get vname 'coordinates))

)

Bisous,
Luna

Lien vers le commentaire
Partager sur d’autres sites

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é