Capitolo 14
Argomenti: la spugna di Menger

Livello: Avanzato

In questo capitolo costruiremo un solido frattale chiamato spugna di Menger. Questi sono i primi passi per creare questo solito:

PIC

Passo 0

PIC

Passo 1


PIC

Passo 2

PIC

Passo 3

Questo capitolo contiene due sezioni:

14.1 Primo approccio: ricorsione

Consideriamo una spugna di Menger di ordine n con spigolo L.

PIC

Nello schema notiamo che la spugna contiene 20 spugne di Menger di ordine n - 1 di spigolo L
--
 3. La natura ricorsiva della spugna e’ evidente.

14.1.1 Il programma

per cubo :l 
  Se :counter=10000 [VistaPoligono3D] 
  AssegnaVarLocale "colori [Giallo Magenta Ciano Blu] 
  # facce laterali 
  Ripeti 4 [ImpostaColorePenna Lancia Elemento ContaRipetizioni :colori 
  quadrato :l RuotaDestra 90 Avanti  :l RuotaSinistra 90 RollioDestra 90] 
  # faccia inferiore 
  ImpostaColorePenna Rosso BeccheggiaGiu 90 quadrato :l BeccheggiaSu 90 
  Avanti :l BeccheggiaGiu 90 ImpostaColorePenna Verde quadrato :l 
  BeccheggiaSu 90 Indietro :l 
fine 
 
per quadrato :c 
  AssegnaVar "counter :counter+1 
  InizioPoligono 
  Ripeti 4 [Avanti :c RuotaDestra 90] 
  FinePoligono 
fine 
 
# spugna di menger 
# p: ordine di ricorsione 
# l: spigolo del cubo 
per menger :l :p 
  Se :p=0 [cubo :l] [ 
    AssegnaVarLocale "p :p-1 
    AssegnaVarLocale "l :l/3 
    # faccia frontale 
    Ripeti 3 [menger :l :p Avanti :l] Indietro 3*:l 
    RuotaDestra 90 Avanti :l RuotaSinistra 90 
    menger :l :p Avanti 2*:l menger :l :p Indietro 2*:l 
    RuotaDestra 90 Avanti :l RuotaSinistra 90 
    Ripeti 3 [menger :l :p Avanti :l] Indietro 3*:l 
    # faccia di destra 
   BeccheggiaGiu 90 Avanti :l BeccheggiaSu 90 
    menger :l :p  Avanti 2*:l menger :l :p Indietro 2*:l 
    BeccheggiaGiu 90 Avanti :l BeccheggiaSu 90 
    Ripeti 3 [menger :l :p Avanti :l] Indietro 3*:l 
    RuotaSinistra 90 Avanti :l RuotaDestra 90 
    menger :l :p  Avanti 2*:l menger :l :p Indietro 2*:l 
    RuotaSinistra 90 Avanti :l RuotaDestra 90 
    Ripeti 3 [menger :l :p Avanti :l] Indietro 3*:l 
    BeccheggiaGiu 90 Indietro :l BeccheggiaSu 90 
    menger :l :p  Avanti 2*:l menger :l :p Indietro 2*:l 
     BeccheggiaGiu 90 Indietro :l BeccheggiaSu 90 
  ] 
fine 
 
per spugna :p 
  PulisciSchermo NascondiTartaruga AssegnaVar "counter 0 3D 
  ImpostaColoreSfondo 0 menger 800 :p 
  Scrivi [nombre ColorePenna polygone: ] Stampa :counter 
  VistaPoligono3D 
fine

Il programma ha quattro procedure:

Il vantaggio di questo programma e’ di sfruttare la struttura ricorsiva del solido. Il metodo e’ molto simile a quello usato per disegnare il fiocco di neve di Van Kock a pagina §. Il vantaggio della ricorsione e’ una codice piuttosto snello.
Il principale svantaggio di questo approccio e’ che, essendo ricorsivo, richiede molta memoria per la sua esecuzione. Infatti una spugna di ordine 3 disegna 48000 poligoni. XLOGO richiede in questo caso di alzare il limite della memoria interna di 256 MB (impostabile nel pannello delle preferenze) per prevenire l’overflow.

14.2 Secondo approccio: il tappeto Sierpinski

Se vogliamo disegnare una spugna di Menger di ordine 4, dobbiamo ripensare il programma e dimenticare la ricorsione. Creeremo un programma che disegnerą il solido di Menger di ordine 0, 1, 2, 3 e 4.

14.2.1 il tappeto di Sierpinski

La spugna di Menger e’ una generalizzazione in 3 dimensioni di una figura piana chiamata “tappeto di Sierpinski”. Questi sono i primi passi per generare questa figura:

PIC
Passo 0

PIC
Passo 1

PIC
Passo 2

PIC
Passo 3



Ciascuna faccia della spugna di Menger di ordine p e’ un tappeto di Sierpinski di ordine p.

14.2.2 Disegnare un tappeto Sierpinski di ordine p

L’obiettivo e’ di usare il minor numero possibile di poligoni per disegnare un tappeto Sierpinski. Il seguente esempio spiega come disegnare un tappeto di ordine 3. Il primo quadrato ha 33 = 27 linee e 27 colonne. Scriviamo in base 3 ciascun numero di riga e ciascun numero di colonna.

Abbiamo costruito un tappeto Sierpinski di ordine 3. Per disegnare tale poligono abbiamo bisogno di 16 + 16 + 32 + 16 = 80 poligoni.

14.2.3 Tutti i diversi possibili schemi per le colonne

Per riassumere, ecco i diversi schemi delle colonne per i vari numeri di riga (il simbolo * rappresenta 0 o 2).



Numero di righe Schema da applicare


*** 27


1** 9 9 9


*1* 3 3 6 3 6 3 3


11* 3 3 3 9 3 3 3


Allo stesso modo, per costruire un tappeto di ordine 4 abbiamo bisogno di un quadrato di 34 = 81 unitą. Le righe e le colonne avranno numeri a base 3 di 4 cifre. Per ciascun numero di riga ecco lo schema da applicare (il simbolo * rappresenta 0 o 2).



Numero di righe Schema da applicare


**** 81


1*** 27 27 27


*1** 9 9 18 9 18 9 9


**1* 3 3 6 3 6 3 6 3 6 3 6 3 6 3 6 3 6 3 3


*11* 3 3 3 9 3 3 6 3 3 9 3 3 6 3 3 9 3 3 3


1*1* 3 3 6 3 6 3 3 27 3 3 6 3 6 3 3


11** 9 9 9 27 9 9 9


111* 3 3 3 9 3 3 3 27 3 3 3 9 3 3 3



496 poligoni sono necessari in questo caso.
Infine questo e’ lo schema per una figura di ordine 2.



Numero di righe Schema da applicare


** 9


1* 3 3 3


14.2.4 Il programma

# disegna un tappeto sierpinski carpet di ordine :p e dimensione :size 
per carpet :size :p 
  AssegnaVar "unit :size/(Potenza 3 :p) 
  Se :p=0 [ rec :size :size Ferma] 
  Se :p=1 [Ripeti 4 [rec :size :unit Avanti :size RuotaDestra 90 ] Ferma] 
  RipetiPer (Elenco "x 1 Potenza 3 :p) [ 
    AssegnaVarLocale "cantorx cantor :x :p [] 
  # non abbiamo disegnato gli elementi con un 1 in Ultimo Posizione 
  Se  non (1=last :cantorx)  [ 
    AssegnaVarLocale "nom evalue EccettoUltimo :cantorx " 
    drawcolumn :x Proprieta "map :nom 
    ] 
  ] 
fine 
 
# Restituisce il numero in base 3 
# p ordeine del tappeto 
# :list Elenco vuoto 
per cantor :x :p :list 
  Se :p=0 [Output :list] 
  AssegnaVarLocale "a Potenza 3 :p-1 
  Se :x<= :a [ 
    Output cantor  :x :p-1  Frase :list 0] 
    [ Se :x<=2*:a [Output cantor  :x-:a :p-1  Frase :list 1] 
    Output cantor :x-2*:a :p-1 Frase :list 0] 
fine 
 
# Disegna la colonna numero x 
# rispetto lo schema nellelenco :list 
per drawcolumn :x :list 
  PennaSu  RuotaDestra 90 Avanti (:x-1)*:unit RuotaSinistra 90 
  PennaGiu des :list 
  PennaSu RuotaSinistra 90 Avanti (:x-1)*:unit RuotaDestra 90 
  Avanti :x*:unit RuotaDestra 90 PennaGiu des :list 
  PennaSu RuotaSinistra 90 Indietro :x*:unit PennaGiu 
fine 
 
# Disegna un rettangolo delle dimensioni scelte 
# e lo immagazzina nel visualizzatore 3D 
per rec :lo :la 
  AssegnaVar "compteur :compteur+1 
  InizioPoligono 
  Ripeti 2 [Avanti :lo RuotaDestra 90 Avanti :la RuotaDestra 90] 
  FinePoligono 
fine 
 
# definisce le diverse possibile colonne 
per initmap 
  AggiungiProprieta "map 111 [3 3 3 9 3 3 3 27 3 3 3 9 3 3 3] 
  AggiungiProprieta "map 110 [9 9 9 27 9 9 9] 
  AggiungiProprieta "map 101 [3 3 6 3 6 3 3 27 3 3 6 3 6 3 3] 
  AggiungiProprieta "map 011 [3 3 3 9 3 3 6 3 3 9 3 3 6 3 3 9 3 3 3] 
  AggiungiProprieta "map 000 [81] 
  AggiungiProprieta "map 100 [27 27 27] 
  AggiungiProprieta "map 010 [9 9 18 9 18 9 9] 
  AggiungiProprieta "map 001 [3 3 6 3 6 3 6 3 6 3 6 3 6 3 6 3 6 3 3] 
  AggiungiProprieta "map 01 [3 3 6 3 6 3 3] 
  AggiungiProprieta "map 00 [27] 
  AggiungiProprieta "map 10 [9 9 9] 
  AggiungiProprieta "map 11 [3 3 3 9 3 3 3] 
  AggiungiProprieta "map 1 [3 3 3] 
  AggiungiProprieta "map 0 [9] 
fine 
 
# Se il numero in base 3 e [1 0 1] restituisce  101 
per evalue :list :mot 
  Se Vuoto? :list [Output :mot] 
  [ 
    AssegnaVarLocale "mot Parola :mot Primo :list 
    Output evalue EccettoPrimo :list :mot 
  ] 
fine 
 
# Disegna il blocco dei rettangoli alternati 
per des :list 
  AssegnaVarLocale "somme 0 
  RipetiPer (Elenco "i 1 Conta :list) [ 
     AssegnaVarLocale "element Elemento :i :list 
      AssegnaVarLocale "somme :element+:somme 
      Se pari? :i [PennaSu Avanti :element*:unit PennaGiu ] 
     [rec :element*:unit :unit Avanti :element*:unit] 
  ] 
  PennaSu Indietro  :somme * :unit PennaGiu 
fine 
 
# :i e un numero pari? 
per pari? :i 
  Output 0=resto :i 2 
fine 
 
# Disegna il tappeto di ordine :p 
per tappeto :p 
  PulisciSchermo 3D NascondiTartaruga initmap 
  AssegnaVar "compteur 0 
  carpet 810 :p 
  Scrivi "Numero di poligoni:\  Stampa :compteur 
  VistaPoligono3D 
fine

tappeto 3 disegna un tappeto di Sierpinski di ordine 3 e di lato uguale a 810. Eccoci! Ora possiamo tornare alla spugna di Menger!

14.2.5 La spugna di Menger di ordine 4

La spugna di Menger ha molte simmetrie. Per costruire la spugna disegneremo le diverse sezioni lungo il piano (xOy) e quindi ripetiamo queste figure lungo i piani (yOz) e (xOz). Per spiegare cosa succede consideriamo la spugna di ordine 2. Quando tagliamo con un piano verticale possiamo ottenere quattro linee:

PIC
PIC
PIC
PIC

Per disegnare una spugna di ordine 3 faremo una ricerca nei numeri da 1 a 27, cioe’ da 001 a 222 in base 3. Per ciascun numero applicheremo la sezione valida e riporteremo questa figura lungo (Ox), (Oy) e (Oz).

Il programma

Con questo programma possiamo disegnare la spugna di Menger di ordine 0,1,2,3 e 4.

# disegna un tappeto sierpinski carpet di ordine :p e dimensione :size 
per carpet :size :p 
  AssegnaVar "unit :size/(Potenza 3 :p) 
  Se :p=0 [ rec :size :size Ferma] 
  Se :p=1 [Ripeti 4 [rec :size :unit Avanti :size RuotaDestra 90 ] Ferma] 
  RipetiPer (Lista "x 1 Potenza 3 :p) [ 
    AssegnaVarLocale "cantorx cantor :x :p [] 
    # non abbiamo disegnato gli elementi con un 1 in Ultimo Posizione 
  Se  non (1=last :cantorx)  [ 
    AssegnaVarLocale "nom evalue EccettoUltimo :cantorx " 
    drawcolumn :x Proprieta "map :nom 
    ] 
  ] 
fine 
 
# Restituisce il numero in base 3 
# p ordeine del tappeto 
# :list Elenco vuoto 
per cantor :x :p :list 
  Se :p=0 [Output :list] 
  AssegnaVarLocale "a Potenza 3 :p-1 
  Se :x<= :a [ 
    Output cantor  :x :p-1  Frase :list 0] 
    [ Se :x<=2*:a [Output cantor  :x-:a :p-1  Frase :list 1] 
    Output cantor :x-2*:a :p-1 Frase :list 2] 
fine 
 
# Disegna la colonna numero x 
# rispetto lo schema nellelenco :list 
per drawcolumn :x :list 
  PennaSu  RuotaDestra 90 Avanti (:x-1)*:unit 
  RuotaSinistra 90  PennaGiu des :list 
  PennaSu RuotaSinistra 90 Avanti (:x-1)*:unit 
  RuotaDestra 90 Avanti :x*:unit RuotaDestra 90 PennaGiu des :list 
  PennaSu RuotaSinistra 90 Indietro :x*:unit PennaGiu 
fine 
 
# Disegna un rettangolo delle dimensioni scelte 
# e lo immagazzina nel visualizzatore 3D 
per rec :lo :la 
  AssegnaVar "counter :counter+1 
  InizioPoligono 
  Ripeti 2 [Avanti :lo RuotaDestra 90 Avanti :la RuotaDestra 90] 
  FinePoligono 
fine 
 
# definisce le diverse possibile colonne 
per initmap 
  AggiungiProprieta "map 111 [3 3 3 9 3 3 3 27 3 3 3 9 3 3 3] 
  AggiungiProprieta "map 110 [9 9 9 27 9 9 9] 
  AggiungiProprieta "map 101 [3 3 6 3 6 3 3 27 3 3 6 3 6 3 3] 
  AggiungiProprieta "map 011 [3 3 3 9 3 3 6 3 3 9 3 3 6 3 3 9 3 3 3] 
  AggiungiProprieta "map 000 [81] 
  AggiungiProprieta "map 100 [27 27 27] 
  AggiungiProprieta "map 010 [9 9 18 9 18 9 9] 
  AggiungiProprieta "map 001 [3 3 6 3 6 3 6 3 6 3 6 3 6 3 6 3 6 3 3] 
  AggiungiProprieta "map 01 [3 3 6 3 6 3 3] 
  AggiungiProprieta "map 00 [27] 
  AggiungiProprieta "map 10 [9 9 9] 
  AggiungiProprieta "map 11 [3 3 3 9 3 3 3] 
  AggiungiProprieta "map 1 [3 3 3] 
  AggiungiProprieta "map 0 [9] 
fine 
 
# Se il numero in base 3 e [1 0 1] restituisce 101 
# Se il numero in base 3 e [1 0 2] restituisce 100 
# gli elementi da :list sono tradotti in un parola 
# 2 sono sostituiti da 0 
 
per evalue :list :mot 
  Se Vuoto? :list [Output :mot] 
    [ 
    AssegnaVarLocale "first Primo :list 
    Se :first=2 [AssegnaVarLocale "first 0] 
   AssegnaVarLocale "mot Parola :mot :first 
    Output evalue EccettoUltimo :list :mot 
  ] 
fine 
 
# Disegna il blocco dei rettangoli alternati 
per des :list 
  AssegnaVarLocale "somme 0 
  RipetiPer (Lista "i 1 Conta :list) [ 
     AssegnaVarLocale "element Elemento :i :list 
      AssegnaVarLocale "somme :element+:somme 
    Se even? :i [PennaSu Avanti :element*:unit PennaGiu ] 
        [rec :element*:unit :unit Avanti :element*:unit] 
  ] 
  PennaSu Indietro  :somme * :unit PennaGiu 
fine 
 
# Disegna il tappeto di ordine :p 
per tapis :p 
  PulisciSchermo 3D NascondiTartaruga initmap 
  AssegnaVar "compteur 0 
  carpet 810 :p 
  Scrivi "nombre\ de\ polygones:\  Stampa :compteur 
  VistaPoligono3D 
fine 
 
# :i e un numero pari? 
per even? :i 
  Output 0=modulo :i 2 
fine 
 
 
# Rimuovi lultimo 1 da :list 
per deletelastone :list 
  RipetiPer (Lista "i Conta :list 1 Meno 1) [ 
    AssegnaVarLocale "element Elemento :i :list 
    Se :element=1 [AssegnaVarLocale "list Sostituisci :list :i 0 
  Ferma] [Se :element=2 [Ferma]] 
  ] 
  Output :list 
fine 
 
# disegna il tappeto di serpinski 
# lungo lasse (ox), (oy) e (oz) 
per DisegnaTappeto3 :size :order :z 
  PennaSu Origine 
  BeccheggiaSu 90 Avanti (:z-1)*:unite BeccheggiaGiu 90 PennaGiu 
  ImpostaColorePenna Blu Lancia :order :size 
  PennaSu Origine 
  RollioSinistra 90 Avanti (:z-1)*:unite BeccheggiaGiu 90  PennaGiu 
  ImpostaColorePenna Giallo Lancia :order :size 
  PennaSu Origine 
  BeccheggiaSu 90 Avanti :size RuotaDestra 90 Avanti (:z-1)*:unite 
  BeccheggiaGiu 90 PennaGiu 
  ImpostaColorePenna Magenta Lancia :order :size 
fine 
 
# spugna di menger di ordine :p e dimensione :size 
per menger :size :p 
  AssegnaVar "unite :size/(Potenza 3 :p) 
  RipetiPer (Lista "z 1 Potenza 3 :p) [ 
    AssegnaVarLocale "cantorz cantor :z :p [] 
    AssegnaVarLocale "last Ultimo :cantorz 
    AssegnaVarLocale "cantorz EccettoUltimo :cantorz 
    Se :last=0 [AssegnaVarLocale "order evalue deletelastone :cantorz "] 
             [AssegnaVarLocale "order evalue :cantorz "] 
    AssegnaVarLocale "order Parola "coupe :order 
    DisegnaTappeto3 :size :order :z 
    PennaSu BeccheggiaSu 90 Avanti :unit BeccheggiaGiu 90 PennaGiu 
  ] 
  DisegnaTappeto3 :size :order (Potenza 3 :p)+1 
fine 
 
 
# procedure pricipale 
# disegna una spugna di ordine :p di spigolo 405 
per sponge :p 
  PulisciSchermo ImpostaColoreSfondo 0 3D NascondiTartaruga 
  AssegnaVarLocale "time SecondiDaAvvio 
  initmap 
  AssegnaVar "counter 0 
  Se :p=0 [cube 405] [menger 405 :p] 
  # Visualizza il tempo di esecuzione 
  Scrivi "numero\ poligoni:\  Stampa :counter 
  Scrivi "Tempo:\  Stampa SecondiDaAvvio -:time 
  VistaPoligono3D 
fine 
 
# diverse sezioni per menger di ordine 2 
per coupe1 :size 
  Ripeti 4 [carpet :size/3 1 PennaSu Avanti :size RuotaDestra 90 PennaGiu] 
fine 
 
per coupe0 :size 
  carpet :size 2 
fine 
 
# diverse sezioni per menger di ordine 3 
 
per coupe10 :size 
  Ripeti 4 [carpet :size/3 2 PennaSu Avanti :size RuotaDestra 90 PennaGiu] 
fine 
 
per coupe01 :size 
  Ripeti 4 [Ripeti 2 [coupe1 :size/3 PennaSu Avanti :size/3 PennaGiu] 
  Avanti :size/3 RuotaDestra 90] 
fine 
 
per coupe11 :size 
  Ripeti 4 [coupe1 :size/3 PennaSu Avanti :size RuotaDestra 90 PennaGiu] 
fine 
 
 
per coupe00 :size 
  carpet :size 3 
fine 
 
# diverse sezioni per menger di ordine 4 
per coupe000 :size 
  carpet :size 4 
fine 
 
per coupe100 :size 
  Ripeti 4 [carpet :size/3 3 PennaSu Avanti :size RuotaDestra 90 PennaGiu] 
fine 
 
per coupe010 :size 
  Ripeti 4 [Ripeti 2 [coupe10 :size/3 PennaSu Avanti :size/3 PennaGiu] 
  Avanti :size/3 RuotaDestra 90] 
fine 
 
per coupe001 :size 
  Ripeti 4 [Ripeti 2 [coupe01 :size/3 PennaSu Avanti :size/3 PennaGiu] 
  Avanti :size/3 RuotaDestra 90] 
fine 
 
per coupe110 :size 
  Ripeti 4 [coupe10 :size/3 PennaSu Avanti :size PennaGiu RuotaDestra 90 ] 
fine 
 
per coupe111 :size 
  Ripeti 4 [coupe11 :size/3 PennaSu Avanti :size RuotaDestra 90 PennaGiu] 
fine 
 
per coupe101 :size 
  Ripeti 4 [coupe01 :size/3 PennaSu Avanti :size RuotaDestra 90 PennaGiu] 
fine 
 
per coupe011 :size 
  Ripeti 4 [Ripeti 2 [coupe11 :size/3 PennaSu Avanti :size/3 PennaGiu] 
  Avanti :size/3 RuotaDestra 90] 
fine 
 
per coupe :size 
  carpet :size 1 
fine 
 
per cube :size 
  Ripeti 2 [ 
  ImpostaColorePenna Blu rec :size :size PennaSu Avanti :size 
  BeccheggiaGiu 90 PennaGiu 
  ImpostaColorePenna Giallo rec :size :size PennaSu Avanti :size 
  BeccheggiaGiu 90  PennaGiu 
  ] 
  ImpostaColorePenna Magenta 
  PennaSu RollioSinistra 90 RuotaSinistra 90 Avanti :size 
  RuotaDestra 90 PennaGiu rec :size :size 
  PennaSu RuotaDestra 90 Avanti :size RuotaSinistra 90 
  RollioDestra 90 RuotaDestra 90 Avanti :size RuotaSinistra 90 
  RollioDestra 90 PennaGiu rec :size  :size 
  RollioSinistra 90 RuotaSinistra 90 Avanti :size RuotaDestra 90 
fine

Occorre impostare la memoria disponibile per XLOGO a 640 MB: spugna 4.

PIC