Aller au contenu

[Challenge] Spirale de Fibonacci


Messages recommandés

Posté(e)

Salut,

Je propose un challenge pour l'été (profiter des vacances pour apprendre ou se perfectionner en LISP).

Tout le monde a entendu parler de la suite de Fibonacci. Une spirale de Fibonacci est une succession d'arcs de cercle de 90° connectés tangentiellement dont les rayons sont les termes de la suite de Fibonacci.

Un exemple de spirale de Finonacci composée de 7 arcs :

image.png.04b9178ecfcc7a1e814ee2ab980cf108.png

Challenge

Il s'agit d'écrire une routine qui prend en argument le point de départ de la spirale et le nombre d'arcs pour dessiner la spirale dans AutoCAD (plusieurs arcs ou une polyligne).

La routine (ici nommée spiralFib) devra pouvoir être appelée depuis une commande LISP (ici nommée c:TEST) pour pouvoir être testée dans AutoCAD pour dessiner des spirales ayant au minimum 4 arcs.

(defun c:test (/ p i)
  (and
    (setq p (getpoint "\nPoint de départ: "))
    (setq i (getint "\nNombre d'arcs [4-32]: "))
    (< 3 i)
    (spiralFib p i)
  )
  (princ)
)

Un screencast montrant un exemple.

 

Variante

On peut, sur le même principe faire une routine pour une "Spirale d'or".

  • Like 1

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

Posté(e)

Génial, je n'ai pas d'AutoCAD Full sous la main actuellement, donc je devrais pas être en mesure de proposer quelque chose de suite (pas avant une bonne semaine), mais dès que c'est possible je tenterai un truc, ne serait ce que pour valider les 2 à 3 petites idées qui me viennent en tête à la lecture de l'énoncé :)

 

  • Like 1

Apprendre => Prendre => Rendre

Posté(e)

Se serait avec plaisir de participer (de même que le challenge des cercles magiques) mais je manque cruellement de temps en ce moment. Donc je vais devoir passer malheureusement..

Bisous,
Luna

  • Like 1
Posté(e)

Bonjour

Merci @(gile) de nous faire des devoirs de vacances.
Tu crois qu'on n'a pas assez de ceux des petits-enfants qu'il faut corriger, passer au correcteur, rajouter des S pour les pluriels et autres joyeusetés qu'on subit quand on a 9 ans ?
Blague à part, j'aime ce qui est beau et il se trouve que cette suite est belle et que la spirale résultante l'est tout autant.
Donc, je me m'inscris sur la liste des participants, maintenant, il va falloir ménager du temps entre les siestes et les cahiers de vacances...

Amicalement

Posté(e)
Le 01/08/2022 à 10:47, (gile) a dit :

Ceux qui auraient déjà fini leur devoirs (et qui s'ennuient) peuvent se pencher sur la variante "Spirale d'or".

Bonjour (gile)

Juste une petite précision dans la modélisation pour le premier rayon de la Spirale d'or (qui est infini), tu pars sur une valeur de 1 (comme pour la spirale de Bonifacci)?

La petite précision est utile, pour pouvoir superposer aisément les Spirales au moment de la correction 😉.

 

Autre précision lorsque je lis ceci dans le lien sur Wikipédia :

Citation

En géométrie, une spirale d'or est une spirale logarithmique avec un facteur de croissance de {\displaystyle \varphi ={\frac {1+{\sqrt {5}}}{2}}\simeq 1,618}{\displaystyle \varphi ={\frac {1+{\sqrt {5}}}{2}}\simeq 1,618}, appelé nombre d'or.1 Une spirale d'or devient plus large par un facteur de φ pour chaque quart de tour qu'elle fait.

L'assertion suivant me dérange "une spirale d'or est une spirale logarithmique", car une spirale logarithmique est une spirale de croissance continue, ce que n'est pas la spirale d'or qui a un facteur de croissance à chaque quart de tour. Ouf heureusement que c'est précisé à la fin de la phrase, pour invalider l'assertion de départ...

A+ Bruno

Apprendre => Prendre => Rendre

Posté(e)

Bonsoir,

Bientôt en vacances donc j'ouvre le bal:

Spirale Bonifacci (version polyligne)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;  Spirale Fibonacci ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun spiralFib (p i / make_courbe tan)
  (defun tan (ang) (/ (sin ang) (cos ang)))
  (defun make_courbe (dxf42 p ang corde1 corde2 i)
    (if	(>= i 0)
      (cons (cons 10 p)
	    (cons dxf42
		  (make_courbe dxf42 (polar p ang corde1) (+ ang (* 0.5 pi)) corde2 (+ corde1 corde2) (1- i))
	    )
      )
    )
  )
  (entmakex
    (append (list (cons 0 "LWPOLYLINE")
		  (cons 100 "AcDbEntity")
		  (cons 100 "AcDbPolyline")
		  (cons 90 i)
	    )
	    (make_courbe (cons 42 (tan (* 0.125 pi))) p (* 0.25 pi) (sqrt 2) (sqrt 2) i)
    )
  )
)

 

La variante Spirale d'Or (version polyligne)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Spirale d'Or ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun spiralOr	(p i / make_courbe tan)
  (defun tan (ang) (/ (sin ang) (cos ang)))
  (defun make_courbe (dxf42 p ang corde phi i)
    (if	(>= i 0)
      (cons (cons 10 p)
	    (cons dxf42 (make_courbe dxf42 (polar p ang corde) (+ ang (* 0.5 pi)) (* corde phi) phi (1- i)))
      )
    )
  )
  (entmakex
    (append (list (cons 0 "LWPOLYLINE")
		  (cons 100 "AcDbEntity")
		  (cons 100 "AcDbPolyline")
		  (cons 90 i)
	    )
	    (make_courbe (cons 42 (tan (* 0.125 pi))) p (* 0.75 pi) (sqrt 2) (/ (1+ (sqrt 5)) 2.) i)
    )
  )
)

Salutations

Bruno

Apprendre => Prendre => Rendre

Posté(e)

Re,

Et pour proposer autre chose, très rapidement une variante de la Spirale Bonifacci (version arc de cercle)

(defun SpiralFib (p i / sFib cen ang)
  (defun make_arc (cen ray angdep angfin)
    (entmakex (list '(0 . "ARC")
		    (cons 10 cen)
		    (cons 40 ray)
		    (cons 50 angdep)
		    (cons 51 angfin)
	      )
    )
  )
  (setq	sFib '(1 1)
	ang  (/ pi 2)
	cen  (polar p (/ pi 2) 1.)
  )
  (make_arc cen 1. (- ang) 0.)
  (make_arc cen 1. 0. ang)
  (repeat (- i 2)
    (setq cen  (polar cen (+ ang pi) (cadr sFib))
	  sFib (cons (+ (car sFib) (cadr sFib)) sFib)
    )
    (make_arc cen (car sFib) ang (setq ang (+ ang (/ pi 2))))
  )
)

 

Apprendre => Prendre => Rendre

Posté(e)

Super.

Des routine dans un style fonctionnel, on n'en attendait pas moins de toi.

Tu pars en vacances en Corse ? Ça expliquerait Bonifacci(o) en lieu de Fibonacci.

J'attends que d'autres postent des réponse pour voir si je peux proposer quelque chose de différent.

  • Upvote 1

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

Posté(e)
il y a 54 minutes, (gile) a dit :

Tu pars en vacances en Corse ? Ça expliquerait Bonifacci(o) en lieu de Fibonacci.

😂😂😂 Excellent!!! 

Non Bretagne, c'est moins loin pour moi et j'ai pas trop envie de traverser toute la France, mais si un jour j'y vais, je m'organiserais pour faire étape à Marseille😉

 

Apprendre => Prendre => Rendre

Posté(e)

Bonjour.

À mon tour de proposer mes routines, pas toujours dans l'académique, mais ça fait le job.
J'ai respecté la demande initiale de faire un testFIB et un testGOLD

Fibonacci :

(defun spiralfib ( cen nb / b dir li li2 n p pol rac2)
    (setvar "cmdecho" 0)
    (defun suitefib (nb)
        (setq li '(1 0))
        (repeat nb
            (setq li (cons (+ (car li) (cadr li)) li))
            )
        (reverse li)
        )
    ;(setq li2 '())
    (setq li (cdr (suitefib nb)))   
    (setq dir (/ pi 4)
          rac2 (sqrt 2.0)
          )
    (setq li2 (cons (list (+ (car cen) 1)(cadr cen)) li2))
        (foreach ele li
        (setq li2 (cons (polar (car li2) (setq dir (+ dir (/ pi 2))) (* rac2 ele)) li2))
        )
    (setq b (/ (sin (/ pi 8))(cos (/ pi 8))))
    (entmakex (append (list '(0 . "LWPOLYLINE") '(100 . "AcDbEntity") '(100 . "AcDbPolyline") (cons 38 0)
                        (cons 90 (length  li2))
                        (cons 70 0)
                        (cons 62 1)
                        )
                  (mapcar '(lambda (p) (cons 10 p)) li2)
                  );_ Fin de append
           ) ;_ Fin de entmake
    
(entmakex (append (list '(0 . "LWPOLYLINE") '(100 . "AcDbEntity") '(100 . "AcDbPolyline") (cons 38 0)
                        (cons 90 (length  li2))  (cons 70 0)(cons 62 6)
                        )
                  (mapcar '(lambda (p) (cons 10 p)) li2)
                  );_ Fin de append
           )

    (setq n -1)
    (setq pol (vlax-ename->vla-object (entlast)))
    (repeat (cdr (assoc 90 (entget (entlast))))
        (vla-SetBulge pol (setq n (1+ n)) -0.414214)
        )
    (vla-Update pol)

    (setq n 0)
    (setq li22 (reverse li2))
    (setq oldosmode (getvar 'osmode))
    (setvar "osmode" 0)
    (repeat (length li2)
        (command "_rectang" (nth n li2) (nth (1+ n) li2))
        (setq n (+ 1 n))
        )
    (setvar "osmode" oldosmode)
    (setq li2 (reverse li2))
    )

(defun c:testfib (/ p i)
  (and
    (setq p (getpoint "\nPoint de départ: "))
    (setq i (getint "\nNombre d'arcs [4-32]: "))
    (and (< 3 i)(< i 33))    
    (spiralFib p i)
  )
  (princ)
)

 

Et maintenant Spirale d'Or (ne faites pas de bruit, la spirale dort)

(defun spiralgold ( cen nb / gold b dir li li2 n p pol rac2)
    (setvar "cmdecho" 0)
    (setq li '(1))
    (setq gold (/ ( + 1 (sqrt 5)) 2))
    (repeat nb
        (setq li (cons (* (car li) gold) li))
        )
    (setq li (reverse li))
    (setq dir (/ pi 4)
          rac2 (sqrt 2.0)
          )
    (setq li2 (cons (list (+ (car cen) 1)(cadr cen)) li2))
     (foreach ele li
        (setq li2 (cons (polar (car li2) (setq dir (+ dir (/ pi 2))) (* rac2 ele)) li2))
        )
    (setq b (* (/ (sin (/ pi 8))(cos (/ pi 8)))-1))
    (entmakex (append (list '(0 . "LWPOLYLINE") '(100 . "AcDbEntity") '(100 . "AcDbPolyline") (cons 38 0)
                        (cons 90 (length  li2))
                        (cons 70 0)
                        (cons 62 1)
                        )
                  (mapcar '(lambda (p) (cons 10 p)) li2)
                  );_ Fin de append
           ) ;_ Fin de entmake
    (entmakex (append (list '(0 . "LWPOLYLINE") '(100 . "AcDbEntity") '(100 . "AcDbPolyline") (cons 38 0)
                        (cons 90 (length  li2))  (cons 70 0)(cons 62 2)
                        )
                  (mapcar '(lambda (p) (cons 10 p)) li2)
                  );_ Fin de append
           )

    (setq n -1)
    (setq pol (vlax-ename->vla-object (entlast)))
    (repeat (cdr (assoc 90 (entget (entlast))))
        (vla-SetBulge pol (setq n (1+ n)) b)
        )
    (vla-Update pol)

    (setq n 0)
    (setq li22 (reverse li2))
    (setq oldosmode (getvar 'osmode))
    (setvar "osmode" 0)
    (repeat (length li2)
        (command "_rectang" (nth n li2) (nth (1+ n) li2))
        (setq n (+ 1 n))
        )
    (setvar "osmode" oldosmode)
    (setq li2 (reverse li2))
    )

Amicalement

 

Posté(e)

@didier

La routine spiralfib  génère un arc de plus que demandé, sinon, "elle fait le job", même plus.

La routine spiralgold plante, et même après correction du nom d'une variable, "elle ne fait pas le job".

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

Posté(e)

Bonjour @(gile)

oops ! je suis une triple buse !!!

Une modif de dernière minute qui fût fatale !!
Désolé du dérangement, j'ai corrigé le code dans le message de réponse.

Je n'ai corrigé que la GOLD, l'arc de trop dans la Fibonacci n'est pas encore corrigé.
Est-ce que ça fonctionne mieux maintenant ?

Amicalement

Posté(e)

Pour la spirale de Fibonacci, on avait le choix entre dessiner une polyligne ou des arcs. Jusque là, il semble que la polyligne ait eu un peu plus de succès.

Ensuite, on peut adopter un style fonctionnel avec une fonction auxiliaire récursive (comme à fait @VDH-Bruno) ou un style plus impératif avec la fonction repeat (comme a fait @didier)

Pour donner quelque chose d'un peu différent des précédentes réponses, je voudrais juste montrer comment on peut calculer les sommets de la polyligne sans utiliser la fonction polar. Dans les routines suivantes, les variables ou arguments n et m stockent deux termes consécutifs de la suite de Fibonacci, les variables ou arguments x et y stockent les signes (+1 ou -1) utilisés pour déplacer le sommet.

Style fonctionnel:

(defun fibSpiral (p i / loop b)
  (setq b (- (sqrt 2.) 1.))
  (defun loop (i p n m x y)
      (vl-list*	(cons 10 p)
		(cons 42 b)
		(if (< 0 i)
		  (loop	(1- i)
			(mapcar '+ p (list (* x m) (* y m)))
			m
			(+ n m)
			(- y)
			x
		  )
		)
      )
  )
  (entmakex
    (append
      (list
	(cons 0 "LWPOLYLINE")
	(cons 100 "AcDbEntity")
	(cons 100 "AcDbPolyline")
	(cons 90 (+ i 1))
      )
      (loop i p 0 1 -1 1)
    )
  )
)

Style impératif:

(defun fibSpiral (p i / b x y n m l)
  (setq	b (- (sqrt 2.) 1.)
	n 0
	m 1
	x -1
	y 1
  )
  (repeat (setq i (1+ i))
    (setq l (cons (cons 42 b) (cons (cons 10 p) l))
	  p (mapcar '+ p (list (* x m) (* y m)))
    )
    (mapcar 'set '(n m x y) (list m (+ n m) (- y) x))
  )
  (entmakex
    (append
      (list
	(cons 0 "LWPOLYLINE")
	(cons 100 "AcDbEntity")
	(cons 100 "AcDbPolyline")
	(cons 90 i)
      )
      (reverse l)
    )
  )
)

 

Toutes les précédentes réponses utilisent entmake(x) pour créer la polyligne, je ne peux pas résister à poster un exemple (plus concis) avec command:

(defun fibSpiral (p i / b x y n m)
  (setq	b (- (sqrt 2.) 1.)
	n 0
	m 1
	x -1
	y 1
  )
  (command "_.pline" "_non" p "_arc" "_direction" (mapcar '+ p '(0. 1.)))
  (repeat i
    (command "_non" (setq p (mapcar '+ p (list (* x m) (* y m)))))
    (mapcar 'set '(n m x y) (list m (+ n m) (- y) x))
  )
  (command "")
)

 

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

Posté(e)
il y a 6 minutes, didier a dit :

Je n'ai corrigé que la GOLD, l'arc de trop dans la Fibonacci n'est pas encore corrigé.
Est-ce que ça fonctionne mieux maintenant ?

Ça fonctionne (toujours avec un arc de trop)

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

Posté(e)

Bonjour @(gile)

Merci d'avoir testé, maintenant tout doit être OK, car j'ai corrigé l'arc superflu.
Merci aussi pour les explications concernant tes versions.

On sait que ça existe, tu en es la preuve, mais je n'ai pas le niveau pour "penser" comme ça.
Je cherche encore à m'améliorer, mais je pense avoir atteint un palier.

Amicalement

Posté(e)

Avec des arcs:

(defun spiralFib (p i / loop a)
  (defun loop (i c n m s e x y)
    (entmake (mapcar 'cons '(0 10 40 50 51) (list "ARC" c m s e)))
    (if	(< 1 i)
      (loop (1- i) (mapcar '+ c (list (* x n) (* y n))) m (+ n m) e (+ e a) (- y) x)
    )
  )
  (setq	a (* 0.5 pi))
  (loop i (mapcar '+ p '(-1. 0.)) 0. 1. 0. a 0. -1.)
)

 

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

Posté(e)

Pour la spirale d'or, on peut, comme l'ont fait Bruno et Didier, multiplier le terme précédent par le nombre d'or pour obtenir le suivant, mais ce qui caractérise le nombre d'or, c'est qu'on peut aussi obtenir le terme suivant avec la somme des deux termes précédents, comme avec la suite de Fibonacci. D'ailleurs le rapport entre deux termes successifs de la suite de Fibonacci tend vers le nombre d'or quand cette suite tend vers l'infini.

On peut donc reprendre une des routines ayant servi à la suite de Fibonacci en remplaçant les deux premiers termes (0 et 1) par 1 et le nombre d'or.

Style fonctionnel :

(defun goldenSpiral (p i / loop b)
  (setq b (- (sqrt 2.) 1.))
  (defun loop (i p n m x y)
      (vl-list*	(cons 10 p)
		(cons 42 b)
		(if (< 0 i)
		  (loop	(1- i)
			(mapcar '+ p (list (* x n) (* y n)))
			m
			(+ n m)
			(- y)
			x
		  )
		)
      )
  )
  (entmakex
    (append
      (list
	(cons 0 "LWPOLYLINE")
	(cons 100 "AcDbEntity")
	(cons 100 "AcDbPolyline")
	(cons 90 (+ i 1))
      )
      (loop i p 1 (+ (sqrt 1.25) 0.5) -1 1)
    )
  )
)

Impératif :

(defun goldenSpiral (p i / b x y n m l)
  (setq	b (- (sqrt 2.) 1.)
	n 1.
	m (+ (sqrt 1.25) 0.5)
	x -1.
	y 1.
  )
  (repeat (setq i (1+ i))
    (setq l (cons (cons 42 b) (cons (cons 10 p) l))
	  p (mapcar '+ p (list (* x n) (* y n)))
    )
    (mapcar 'set '(n m x y) (list m (+ n m) (- y) x))
  )
  (entmakex
    (append
      (list
	(cons 0 "LWPOLYLINE")
	(cons 100 "AcDbEntity")
	(cons 100 "AcDbPolyline")
	(cons 90 i)
      )
      (reverse l)
    )
  )
)

 

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

Posté(e)
Il y a 11 heures, (gile) a dit :

mais ce qui caractérise le nombre d'or, c'est qu'on peut aussi obtenir le terme suivant avec la somme des deux termes précédents, comme avec la suite de Fibonacci.

Merci je prends, j'étais passé à coté de cette propriété.

Joli codes comme toujours 🙂

Apprendre => Prendre => Rendre

Posté(e)

Alors la spirale d'or à ma façon (moins gracieux que Gilles et Bruno), mais j'ai essayé d'éviter la trigonométrie, juste de l'arithmétique.

(defun c:test ( / phi l_r cnt opx opy l)
  (setq
    phi (* (1+ (sqrt 5)) 0.5)
    l_r '(1.0)
    cnt 0
  )
  (initget 7)
  (repeat (getint "\nNombre de répétion?: ")
    (setq l_r (cons (expt phi (setq cnt (1+ cnt))) l_r))
  )
  (setq l_r (reverse l_r) cnt 0 l '((1.0 0.0)))
  (while l_r
    (cond
      ((zerop cnt) (setq opx - opy +))
      ((zerop (rem cnt 4)) (setq  opx - opy + cnt 0))
      ((zerop (rem cnt 3)) (setq opx + opy +))
      ((zerop (rem cnt 2)) (setq opx + opy -))
      ((zerop (rem cnt 1)) (setq opx - opy -))
    )
    (setq
      l (cons (list ((eval opx) (caar l) (car l_r)) ((eval opy) (cadar l) (car l_r))) l)
      l_r (cdr l_r)
      cnt (1+ cnt)
    )
  )
  (entmakex
    (append
      (list
        '(0 . "LWPOLYLINE")
        '(100 . "AcDbEntity")
        '(100 . "AcDbPolyline")
        (cons 90 (length l))
        (cons 70 0)
      )
      (apply 'append
        (mapcar
          (function
            (lambda (x)
              (list
                (cons 10 x)
                (cons 42 (1- (sqrt 2)))
              )
            )
          )
          (reverse l)
        )
      )
    )
  )
)

 

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

Posté(e)

@bonuscad Super, une nouvelle approche.

Comme je disais plus haut, la caractéristique du nombre d'or, c'est qu'il permet de générer une suite géométrique : Un+1 = Un * phi qui est aussi une suite de type Fibonacci : Un+2 = Un+1 + Un. Autrement dit, avec n0 = 1, n+1 = phi, on a n+2 = phi * phi ou n+2 = 1 + phi

Ce qui permet de simplifier le calcul en remplaçant les appels à la fonction expt par de simples additions.

  (setq
    phi (* (1+ (sqrt 5)) 0.5)
    l_r '(1.0)
    cnt 0
  )
  (initget 7)
  (repeat (getint "\nNombre de répétion?: ")
    (setq l_r (cons (expt phi (setq cnt (1+ cnt))) l_r))
  )

par

  (setq l_r (list (* (1+ (sqrt 5)) 0.5) 1.0))
  (initget 7)
  (repeat	(1- (getint "\nNombre de répétion?: "))
    (setq l_r (cons (+ (car l_r) (cadr l_r)) l_r))
  )

 

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

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é