Ruotare una sfera in una DrawingArea: differenze tra le versioni

Da Gambas-it.org - Wikipedia.
Vai alla navigazione Vai alla ricerca
(Creata pagina con "Di seguito mostreremo un possibile codice per ottenere l'effetto di una sfera che ruota in senso antiorario. <FONT Color=gray>' ''Costanti per raggio della sfera e numero di...")
 
Nessun oggetto della modifica
Riga 98: Riga 98:
  <FONT Color=gray>' ''=== Disegna il bordo della sfera ===''</font>
  <FONT Color=gray>' ''=== Disegna il bordo della sfera ===''</font>
   Paint.Brush = Paint.Color(&H000000)  ' Nero
   Paint.Brush = Paint.Color(&H000000)  ' Nero
  Paint.Ellipse(cx - r, cy - r, r * 2, r * 2)
  Paint.Stroke()
  Paint.End
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.
<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>
Private Const 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 map As Image                          <FONT Color=gray>' ''Mappa terrestre in proiezione equirettangolare''</font>
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
<FONT Color=gray>' ''Carica la mappa terrestre (proiezione equirettangolare):''</font>
  map = Image.Load("<FONT Color=darkgreen>''/tmp/Equirectangular-projection.PNG''</font>")
<FONT Color=gray>' ''Avvia il timer con ~60 fotogrammi al secondo:''</font>
  Timer1.Delay = 16
  Timer1.Start
End
Public Sub Timer1_Timer()
<FONT Color=gray>' ''Incrementa l’angolo di rotazione (in radianti):''</font>
  angle += 0.05
<FONT Color=gray>' ''Mantiene l’angolo entro 0–2π:''</font>
  If angle > 2 * Pi Then angle = 0
<FONT Color=gray>' ''Richiede il ridisegno della DrawingArea:''</font>
  DrawingArea1.Refresh
End
Public Sub DrawingArea1_Draw()
<FONT Color=gray>' ''Centro della sfera nella finestra:''</font>
  Dim cx As Float = DrawingArea1.Width / 2
  Dim cy As Float = DrawingArea1.Height / 2
  Dim r As Float = RAGGIO_SFERA
<FONT Color=gray>' ''Dimensioni dell’immagine mappa:''</font>
  Dim imgW As Integer = map.Width
  Dim imgH As Integer = map.Height
<FONT Color=gray>' ''Variabili per lat/lon, rotazione e proiezione:''</font>
  Dim u, v As Float        <FONT Color=gray>' ''Coordinate normalizzate [0,1] su X e Y dell’immagine''</font>
  Dim lon, lat As Float    <FONT Color=gray>' ''Coordinate geografiche in radianti''</font>
  Dim x, y, z As Float      <FONT Color=gray>' ''Coordinate 3D''</font>
  Dim xRot, zRot As Float  <FONT Color=gray>' ''Coordinate dopo rotazione sull’asse Y''</font>
  Dim sx, sy As Float      <FONT Color=gray>' ''Coordinate proiettate 2D''</font>
  Dim i, j As Integer
  Dim cosA, sinA As Float
  Dim mapColor As Integer
<FONT Color=gray>' ''Calcola seno e coseno dell’angolo per ottimizzazione:''</font>
  cosA = Cos(angle)
  sinA = Sin(angle)
<FONT Color=gray>' ''Disegna sfondo blu (la sfera base):''</font>
  Paint.Brush = Paint.Color(Color.RGB(0, 80, 160))
  Paint.Ellipse(cx - r, cy - r, r * 2, r * 2)
  Paint.Fill()
<FONT Color=gray>' ''=== Ciclo per proiettare l’immagine mappa sulla sfera ===''</font>
  For j = 0 To imgH Step 2
    v = j / imgH                    <FONT Color=gray>' ''Valore normalizzato verticale (0 = nord, 1 = sud)''</font>
    lat = v * Pi                    <FONT Color=gray>' ''Latitudine da 0 (nord) a Pi (sud)''</font>
    y = Cos(lat)                    <FONT Color=gray>' ''Coordinate verticali (asse Y cartesiano)''</font>
    For i = 0 To imgW Step 2
      u = i / imgW                  <FONT Color=gray>' ''Valore normalizzato orizzontale (0 = ovest, 1 = est)''</font>
      lon = Pi - u * 2 * Pi        <FONT Color=gray>' ''Longitudine da -Pi (est) a +Pi (ovest)''</font>
<FONT Color=gray>' ''Conversione sferica → cartesiana (raggio = 1)''</font>
      x = Sin(lat) * Cos(lon)
      z = Sin(lat) * Sin(lon)
<FONT Color=gray>' ''Rotazione attorno all’asse Y (trasformazione 3D)''</font>
      xRot = x * cosA + z * sinA
      zRot = -x * sinA + z * cosA
<FONT Color=gray>' ''Disegna solo i punti "visibili", cioè con zRot > 0:''</font>
      If zRot > 0 Then
<FONT Color=gray>' ''Proiezione 2D sul piano dello schermo:''</font>
        sx = cx + xRot * r
        sy = cy - y * r              <FONT Color=gray>' ''Invertito perché Y su schermo cresce verso il basso''</font>
<FONT Color=gray>' ''Campiona il colore dalla mappa:''</font>
        mapColor = map[i, j]
<FONT Color=gray>' ''Disegna un punto colorato (pixel 1x1):''</font>
        Paint.Brush = Paint.Color(mapColor)
        Paint.Ellipse(sx, sy, 1, 1)
        Paint.Fill()
      Endif
    Next
  Next
<FONT Color=gray>' ''Disegna bordo nero della sfera:''</font>
  Paint.Brush = Paint.Color(&H000000)
   Paint.Ellipse(cx - r, cy - r, r * 2, r * 2)
   Paint.Ellipse(cx - r, cy - r, r * 2, r * 2)
   Paint.Stroke()
   Paint.Stroke()

Versione delle 07:25, 20 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 SPHERE_RADIUS As Integer = 100
Private Const NUM_POINTS As Integer = 200

' 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 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 = SPHERE_RADIUS

' 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


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.
Il file immagine contenente i dati della mappa equirettangolare deve essere del formato PNG.
Supporremo che il file immagine della mappa sia posto nella cartella "/tmp".

' === Costanti e variabili globali ===
Private Const 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("/tmp/Equirectangular-projection.PNG")

' 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 = 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