Ruotare un dodecaedro in una DrawingArea: differenze tra le versioni

Da Gambas-it.org - Wikipedia.
Vai alla navigazione Vai alla ricerca
Nessun oggetto della modifica
Nessun oggetto della modifica
 
(3 versioni intermedie di uno stesso utente non sono mostrate)
Riga 1: Riga 1:
Mostreremo un possibile codice per disegnare e ruotare un Dodecaedro con facce pentagonali intorno ai suoi assi X, Y e Z in una ''DrawingArea''.
Mostreremo un possibile codice per disegnare e ruotare un Dodecaedro con facce pentagonali intorno ai suoi assi X, Y e Z in una ''DrawingArea''.


Nell'esempio che segue sarà possibile aumentare o diminuire la dimensione del disegno del Dodecaedro, cliccando rispettivamente sui tasti "+" e "-" della tastiera.
Negli seguenti esempi sarà possibile aumentare o diminuire la dimensione del disegno del Dodecaedro, cliccando rispettivamente sui tasti "+" e "-" della tastiera.
 
===Con effetto della prospettiva sulle facce===
Private DrawingArea1 As DrawingArea
Private Timer1 As Timer
  Private angleX As Float        <FONT Color=gray>' ''Angolo di rotazione sull'asse X''</font>
  Private angleX As Float        <FONT Color=gray>' ''Angolo di rotazione sull'asse X''</font>
  Private angleY As Float        <FONT Color=gray>' ''Angolo di rotazione sull'asse Y''</font>
  Private angleY As Float        <FONT Color=gray>' ''Angolo di rotazione sull'asse Y''</font>
  Private Zoom As Float = 150    <FONT Color=gray>' ''Fattore di ingrandimento''</font>
  Private Zoom As Float = 150    <FONT Color=gray>' ''Zoom isometrico: fattore di ingrandimento''</font>
  Private Vertices As Object[]  <FONT Color=gray>' ''Lista di vertici 3D (Float[])''</font>
  Private Vertices As Object[]  <FONT Color=gray>' ''Lista di vertici 3D (Float[])''</font>
  Private Faces As Object[]      <FONT Color=gray>' ''Lista di facce (ogni faccia è un array di 5 indici)''</font>
  Private Faces As Object[]      <FONT Color=gray>' ''Lista di facce (ogni faccia è un array di 5 indici)''</font>
Riga 12: Riga 16:
   
   
  <FONT Color=gray>' ''Impostazioni iniziali della finestra:''</font>
  <FONT Color=gray>' ''Impostazioni iniziali della finestra:''</font>
   Me.Title = "Dodecaedro rotante con facce pentagonali"
   With Me
  Me.Move(0, 0, Screen.AvailableWidth, Screen.AvailableHeight)
    .Title = "Dodecaedro rotante con facce pentagonali - Proiezione isometrica con effetto prospettico"
  Me.Arrangement = Arrange.Fill
    .Move(0, 0, Screen.AvailableWidth, Screen.AvailableHeight)
    .Arrangement = Arrange.Fill
  End With
<FONT Color=gray>' ''Crea la "DrawingArea":''</font>
  With DrawingArea1 = New DrawingArea(Me) As "DrawingArea1"
    .Background = Color.White
  End With
   
   
  <FONT Color=gray>' ''Inizializza gli array:''</font>
  <FONT Color=gray>' ''Inizializza gli array:''</font>
Riga 63: Riga 74:
   Faces.Push([5, 9, 11, 7, 19])
   Faces.Push([5, 9, 11, 7, 19])
   
   
   Timer1.Delay = 16
   With Timer1 = New Timer As "Timer1"
  Timer1.Start
    .Delay = 16
    .Start
  End With
   
   
  End
  End
Riga 154: Riga 167:
   
   
  End
  End
oppure senza effetto della prospettiva sulle facce:
 
 
===Senza effetto della prospettiva sulle facce===
Private DrawingArea1 As DrawingArea
Private Timer1 As Timer
  Private angleX As Float
  Private angleX As Float
  Private angleY As Float
  Private angleY As Float
  Private Zoom As Float = 200     <FONT Color=gray>' ''Zoom isometrico costante''</font>
  Private Zoom As Float = 150     <FONT Color=gray>' ''Zoom isometrico: fattore di ingrandimento''</font>
  Private Vertices As Object[]
  Private Vertices As Object[]
  Private Faces As Object[]
  Private Faces As Object[]
Riga 164: Riga 181:
  Public Sub Form_Open()
  Public Sub Form_Open()
   
   
   Me.Title = "Dodecaedro rotante - Proiezione isometrica senza effetto prospettico"
<FONT Color=gray>' ''Impostazioni iniziali della finestra:''</font>
  Me.Move(0, 0, Screen.AvailableWidth, Screen.AvailableHeight)
   With Me
  Me.Arrangement = Arrange.Fill
    .Title = "Dodecaedro rotante - Proiezione isometrica senza effetto prospettico"
    .Move(0, 0, Screen.AvailableWidth, Screen.AvailableHeight)
    .Arrangement = Arrange.Fill
  End With
   
   
   DrawingArea1.Background = Color.White
<FONT Color=gray>' ''Crea la "DrawingArea":''</font>
   With DrawingArea1 = New DrawingArea(Me) As "DrawingArea1"
    .Background = Color.White
  End With
   
   
   Vertices = New Object[]
   Vertices = New Object[]
Riga 213: Riga 236:
   Faces.Push([5, 9, 11, 7, 19])
   Faces.Push([5, 9, 11, 7, 19])
   
   
   Timer1.Delay = 16
   With Timer1 = New Timer As "Timer1"
  Timer1.Start
    .Delay = 16
    .Start
  End With
   
   
  End
  End

Versione attuale delle 21:28, 10 set 2025

Mostreremo un possibile codice per disegnare e ruotare un Dodecaedro con facce pentagonali intorno ai suoi assi X, Y e Z in una DrawingArea.

Negli seguenti esempi sarà possibile aumentare o diminuire la dimensione del disegno del Dodecaedro, cliccando rispettivamente sui tasti "+" e "-" della tastiera.

Con effetto della prospettiva sulle facce

Private DrawingArea1 As DrawingArea
Private Timer1 As Timer
Private angleX As Float        ' Angolo di rotazione sull'asse X
Private angleY As Float        ' Angolo di rotazione sull'asse Y
Private Zoom As Float = 150    ' Zoom isometrico: fattore di ingrandimento
Private Vertices As Object[]   ' Lista di vertici 3D (Float[])
Private Faces As Object[]      ' Lista di facce (ogni faccia è un array di 5 indici)


Public Sub Form_Open()

' Impostazioni iniziali della finestra:
 With Me
   .Title = "Dodecaedro rotante con facce pentagonali - Proiezione isometrica con effetto prospettico"
   .Move(0, 0, Screen.AvailableWidth, Screen.AvailableHeight)
   .Arrangement = Arrange.Fill
 End With

' Crea la "DrawingArea":
 With DrawingArea1 = New DrawingArea(Me) As "DrawingArea1"
   .Background = Color.White
 End With

' Inizializza gli array:
 Vertices = New Object[]
 Faces = New Object[]

' Sezione aurea e valori derivati per la costruzione del dodecaedro:
 Dim phi As Float = (1 + Sqr(5)) / 2
 Dim a As Float = 1
 Dim b As Float = 1 / phi

' === 20 Vertici del dodecaedro ===
' I vertici sono scelti in modo simmetrico e disposti con coordinate note:
 Vertices.Push([ a,  a,  a])     '  0
 Vertices.Push([ a,  a, -a])     '  1
 Vertices.Push([ a, -a,  a])     '  2
 Vertices.Push([ a, -a, -a])     '  3
 Vertices.Push([-a,  a,  a])     '  4
 Vertices.Push([-a,  a, -a])     '  5
 Vertices.Push([-a, -a,  a])     '  6
 Vertices.Push([-a, -a, -a])     '  7
 Vertices.Push([ 0,  b,  phi])   '  8
 Vertices.Push([ 0,  b, -phi])   '  9
 Vertices.Push([ 0, -b,  phi])   ' 10
 Vertices.Push([ 0, -b, -phi])   ' 11
 Vertices.Push([ b,  phi, 0])    ' 12
 Vertices.Push([ b, -phi, 0])    ' 13
 Vertices.Push([-b, phi, 0])     ' 14
 Vertices.Push([-b, -phi, 0])    ' 15
 Vertices.Push([ phi, 0,  b])    ' 16
 Vertices.Push([ phi, 0, -b])    ' 17
 Vertices.Push([-phi, 0,  b])    ' 18
 Vertices.Push([-phi, 0, -b])    ' 19

' === 12 Facce pentagonali, ognuna con 5 indici di vertici ===
' L'ordine dei vertici garantisce facce chiuse, senza incroci:
 Faces.Push([0, 8, 10, 2, 16])
 Faces.Push([0, 16, 17, 1, 12])
 Faces.Push([0, 12, 14, 4, 8])
 Faces.Push([8, 4, 18, 6, 10])
 Faces.Push([10, 6, 15, 13, 2])
 Faces.Push([2, 13, 3, 17, 16])
 Faces.Push([1, 17, 3, 11, 9])
 Faces.Push([1, 9, 5, 14, 12])
 Faces.Push([4, 14, 5, 19, 18])
 Faces.Push([6, 18, 19, 7, 15])
 Faces.Push([3, 13, 15, 7, 11])
 Faces.Push([5, 9, 11, 7, 19])

 With Timer1 = New Timer As "Timer1"
   .Delay = 16
   .Start
 End With

End


Public Sub Timer1_Timer()

' Aggiorna gli angoli di rotazione:
 angleX += 0.02
 angleY += 0.015

 DrawingArea1.Refresh

End


Public Sub DrawingArea1_Draw()

' Centro della DrawingArea:
 Dim w As Integer = DrawingArea1.W
 Dim h As Integer = DrawingArea1.H
 Dim cx As Float = w / 2
 Dim cy As Float = h / 2

' Array dei punti proiettati 2D:
 Dim points As Object[] = New Object[]

' Sfondo bianco:
 Paint.FillRect(0, 0, w, h, Color.White)

' Proiezione 3D → 2D per ciascun vertice:
 For Each v As Float[] In Vertices
   Dim x, y, z As Float
   x = v[0]
   y = v[1]
   z = v[2]

' Rotazione sull'asse X:
   Dim y1 As Float = y * Cos(angleX) - z * Sin(angleX)
   Dim z1 As Float = y * Sin(angleX) + z * Cos(angleX)
   y = y1
   z = z1

' Rotazione sull'asse Y:
   Dim x1 As Float = x * Cos(angleY) + z * Sin(angleY)
   z1 = -x * Sin(angleY) + z * Cos(angleY)
   x = x1
   z = z1

' Proiezione prospettica (evita divisione per zero):
   If (z + 3) < 0.1 Then Continue

' Interpolazione tra prospettiva e isometria:
   Dim factor As Float = 0.3    ' 0 = isometrica, 1 = prospettiva completa
   Dim scale As Float = Zoom / (1 + factor * (z + 3))

   Dim sx As Float = cx + x * scale
   Dim sy As Float = cy - y * scale

   points.Push([sx, sy])
 Next

' Disegna ogni faccia (5 lati chiusi):
 Paint.Brush = Paint.Color(Color.Black)
 For Each f As Integer[] In Faces
   Dim i As Integer
   For i = 0 To f.Count - 1
     Dim p1 As Float[] = points[f[i]]
     Dim p2 As Float[] = points[(f[(i + 1) Mod f.Count])]
     Paint.MoveTo(p1[0], p1[1])
     Paint.LineTo(p2[0], p2[1])
     Paint.Stroke
   Next
 Next
 
End


Public Sub Form_KeyPress()

Select Case Key.Code
  Case Key["+"]
   Zoom = Min(Zoom + 25, 1000)
 Case Key["-"]
   Zoom = Max(Zoom - 25, 25)
 End Select

 DrawingArea1.Refresh

End


Senza effetto della prospettiva sulle facce

Private DrawingArea1 As DrawingArea
Private Timer1 As Timer
Private angleX As Float
Private angleY As Float
Private Zoom As Float = 150      ' Zoom isometrico: fattore di ingrandimento
Private Vertices As Object[]
Private Faces As Object[]


Public Sub Form_Open()

' Impostazioni iniziali della finestra:
 With Me
   .Title = "Dodecaedro rotante - Proiezione isometrica senza effetto prospettico"
   .Move(0, 0, Screen.AvailableWidth, Screen.AvailableHeight)
   .Arrangement = Arrange.Fill
 End With

' Crea la "DrawingArea":
 With DrawingArea1 = New DrawingArea(Me) As "DrawingArea1"
   .Background = Color.White
 End With

 Vertices = New Object[]
 Faces = New Object[]

 Dim phi As Float = (1 + Sqr(5)) / 2
 Dim a As Float = 1
 Dim b As Float = 1 / phi

' === 20 Vertici ===
 Vertices.Push([a, a, a])    ' 0
 Vertices.Push([a, a, -a])    ' 1
 Vertices.Push([a, -a, a])    ' 2
 Vertices.Push([a, -a, -a])    ' 3
 Vertices.Push([-a, a, a])    ' 4
 Vertices.Push([-a, a, -a])    ' 5
 Vertices.Push([-a, -a, a])    ' 6
 Vertices.Push([-a, -a, -a])    ' 7
 Vertices.Push([0, b, phi])  ' 8
 Vertices.Push([0, b, -phi])  ' 9
 Vertices.Push([0, -b, phi])  '10
 Vertices.Push([0, -b, -phi])  '11
 Vertices.Push([b, phi, 0])   '12
 Vertices.Push([b, -phi, 0])   '13
 Vertices.Push([-b, phi, 0])    '14
 Vertices.Push([-b, -phi, 0])   '15
 Vertices.Push([phi, 0, b])   '16
 Vertices.Push([phi, 0, -b])   '17
 Vertices.Push([-phi, 0, b])   '18
 Vertices.Push([-phi, 0, -b])   '19

' === 12 Facce pentagonali (5 vertici ciascuna) ===
 Faces.Push([0, 8, 10, 2, 16])
 Faces.Push([0, 16, 17, 1, 12])
 Faces.Push([0, 12, 14, 4, 8])
 Faces.Push([8, 4, 18, 6, 10])
 Faces.Push([10, 6, 15, 13, 2])
 Faces.Push([2, 13, 3, 17, 16])
 Faces.Push([1, 17, 3, 11, 9])
 Faces.Push([1, 9, 5, 14, 12])
 Faces.Push([4, 14, 5, 19, 18])
 Faces.Push([6, 18, 19, 7, 15])
 Faces.Push([3, 13, 15, 7, 11])
 Faces.Push([5, 9, 11, 7, 19])

 With Timer1 = New Timer As "Timer1"
   .Delay = 16
   .Start
 End With

End


Public Sub Timer1_Timer()

 angleX += 0.02
 angleY += 0.015
 DrawingArea1.Refresh

End


Public Sub DrawingArea1_Draw()

 Dim w As Integer = DrawingArea1.W
 Dim h As Integer = DrawingArea1.H
 Dim cx As Float = w / 2
 Dim cy As Float = h / 2
 Dim points As Object[] = New Object[]
 Dim rotatedZs As Float[] = New Float[Vertices.Count]      ' Per z-sorting

' === Proiezione isometrica: nessuna prospettiva ===
 For Each v As Float[] In Vertices
   Dim x, y, z As Float
   x = v[0]
   y = v[1]
   z = v[2]

' Rotazione attorno a X:
   Dim y1 As Float = y * Cos(angleX) - z * Sin(angleX)
   Dim z1 As Float = y * Sin(angleX) + z * Cos(angleX)
   y = y1
   z = z1

' Rotazione attorno a Y:
   Dim x1 As Float = x * Cos(angleY) + z * Sin(angleY)
   z1 = -x * Sin(angleY) + z * Cos(angleY)
   x = x1
   z = z1

   Dim sx As Float = cx + x * Zoom
   Dim sy As Float = cy - y * Zoom

   points.Push([sx, sy])
   rotatedZs[points.Max] = z    ' Salva profondità per z-sorting
 Next

' === Calcolo media z per ciascuna faccia ===:
 Dim FaceDepths As Float[] = New Float[Faces.Count]
 Dim i, j, tmp As Integer

 For i = 0 To Faces.Max
   Dim f As Integer[] = Faces[i]
   Dim sumZ As Float = 0
   For Each vi As Integer In f
     sumZ += rotatedZs[vi]
   Next
   FaceDepths[i] = sumZ / f.Count
 Next

' === Ordina facce dal fondo verso il fronte ===
 Dim order As Integer[] = New Integer[Faces.Count]
 For i = 0 To order.Max
   order[i] = i
 Next

 For i = 0 To order.Max - 1
   For j = i + 1 To order.Max
     If FaceDepths[order[i]] > FaceDepths[order[j]] Then
       tmp = order[i]
       order[i] = order[j]
       order[j] = tmp
     Endif
   Next
 Next

' === Disegna facce ordinate ===
 Paint.Brush = Paint.Color(Color.Black)
 For Each fi As Integer In order
    f = Faces[fi]
   For i = 0 To f.Count - 1
     Dim p1 As Float[] = points[f[i]]
     Dim p2 As Float[] = points[(f[(i + 1) Mod f.Count])]
     Paint.MoveTo(p1[0], p1[1])
     Paint.LineTo(p2[0], p2[1])
     Paint.Stroke
   Next
 Next

End


Public Sub Form_KeyPress()

 Select Case Key.Code
   Case Key["+"]
     Zoom = Min(Zoom + 25, 1000)
   Case Key["-"]
     Zoom = Max(Zoom - 25, 50)
 End Select

 DrawingArea1.Refresh

End