Ruotare un quadrato ed un rettangolo in una DrawingArea
Rotazione in 2D
Mostriamo due analoghi possibili codici [nota 1] per far ruotare su se stessi, ossia intorno al proprio asse centrale, un Quadrato ed un Rettangolo disegnati su una DrawingArea. [nota 2]
In entrambi gli esempi la rotazione del Quadrato e del Rettangolo viene effettuata premendo i tasti freccia in su e freccia in giù della tastiera oppure ruotando la rotellina del mouse.
Ruotare un Quadrato sul proprio asse centrale
Per ottenere la rotazione sul proprio asse centrale di un quadrato disegnato in una DrawingArea è possibile adottare il seguente codice:
' Il fulcro del Metodo ".Translate()" agisce da vortice, da centro di rotazione intorno a una ipotetica circonferenza
Private da As DrawingArea
Private Const LATO As Short = 200 ' Memorizza il lato del quadrato.
Private fAngolo As Float ' Memorizza i gradi dell'angolo.
Private c As Integer[] = [Color.Blue, Color.Green, Color.Yellow, Color.Red]
Private f As Float[] = [0, 0.34, 0.67, 1]
Public Sub Form_Open()
With Me
.W = LATO * 3
.H = .W * 0.6
.Center
.Arrangement = Arrange.Fill
End With
With da = New DrawingArea(Me) As "DrawingArea1"
.Background = Color.White
End With
End
Public Sub DrawingArea1_Draw()
With Paint
.Brush = .LinearGradient(0, 20, 15, 0, c, f)
' Imposta il fulcro/punto della rotazione - ad esempio - al centro dell'area di disegno:
.Translate(da.W / 2, da.H / 2)
.Rotate(Rad(fAngolo))
.LineWidth = 2.0
' Disegna il quadrato.
' Siccome l'angolo ruota su se stesso, si dà alle coordinate del quadrato la metà della dimensione del suo lato.
' Non si devono modificare i valori né i segni dei quattro argomenti qui riportati.
.Rectangle(LATO / 2, LATO / 2, -LATO, -LATO)
' oppure così:
' .Rectangle(-LATO / 2, -LATO / 2, LATO, LATO)
.Stroke
.End
End With
End
Public Sub Form_KeyPress()
Select Case Key.Code
Case Key.Up
fAngolo += 1
If fAngolo = 361 Then fAngolo = 1
Case Key.Down
fAngolo -= 1
If fAngolo = -361 Then fAngolo = -1
End Select
da.Refresh
End
Public Sub Form_MouseWheel()
fAngolo += Mouse.Delta
Select Case fAngolo
Case 361
fAngolo = 1
Case -361
fAngolo = -1
End Select
da.Refresh
End
Public Sub Form_Resize() ' Con questo evento se cambia la dimensione del Form, il disegno non va perso.
da.Refresh
End
Ruotare un Rettangolo sul proprio asse centrale
Per ottenere la rotazione sul proprio asse centrale di un Rettangolo disegnato in una DrawingArea è possibile adottare il seguente codice identico al precedente:
' Il fulcro del Metodo ".Translate()" agisce da vortice, da centro di rotazione intorno a una ipotetica circonferenza
Private da As DrawingArea
Private Const ORIZZONTALE As Short = 200 ' Memorizza la dimensione di ciascun lato orizzontale.
Private Const VERTICALE As Short = 100 ' Memorizza la dimensione di ciascun lato verticale.
Private fAngolo As Float ' Memorizza i gradi dell'angolo.
Private c As Integer[] = [Color.Blue, Color.Green, Color.Yellow, Color.Red]
Private f As Float[] = [0, 0.34, 0.67, 1]
Public Sub Form_Open()
With Me
.W = Max(ORIZZONTALE, VERTICALE) * 4
.H = .W / 2
.Center
.Arrangement = Arrange.Fill
End With
With da = New DrawingArea(Me) As "DrawingArea1"
.Background = Color.White
End With
End
Public Sub DrawingArea1_Draw()
With Paint
.Brush = .LinearGradient(0, 20, 15, 0, c, f)
' Imposta il fulcro/punto della rotazione - ad esempio -al centro dell'area di disegno:
.Translate(da.W / 2, da.H / 2)
.Rotate(Rad(fAngolo))
.LineWidth = 2.0
' Disegna il rettangolo.
' Siccome l'angolo ruota su se stesso, si dà alle coordinate del rettangolo la metà della dimensione di ciascun suo lato:
' Non si devono modificare i valori né i segni dei quattro argomenti qui riportati.
.Rectangle(ORIZZONTALE / 2, VERTICALE / 2, -ORIZZONTALE, -VERTICALE)
' oppure così:
' .Rectangle(-ORIZZONTALE / 2, -VERTICALE / 2, ORIZZONTALE, VERTICALE)
.Stroke
.End
End With
End
Public Sub Form_KeyPress()
Select Case Key.Code
Case Key.Up
fAngolo += 1
If fAngolo = 361 Then fAngolo = 1
Case Key.Down
fAngolo -= 1
If fAngolo = -361 Then fAngolo = -1
End Select
da.Refresh
End
Public Sub Form_MouseWheel()
fAngolo += Mouse.Delta
Select Case fAngolo
Case 361
fAngolo = 1
Case -361
fAngolo = -1
End Select
da.Refresh
End
Public Sub Form_Resize() ' Con questo evento se cambia la dimensione del Form, il disegno non va perso.
da.Refresh
End
Rotazione in 3D
Rotazione di un quadrato intorno al suo asse Y
Private angleY As Float ' Angolo di rotazione attorno all’asse Y 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 End Public Sub Timer1_Timer() angleY += 2 ' Incrementa l’angolo ogni frame DrawingArea1.Refresh ' Richiede il ridisegno End Public Sub DrawingArea1_Draw() ' Centra il disegno del quadrato nella "DrawingArea": Dim cx As Float = DrawingArea1.Width / 2 Dim cy As Float = DrawingArea1.Height / 2 Dim size As Float = 1.0 ' Metà lato del quadrato Dim d As Float = 5.0 ' Distanza "camera" (l'osservatore) Dim ay As Float = Rad(angleY) ' Angolo in radianti ' === Vertici 3D del quadrato === ' Ordinati in senso orario: Dim square As New Float[][4] square[0] = [-size, size, 0.0] ' In alto a sinistra square[1] = [ size, size, 0.0] ' In alto a destra square[2] = [ size, -size, 0.0] ' In basso a destra square[3] = [-size, -size, 0.0] ' In basso a sinistra ' === Ruota e proietta i 4 vertici === Dim coords As Float[] = [] For i As Integer = 0 To 3 Dim p As Float[] = RotateY(square[i], ay) Dim pt As PointF = Project3D(p, d, cx, cy) coords.Add(pt.X) coords.Add(pt.Y) Next ' === Disegna il quadrato ruotato === Paint.Brush = Paint.Color(Color.RGB(100, 200, 255)) Paint.Polygon(coords) Paint.Fill() ' Bordo del quadrato: Paint.LineWidth = 1 Paint.Brush = Paint.Color(Color.Black) Paint.Polygon(coords) Paint.Stroke() End ' === Rotazione attorno all'asse Y === Private Function RotateY(v As Float[], angle As Float) As Float[] Dim x As Float = v[0] Dim y As Float = v[1] Dim z As Float = v[2] ' Rotazione nel piano XZ: Dim xr As Float = x * Cos(angle) + z * Sin(angle) Dim zr As Float = -x * Sin(angle) + z * Cos(angle) Return [xr, y, zr] End ' === Proiezione 3D → 2D con prospettiva === Private Function Project3D(v As Float[], d As Float, cx As Float, cy As Float) As PointF Dim x As Float = v[0] Dim y As Float = v[1] Dim z As Float = v[2] ' Scala in base alla profondità: Dim factor As Float = d / (z + d + 0.001) Dim x2D As Float = x * factor Dim y2D As Float = y * factor Return New PointF(cx + x2D * 100, cy - y2D * 100) End
Note
[1] I codici, presenti in questa pagina, sono tratti - con modifiche ed integrazioni - da suggerimenti del membro Gianluigi del forum di gambas-it.org e del membro Shell del forum www.gambas-es.org .
[2] Vedere anche queste pagine: