Ruotare una sfera 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
Riga 115: Riga 115:
  End
  End
    
    
  Public Sub Form_KeyPress()  ' Gestione della tastiera per controllare lo zoom
  Public Sub Form_KeyPress()  <FONT Color=gray>' ''Gestione della tastiera per controllare lo zoom''</font>
   
   
   Select Case Key.Code
   Select Case Key.Code
Riga 131: Riga 131:
===Caricare una mappa terrestre equirettangolare===
===Caricare una mappa terrestre equirettangolare===
Di seguito mostreremo un codice per adattare sulla sfera una mappa terrestre equirettangolare, al fine di far apparire la sfera come il pianeta terra in rotazione.
Di seguito mostreremo un codice per adattare sulla sfera una mappa terrestre equirettangolare, al fine di far apparire la sfera come il pianeta terra in rotazione.
<BR>Il file immagine contenente i dati della mappa equirettangolare deve essere del formato PNG.
<BR>Supporremo che il file immagine della mappa sia posto nella cartella "/tmp".
  <FONT Color=gray>' ''=== Costanti e variabili globali ===''</font>
  <FONT Color=gray>' ''=== Costanti e variabili globali ===''</font>
  Private Const RAGGIO_SFERA As Integer = 100   <FONT Color=gray>' ''Raggio della sfera da disegnare''</font>
  Private zoom_raggio_sfera As Integer = 100   <FONT Color=gray>' ''Raggio della sfera da disegnare''</font>
  Private angle As Float                        <FONT Color=gray>' ''Angolo di rotazione attorno all’asse Y''</font>
  Private angle As Float                        <FONT Color=gray>' ''Angolo di rotazione attorno all’asse Y''</font>
  Private map As Image                          <FONT Color=gray>' ''Mappa terrestre in proiezione equirettangolare''</font>
  Private map As Image                          <FONT Color=gray>' ''Mappa terrestre in proiezione equirettangolare''</font>
Riga 148: Riga 146:
   
   
  <FONT Color=gray>' ''Carica la mappa terrestre (proiezione equirettangolare):''</font>
  <FONT Color=gray>' ''Carica la mappa terrestre (proiezione equirettangolare):''</font>
   map = Image.Load("<FONT Color=darkgreen>''/tmp/Equirectangular-projection.PNG''</font>")
   map = Image.Load("<FONT Color=darkgreen>''/percorso/del/file/immagine/proiezione-equirettangolare''</font>")
   
   
  <FONT Color=gray>' ''Avvia il timer con ~60 fotogrammi al secondo:''</font>
  <FONT Color=gray>' ''Avvia il timer con ~60 fotogrammi al secondo:''</font>
Riga 176: Riga 174:
   Dim cx As Float = DrawingArea1.Width / 2
   Dim cx As Float = DrawingArea1.Width / 2
   Dim cy As Float = DrawingArea1.Height / 2
   Dim cy As Float = DrawingArea1.Height / 2
   Dim r As Float = RAGGIO_SFERA
   Dim r As Float = zoom_raggio_sfera
   
   
  <FONT Color=gray>' ''Dimensioni dell’immagine mappa:''</font>
  <FONT Color=gray>' ''Dimensioni dell’immagine mappa:''</font>
Riga 243: Riga 241:
   
   
   Paint.End
   Paint.End
End
Public Sub Form_KeyPress()  <FONT Color=gray>' ''Gestione della tastiera per controllare lo zoom''</font>
  Select Case Key.Code
    Case Key["+"]
      zoom_raggio_sfera = Min(zoom_raggio_sfera + 25, 1000)
    Case Key["-"]
      zoom_raggio_sfera = Max(zoom_raggio_sfera - 25, 25)
  End Select
DrawingArea1.Refresh
   
   
  End
  End

Versione delle 14:12, 21 lug 2025

Di seguito mostreremo un possibile codice per ottenere l'effetto di una sfera che ruota in senso antiorario.

' Costanti per raggio della sfera e numero di punti visibili:
Private Const NUM_POINTS As Integer = 200
Private Zoom_Raggio_Sfera As Integer = 100

' Angolo di rotazione della sfera (in radianti):
Private angle As Float

' Array contenente i punti 3D generati sulla superficie della sfera
' Ogni elemento è un array [x, y, z] normalizzato:
Private spherePoints As Float[][]


Public Sub Form_Open()

 With Me
   .Title = "Sfera che ruota in senso antiorario"
   .Move(0, 0, Screen.AvailableWidth, Screen.AvailableHeight)
   .Arrangement = Arrange.Fill
 End With

Timer1.Delay = 16   ' ~60 FPS
Timer1.Start

' Inizializza l'array dei punti:
 spherePoints = New Float[][NUM_POINTS]

 Dim i As Integer
 Dim theta, phi As Float
 Dim x, y, z As Float

' Generazione casuale dei punti distribuiti sulla superficie della sfera:
 For i = 0 To NUM_POINTS - 1
   theta = Rnd(0, 2 * Pi)      ' Angolo longitudinale (orizzontale)
   phi = Acos(Rnd(-1, 1))      ' Angolo latitudinale (verticale)

' Conversione da coordinate sferiche a coordinate cartesiane:
   x = Sin(phi) * Cos(theta)
   y = Cos(phi)
   z = Sin(phi) * Sin(theta)

' Salvataggio del punto normalizzato nell'array:
   spherePoints[i] = [x, y, z]
 Next

End


Public Sub Timer1_Timer()

' Rotazione sull'asse Y:
 angle += 0.02

 DrawingArea1.Refresh

End


Public Sub DrawingArea1_Draw()

' Coordinate del centro della sfera nella DrawingArea:
 Dim cx As Float = DrawingArea1.Width / 2
 Dim cy As Float = DrawingArea1.Height / 2
 Dim r As Float = Zoom_Raggio_Sfera

' Variabili per il ciclo:
 Dim i As Integer
 Dim p As Float[]
 Dim x, y, z As Float
 Dim xRot, zRot As Float
 Dim sx, sy As Float

' === Disegno del disco blu di base ===
 Paint.Brush = Paint.Color(Color.RGB(0, 80, 160))
 Paint.Ellipse(cx - r, cy - r, r * 2, r * 2)        ' Cerchio centrato
 Paint.Fill()

' === Disegno dei punti bianchi "ruotati" ===
 For i = 0 To NUM_POINTS - 1

' Estrae il punto dalla lista:
   p = spherePoints[i]
   x = p[0]
   y = p[1]
   z = p[2]

' Rotazione attorno all’asse Y.
' Simula la rotazione della sfera da sinistra a destra:
   xRot = x * Cos(angle) + z * Sin(angle)
   zRot = -x * Sin(angle) + z * Cos(angle)

' Mostra solo i punti "davanti" alla sfera (zRot > 0):
   If zRot > 0 Then

' Proiezione del punto 3D sulla 2D DrawingArea:
     sx = cx + xRot * r
     sy = cy + y * r

' Disegna un piccolo punto bianco (2x2 pixel):
     Paint.Brush = Paint.Color(Color.White)
     Paint.Ellipse(sx - 1, sy - 1, 2, 2)
     Paint.Fill()

   Endif

 Next

' === Disegna il bordo della sfera ===
 Paint.Brush = Paint.Color(&H000000)  ' Nero
 Paint.Ellipse(cx - r, cy - r, r * 2, r * 2)
 Paint.Stroke()

 Paint.End

End
 
Public Sub Form_KeyPress()   ' Gestione della tastiera per controllare lo zoom

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

 DrawingArea1.Refresh

End


Caricare una mappa terrestre equirettangolare

Di seguito mostreremo un codice per adattare sulla sfera una mappa terrestre equirettangolare, al fine di far apparire la sfera come il pianeta terra in rotazione.

' === Costanti e variabili globali ===
Private zoom_raggio_sfera As Integer = 100    ' Raggio della sfera da disegnare
Private angle As Float                        ' Angolo di rotazione attorno all’asse Y
Private map As Image                          ' Mappa terrestre in proiezione equirettangolare


Public Sub Form_Open()

 With Me
   .Title = "Sfera rotante con mappa terrestre in proiezione equirettangolare"
   .Move(0, 0, Screen.AvailableWidth, Screen.AvailableHeight)
   .Arrangement = Arrange.Fill
 End With

' Carica la mappa terrestre (proiezione equirettangolare):
 map = Image.Load("/percorso/del/file/immagine/proiezione-equirettangolare")

' Avvia il timer con ~60 fotogrammi al secondo:
 Timer1.Delay = 16
 Timer1.Start

End


Public Sub Timer1_Timer()

' Incrementa l’angolo di rotazione (in radianti):
 angle += 0.05

' Mantiene l’angolo entro 0–2π:
 If angle > 2 * Pi Then angle = 0

' Richiede il ridisegno della DrawingArea:
 DrawingArea1.Refresh

End


Public Sub DrawingArea1_Draw()

' Centro della sfera nella finestra:
 Dim cx As Float = DrawingArea1.Width / 2
 Dim cy As Float = DrawingArea1.Height / 2
 Dim r As Float = zoom_raggio_sfera

' Dimensioni dell’immagine mappa:
 Dim imgW As Integer = map.Width
 Dim imgH As Integer = map.Height

' Variabili per lat/lon, rotazione e proiezione:
 Dim u, v As Float         ' Coordinate normalizzate [0,1] su X e Y dell’immagine
 Dim lon, lat As Float     ' Coordinate geografiche in radianti
 Dim x, y, z As Float      ' Coordinate 3D
 Dim xRot, zRot As Float   ' Coordinate dopo rotazione sull’asse Y
 Dim sx, sy As Float       ' Coordinate proiettate 2D
 Dim i, j As Integer
 Dim cosA, sinA As Float
 Dim mapColor As Integer

' Calcola seno e coseno dell’angolo per ottimizzazione:
 cosA = Cos(angle)
 sinA = Sin(angle)

' Disegna sfondo blu (la sfera base):
 Paint.Brush = Paint.Color(Color.RGB(0, 80, 160))
 Paint.Ellipse(cx - r, cy - r, r * 2, r * 2)
 Paint.Fill()

' === Ciclo per proiettare l’immagine mappa sulla sfera ===
 For j = 0 To imgH Step 2
   v = j / imgH                    ' Valore normalizzato verticale (0 = nord, 1 = sud)
   lat = v * Pi                    ' Latitudine da 0 (nord) a Pi (sud)
   y = Cos(lat)                    ' Coordinate verticali (asse Y cartesiano)

   For i = 0 To imgW Step 2
     u = i / imgW                  ' Valore normalizzato orizzontale (0 = ovest, 1 = est)
     lon = Pi - u * 2 * Pi         ' Longitudine da -Pi (est) a +Pi (ovest)

' Conversione sferica → cartesiana (raggio = 1)
     x = Sin(lat) * Cos(lon)
     z = Sin(lat) * Sin(lon)

' Rotazione attorno all’asse Y (trasformazione 3D)
     xRot = x * cosA + z * sinA
     zRot = -x * sinA + z * cosA

' Disegna solo i punti "visibili", cioè con zRot > 0:
     If zRot > 0 Then
' Proiezione 2D sul piano dello schermo:
       sx = cx + xRot * r
       sy = cy - y * r              ' Invertito perché Y su schermo cresce verso il basso

' Campiona il colore dalla mappa:
       mapColor = map[i, j]

' Disegna un punto colorato (pixel 1x1):
       Paint.Brush = Paint.Color(mapColor)
       Paint.Ellipse(sx, sy, 1, 1)
       Paint.Fill()
     Endif

   Next
 Next

' Disegna bordo nero della sfera:
 Paint.Brush = Paint.Color(&H000000)
 Paint.Ellipse(cx - r, cy - r, r * 2, r * 2)
 Paint.Stroke()

 Paint.End

End


Public Sub Form_KeyPress()   ' Gestione della tastiera per controllare lo zoom

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

DrawingArea1.Refresh

End