Ruotare un triangolo in una DrawingArea: differenze tra le versioni
Nessun oggetto della modifica |
Nessun oggetto della modifica |
||
| (13 versioni intermedie di uno stesso utente non sono mostrate) | |||
| Riga 1: | Riga 1: | ||
Mostriamo due possibili codice per far ruotare su se stesso un Triangolo disegnato su una ''DrawingArea''. <SUP>[[[#Note|Nota 1]]]</sup> | Mostriamo due possibili codice per far ruotare su se stesso un Triangolo disegnato su una ''DrawingArea''. <SUP>[[[#Note|Nota 1]]]</sup> | ||
=Rotazione in 2D= | |||
==Ruotare un Triangolo intorno al suo Baricentro== | ==Ruotare un Triangolo intorno al suo Baricentro== | ||
Di seguito mostreremo un possibile codice per ruotare un Triangolo intorno al suo <SPAN Style="text-decoration:underline">''[https://it.wikipedia.org/wiki/Baricentro_(geometria) Baricentro]''</span>. | Di seguito mostreremo un possibile codice per ruotare un Triangolo intorno al suo <SPAN Style="text-decoration:underline">''[https://it.wikipedia.org/wiki/Baricentro_(geometria) Baricentro]''</span>. | ||
<BR>Il fulcro del Metodo ".Translate()" agisce da vortice, ossia da centro di rotazione intorno a una ipotetica circonferenza. | |||
<BR>La rotazione del triangolo viene effettuata premendo i tasti freccia in su e freccia in giù della tastiera oppure ruotando la rotellina del mouse. | <BR>La rotazione del triangolo viene effettuata premendo i tasti freccia in su e freccia in giù della tastiera oppure ruotando la rotellina del mouse. | ||
Private DrawingArea1 As DrawingArea | Private DrawingArea1 As DrawingArea | ||
<FONT Color=gray>' ''Imposta le coordinate dei tre vertici del triangolo, con il primo vertice nel punto di rotazione (0, 0):''</font> | <FONT Color=gray>' ''Imposta le coordinate dei tre vertici del triangolo, con il primo vertice nel punto di rotazione (0, 0):''</font> | ||
| Riga 13: | Riga 15: | ||
<FONT Color=gray>' ''Memorizza i gradi dell'angolo:''</font> | <FONT Color=gray>' ''Memorizza i gradi dell'angolo:''</font> | ||
Private ang As Float | Private ang As Float | ||
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 = Screen.AvailableWidth | |||
.H = Screen.AvailableHeight | |||
.Arrangement = Arrange.Fill | |||
End With | |||
With DrawingArea1 = New DrawingArea(Me) As "DrawingArea1" | |||
.Background = Color.White | |||
End With | |||
End | |||
Public Sub DrawingArea1_Draw() | |||
With Paint | With Paint | ||
| Riga 41: | Riga 43: | ||
.LineWidth = 2.0 | .LineWidth = 2.0 | ||
<FONT Color=gray>' ''Disegna il Triangolo.'' | <FONT Color=gray>' ''Disegna il Triangolo.'' | ||
' '' | ' ''Giacché l'angolo ruota su se stesso, avendo come centro di rotazione il proprio "Baricentro", ad ogni coordinata del punto, che costituisce un elemento del vettore del Metodo ".Polygon()", si sottrae il valore della corrispondente coordinata del punto del Baricentro. In questo modo si farà coincidere l'angolo di rotazione con il "Baricentro" del Triangolo.'' | ||
' ''Non si devono modificare i valori né i segni dei quattro argomenti qui riportati.''</font> | ' ''Non si devono modificare i valori né i segni dei quattro argomenti qui riportati.''</font> | ||
.Polygon([ABC[0] - xb, ABC[1] - yb, ABC[2] - xb, ABC[3] - yb, ABC[4] - xb, ABC[5] - yb]) | .Polygon([ABC[0] - xb, ABC[1] - yb, ABC[2] - xb, ABC[3] - yb, ABC[4] - xb, ABC[5] - yb]) | ||
.Stroke | .Stroke | ||
End With | End With | ||
End | |||
Public Sub Form_KeyPress() | |||
Select Case Key.Code | Select Case Key.Code | ||
| Riga 63: | Riga 65: | ||
DrawingArea1.Refresh | DrawingArea1.Refresh | ||
End | |||
Public Sub Form_MouseWheel() | |||
ang += Mouse.Delta | ang += Mouse.Delta | ||
| Riga 77: | Riga 80: | ||
DrawingArea1.Refresh | DrawingArea1.Refresh | ||
End | |||
Public Sub Form_Resize() <FONT Color=gray>' ''Con questo evento se cambia la dimensione del Form, il disegno non va perso.''</font> | |||
DrawingArea1.Refresh | DrawingArea1.Refresh | ||
'''End''' | End | ||
oppure anche questo codice: | |||
Private DrawingArea1 As DrawingArea | |||
Private Timer1 As Timer | |||
Private rotationAngle As Float | |||
Public Sub Form_Open() | |||
With Me | |||
.Move(0, 0, Screen.AvailableWidth, Screen.AvailableHeight) | |||
.Arrangement = Arrange.Fill | |||
End With | |||
With DrawingArea1 = New DrawingArea(Me) As "DrawingArea1" | |||
.Background = Color.Lighter(Color.White) | |||
End With | |||
Timer1 = New Timer As "Timer1" | |||
Timer1.Delay = 30 | |||
Timer1.Start() | |||
End | |||
Public Sub Timer1_Timer() | |||
rotationAngle += Rad(2) <FONT Color=gray>' ''ruota di 2 gradi ogni frame''</font> | |||
If rotationAngle >= 2 * Pi Then | |||
rotationAngle -= 2 * Pi | |||
End If | |||
DrawingArea1.Refresh() | |||
End | |||
Public Sub DrawingArea1_Draw() | |||
Dim cx As Float = DrawingArea1.W / 2 | |||
Dim cy As Float = DrawingArea1.H / 2 | |||
Dim size As Float = Min(DrawingArea1.W, DrawingArea1.H) * 0.4 | |||
<FONT Color=gray>' ''Definisci i vertici del triangolo (posizionati attorno a (0,0)):''</font> | |||
Dim points As New PointF[3] | |||
points[0] = New PointF(0, -size / 2) <FONT Color=gray>' ''vertice superiore''</font> | |||
points[1] = New PointF(-size / 2, size / 2) <FONT Color=gray>' ''vertice basso sinistro''</font> | |||
points[2] = New PointF(size / 2, size / 2) <FONT Color=gray>' ''vertice basso destro''</font> | |||
<FONT Color=gray>' ''Calcola baricentro (centroide):''</font> | |||
Dim centroidX As Float = 0 | |||
Dim centroidY As Float = 0 | |||
For i As Integer = 0 To 2 | |||
centroidX += points[i].X | |||
centroidY += points[i].Y | |||
Next | |||
centroidX /= 3 | |||
centroidY /= 3 | |||
<FONT Color=gray>' ''Ruota i punti attorno al baricentro e trasla al centro DrawingArea:''</font> | |||
For i As Integer = 0 To 2 | |||
Dim xOld As Float = points[i].X - centroidX | |||
Dim yOld As Float = points[i].Y - centroidY | |||
points[i].X = xOld * Cos(rotationAngle) - yOld * Sin(rotationAngle) + centroidX + cx | |||
points[i].Y = xOld * Sin(rotationAngle) + yOld * Cos(rotationAngle) + centroidY + cy | |||
Next | |||
With Paint | |||
.Brush = Paint.Color(Color.Black) | |||
.LineWidth = 2 | |||
.MoveTo(points[0].X, points[0].Y) | |||
For i As Integer = 1 To 2 | |||
.LineTo(points[i].X, points[i].Y) | |||
Next | |||
.LineTo(points[0].X, points[0].Y) | |||
.Stroke | |||
<FONT Color=gray>' ''Punto nero sul baricentro (traslato):''</font> | |||
.Arc(cx + centroidX, cy + centroidY, 5, Rad(0), Rad(360), False) | |||
.Fill | |||
End With | |||
End | |||
Il seguente codice disegna e ruota un Triangolo scaleno intorno al suo Baricentro: | |||
Private DrawingArea1 As DrawingArea | |||
Private Timer1 As Timer | |||
Private rotationAngle As Float | |||
Public Sub Form_Open() | |||
With Me | |||
.Move(0, 0, Screen.AvailableWidth, Screen.AvailableHeight) | |||
.Arrangement = Arrange.Fill | |||
End With | |||
With DrawingArea1 = New DrawingArea(Me) As "DrawingArea1" | |||
.Background = Color.Lighter(Color.White) | |||
End With | |||
Timer1 = New Timer As "Timer1" | |||
Timer1.Delay = 30 | |||
Timer1.Start() | |||
End | |||
Public Sub Timer1_Timer() | |||
rotationAngle += Rad(2) | |||
If rotationAngle >= 2 * Pi Then | |||
rotationAngle -= 2 * Pi | |||
End If | |||
DrawingArea1.Refresh() | |||
End | |||
Public Sub DrawingArea1_Draw() | |||
Dim cx As Float = DrawingArea1.W / 2 | |||
Dim cy As Float = DrawingArea1.H / 2 | |||
<FONT Color=gray>' ''Vertici di un triangolo scaleno (modificabili):''</font> | |||
Dim points As New PointF[3] | |||
points[0] = New PointF(-160, -80) <FONT Color=gray>' 'Vertice A''</font> | |||
points[1] = New PointF(210, 50) <FONT Color=gray>' 'Vertice B''</font> | |||
points[2] = New PointF(50, 190) <FONT Color=gray>' 'Vertice C''</font> | |||
<FONT Color=gray>' ''Calcola il baricentro (media delle coordinate):''</font> | |||
Dim baryX As Float = (points[0].X + points[1].X + points[2].X) / 3 | |||
Dim baryY As Float = (points[0].Y + points[1].Y + points[2].Y) / 3 | |||
<FONT Color=gray>' ''Ruota i punti attorno al baricentro:''</font> | |||
For i As Integer = 0 To 2 | |||
Dim xOld As Float = points[i].X - baryX | |||
Dim yOld As Float = points[i].Y - baryY | |||
points[i].X = xOld * Cos(rotationAngle) - yOld * Sin(rotationAngle) + baryX | |||
points[i].Y = xOld * Sin(rotationAngle) + yOld * Cos(rotationAngle) + baryY | |||
<FONT Color=gray>' ''Trasla il triangolo per centrarlo nella DrawingArea:''</font> | |||
points[i].X += cx | |||
points[i].Y += cy | |||
Next | |||
With Paint | |||
.Brush = Paint.Color(Color.Black) | |||
.LineWidth = 2 | |||
<FONT Color=gray>' ''Disegna il triangolo:''</font> | |||
.MoveTo(points[0].X, points[0].Y) | |||
For i As Integer = 1 To 2 | |||
.LineTo(points[i].X, points[i].Y) | |||
Next | |||
.LineTo(points[0].X, points[0].Y) | |||
.Stroke | |||
<FONT Color=gray>' ''Disegna il punto nero sul baricentro traslato correttamente:''</font> | |||
.Arc(cx + baryX, cy + baryY, 5, Rad(0), Rad(360), False) | |||
.Fill | |||
End With | |||
End | |||
==Ruotare un Triangolo intorno al suo Incentro== | ==Ruotare un Triangolo intorno al suo Incentro== | ||
| Riga 101: | Riga 270: | ||
<FONT Color=gray>' ''Memorizza i gradi dell'angolo:''</font> | <FONT Color=gray>' ''Memorizza i gradi dell'angolo:''</font> | ||
Private ang As Float | Private ang As Float | ||
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 = Screen.AvailableWidth | |||
.H = Screen.AvailableHeight | |||
.Arrangement = Arrange.Fill | |||
End With | |||
With DrawingArea1 = New DrawingArea(Me) As "DrawingArea1" | |||
.Background = Color.White | |||
End With | |||
End | |||
Public Sub DrawingArea1_Draw() | |||
With Paint | With Paint | ||
| Riga 133: | Riga 302: | ||
.Polygon([ABC[0] - ix, ABC[1] - iy, ABC[2] - ix, ABC[3] - iy, ABC[4] - ix, ABC[5] - iy]) | .Polygon([ABC[0] - ix, ABC[1] - iy, ABC[2] - ix, ABC[3] - iy, ABC[4] - ix, ABC[5] - iy]) | ||
.Stroke | .Stroke | ||
End With | End With | ||
End | |||
Public Sub Form_KeyPress() | |||
Select Case Key.Code | Select Case Key.Code | ||
| Riga 151: | Riga 320: | ||
DrawingArea1.Refresh | DrawingArea1.Refresh | ||
End | |||
Public Sub Form_MouseWheel() | |||
ang += Mouse.Delta | ang += Mouse.Delta | ||
| Riga 165: | Riga 335: | ||
DrawingArea1.Refresh | DrawingArea1.Refresh | ||
''' | End | ||
Public Sub Form_Resize() <FONT Color=gray>' ''Con questo evento se cambia la dimensione del Form, il disegno non va perso.''</font> | |||
DrawingArea1.Refresh | |||
End | |||
oppure quest'altro codice: | |||
Private DrawingArea1 As DrawingArea | |||
Private Timer1 As Timer | |||
Private rotationAngle As Float = 0 | |||
Public Sub Form_Open() | |||
With Me | |||
.Move(0, 0, Screen.AvailableWidth, Screen.AvailableHeight) | |||
.Arrangement = Arrange.Fill | |||
End With | |||
With DrawingArea1 = New DrawingArea(Me) As "DrawingArea1" | |||
.Background = Color.Lighter(Color.White) | |||
End With | |||
Timer1 = New Timer As "Timer1" | |||
Timer1.Delay = 30 | |||
Timer1.Start() | |||
End | |||
Public Sub Timer1_Timer() | |||
rotationAngle += Rad(2) | |||
If rotationAngle >= 2 * Pi Then | |||
rotationAngle -= 2 * Pi | |||
End If | |||
DrawingArea1.Refresh() | |||
End | |||
Public Sub DrawingArea1_Draw() | |||
Dim cx As Float = DrawingArea1.W / 2 | |||
Dim cy As Float = DrawingArea1.H / 2 | |||
Dim base As Float = Min(DrawingArea1.W, DrawingArea1.H) * 0.5 | |||
Dim height As Float = base * 0.7 | |||
<FONT Color=gray>' ''Vertici triangolo isoscele (vertice in alto):''</font> | |||
Dim points As New PointF[3] | |||
points[0] = New PointF(0, -height / 2) <FONT Color=gray>' ''vertice superiore A''</font> | |||
points[1] = New PointF(-base / 2, height / 2) <FONT Color=gray>' ''vertice basso sinistro B''</font> | |||
points[2] = New PointF(base / 2, height / 2) <FONT Color=gray>' ''vertice basso destro C''</font> | |||
<FONT Color=gray>' ''Calcola lunghezze lati:''</font> | |||
Dim a As Float = Sqr((points[1].X - points[2].X) ^ 2 + (points[1].Y - points[2].Y) ^ 2) ' BC | |||
Dim b As Float = Sqr((points[0].X - points[2].X) ^ 2 + (points[0].Y - points[2].Y) ^ 2) ' AC | |||
Dim c As Float = Sqr((points[0].X - points[1].X) ^ 2 + (points[0].Y - points[1].Y) ^ 2) ' AB | |||
<FONT Color=gray>' ''Calcola l'Incentro:''</font> | |||
Dim incentroX As Float = (a * points[0].X + b * points[1].X + c * points[2].X) / (a + b + c) | |||
Dim incentroY As Float = (a * points[0].Y + b * points[1].Y + c * points[2].Y) / (a + b + c) | |||
<FONT Color=gray>' ''Ruota attorno all'incentro e trasla nel centro DrawingArea:''</font> | |||
For i As Integer = 0 To 2 | |||
Dim xOld As Float = points[i].X - incentroX | |||
Dim yOld As Float = points[i].Y - incentroY | |||
points[i].X = xOld * Cos(rotationAngle) - yOld * Sin(rotationAngle) + incentroX + cx | |||
points[i].Y = xOld * Sin(rotationAngle) + yOld * Cos(rotationAngle) + incentroY + cy | |||
Next | |||
With Paint | |||
.Brush = Paint.Color(Color.Black) | |||
.LineWidth = 2 | |||
.MoveTo(points[0].X, points[0].Y) | |||
For i As Integer = 1 To 2 | |||
.LineTo(points[i].X, points[i].Y) | |||
Next | |||
.LineTo(points[0].X, points[0].Y) | |||
.Stroke | |||
<FONT Color=gray>' ''Punto nero sul incentro:''</font> | |||
.Arc(cx + incentroX, cy + incentroY, 5, Rad(0), Rad(360), False) | |||
.Fill | |||
End With | |||
End | |||
Il seguente codice disegna e ruota un Triangolo scaleno intorno al suo Incentro: | |||
Private DrawingArea1 As DrawingArea | |||
Private Timer1 As Timer | |||
Private rotationAngle As Float | |||
Public Sub Form_Open() | |||
With Me | |||
.Move(0, 0, Screen.AvailableWidth, Screen.AvailableHeight) | |||
.Arrangement = Arrange.Fill | |||
End With | |||
With DrawingArea1 = New DrawingArea(Me) As "DrawingArea1" | |||
.Background = Color.Lighter(Color.White) | |||
End With | |||
Timer1 = New Timer As "Timer1" | |||
Timer1.Delay = 30 | |||
Timer1.Start() | |||
End | |||
Public Sub Timer1_Timer() | |||
rotationAngle += Rad(2) | |||
If rotationAngle >= 2 * Pi Then | |||
rotationAngle -= 2 * Pi | |||
End If | |||
DrawingArea1.Refresh() | |||
End | |||
Public Sub DrawingArea1_Draw() | |||
Dim cx As Float = DrawingArea1.W / 2 | |||
Dim cy As Float = DrawingArea1.H / 2 | |||
<FONT Color=gray>' ''Vertici di un triangolo scaleno senza angoli retti:''</font> | |||
Dim points As New PointF[3] | |||
points[0] = New PointF(-160, -80) <FONT Color=gray>' ''Vertice A''</font> | |||
points[1] = New PointF(210, 50) <FONT Color=gray>' ''Vertice B''</font> | |||
points[2] = New PointF(50, 190) <FONT Color=gray>' ''Vertice C''</font> | |||
<FONT Color=gray>' ''Calcola le lunghezze dei lati:''</font> | |||
Dim a As Float = Sqr((points[1].X - points[2].X) ^ 2 + (points[1].Y - points[2].Y) ^ 2) ' BC | |||
Dim b As Float = Sqr((points[0].X - points[2].X) ^ 2 + (points[0].Y - points[2].Y) ^ 2) ' AC | |||
Dim c As Float = Sqr((points[0].X - points[1].X) ^ 2 + (points[0].Y - points[1].Y) ^ 2) ' AB | |||
<FONT Color=gray>' ''Calcola l'incentro:''</font> | |||
Dim incentroX As Float = (a * points[0].X + b * points[1].X + c * points[2].X) / (a + b + c) | |||
Dim incentroY As Float = (a * points[0].Y + b * points[1].Y + c * points[2].Y) / (a + b + c) | |||
<FONT Color=gray>' ''Ruota i punti attorno all'incentro e trasla nel centro della DrawingArea:''</font> | |||
For i As Integer = 0 To 2 | |||
Dim xOld As Float = points[i].X - incentroX | |||
Dim yOld As Float = points[i].Y - incentroY | |||
points[i].X = xOld * Cos(rotationAngle) - yOld * Sin(rotationAngle) + incentroX + cx | |||
points[i].Y = xOld * Sin(rotationAngle) + yOld * Cos(rotationAngle) + incentroY + cy | |||
Next | |||
With Paint | |||
.Brush = Paint.Color(Color.Black) | |||
.LineWidth = 2 | |||
<FONT Color=gray>' ''Disegna il triangolo:''</font> | |||
.MoveTo(points[0].X, points[0].Y) | |||
For i As Integer = 1 To 2 | |||
.LineTo(points[i].X, points[i].Y) | |||
Next | |||
.LineTo(points[0].X, points[0].Y) | |||
.Stroke | |||
<FONT Color=gray>' ''Disegna il punto nero sull'incentro:''</font> | |||
.Arc(cx + incentroX, cy + incentroY, 5, Rad(0), Rad(360), False) | |||
.Fill | |||
End With | |||
End | |||
=Rotazione in 3D= | |||
==Rotazione 3D attorno all'asse Y== | |||
Nel seguente codice faremo ruotare un triangolo isoscele attorno all'asse Y (cioè in spazio 3D): | |||
Private DrawingArea1 As DrawingArea | |||
Private Timer1 As Timer | |||
Private angle As Float <FONT Color=gray>' ''Variabile globale per memorizzare l'angolo corrente della rotazione''</font> | |||
Public Sub Form_Open() | |||
With Me | |||
.Title = "Rotazione di un Triangolo isoscele attorno all'asse Y" | |||
.Move(0, 0, Screen.AvailableWidth, Screen.AvailableHeight) | |||
.Arrangement = Arrange.Fill | |||
End With | |||
With DrawingArea1 = New DrawingArea(Me) As "DrawingArea1" | |||
.Background = Color.White | |||
End With | |||
Timer1 = New Timer As "Timer1" | |||
Timer1.Delay = 16 | |||
Timer1.Start() | |||
End | |||
Public Sub Timer1_Timer() | |||
<FONT Color=gray>' ''Aumenta l’angolo di rotazione:''</font> | |||
angle += 2 | |||
If angle >= 360 Then angle = 0 | |||
<FONT Color=gray>' ''Richiede il ridisegno della DrawingArea:''</font> | |||
DrawingArea1.Refresh | DrawingArea1.Refresh | ||
'''End''' | End | ||
Public Sub DrawingArea1_Draw() | |||
<FONT Color=gray>' ''Calcola il centro della DrawingArea:''</font> | |||
Dim cx As Float = DrawingArea1.Width / 2 | |||
Dim cy As Float = DrawingArea1.Height / 2 | |||
<FONT Color=gray>' ''Parametri del triangolo:''</font> | |||
Dim baseHalf As Float = 1.0 <FONT Color=gray>' ''Metà base''</font> | |||
Dim height As Float = 1.5 <FONT Color=gray>' ''Altezza del triangolo''</font> | |||
Dim d As Float = 4.0 <FONT Color=gray>' ''Distanza simulata dalla "camera", ossia dall'osservatore''</font> | |||
<FONT Color=gray>' ''Angolo in radianti:''</font> | |||
Dim radAngle As Float = Rad(angle) | |||
<FONT Color=gray>' ''Definizione dei 3 vertici del triangolo in coordinate 3D (x, y, z):''</font> | |||
Dim v1 As Float[] = [0.0, height / 2, 0.0] <FONT Color=gray>' ''Vertice superiore''</font> | |||
Dim v2 As Float[] = [-baseHalf, -height / 2, 0.0] <FONT Color=gray>' ''Vertice sinistro della base''</font> | |||
Dim v3 As Float[] = [baseHalf, -height / 2, 0.0] <FONT Color=gray>' ''Vertice destro della base''</font> | |||
<FONT Color=gray>' ''Applica la rotazione 3D attorno all’asse Y, quindi proietta in 2D:''</font> | |||
Dim p1 As PointF = Project3D(RotateY(v1, radAngle), d, cx, cy) | |||
Dim p2 As PointF = Project3D(RotateY(v2, radAngle), d, cx, cy) | |||
Dim p3 As PointF = Project3D(RotateY(v3, radAngle), d, cx, cy) | |||
<FONT Color=gray>' ''Costruisce un array di coordinate [x0, y0, x1, y1, x2, y2]:''</font> | |||
Dim coords As Float[] = [p1.X, p1.Y, p2.X, p2.Y, p3.X, p3.Y] | |||
<FONT Color=gray>' ''Disegna e riempie il triangolo:''</font> | |||
Paint.Brush = Paint.Color(Color.Red) <FONT Color=gray>' ''Imposta il colore rosso''</font> | |||
Paint.Polygon(coords) <FONT Color=gray>' ''Definisce la forma''</font> | |||
Paint.Fill() <FONT Color=gray>' ''Riempe il triangolo''</font> | |||
End | |||
Private Function RotateY(v As Float[], angle As Float) As Float[] <FONT Color=gray>' ''Funzione che ruota un punto 3D attorno all’asse Y''</font> | |||
Dim x As Float = v[0] | |||
Dim y As Float = v[1] | |||
Dim z As Float = v[2] | |||
<FONT Color=gray>' ''Formula di rotazione attorno all'asse Y:''</font> | |||
Dim xr As Float = x * Cos(angle) + z * Sin(angle) | |||
Dim zr As Float = -x * Sin(angle) + z * Cos(angle) | |||
<FONT Color=gray>' ''Restituisce il punto ruotato:''</font> | |||
Return [xr, y, zr] | |||
End | |||
Private Function Project3D(v As Float[], d As Float, cx As Float, cy As Float) As PointF <FONT Color=gray>' ''Funzione che proietta un punto 3D nello spazio 2D (prospettiva)''</font> | |||
Dim x As Float = v[0] | |||
Dim y As Float = v[1] | |||
Dim z As Float = v[2] | |||
<FONT Color=gray>' ''Fattore di proiezione prospettica (più z è grande, più il punto è vicino):''</font> | |||
Dim factor As Float = d / (z + d + 0.001) ' +0.001 per evitare divisione per zero | |||
<FONT Color=gray>' ''Coordinate proiettate in 2D:''</font> | |||
Dim x2D As Float = x * factor | |||
Dim y2D As Float = y * factor | |||
<FONT Color=gray>' ''Trasla e scala nel sistema della DrawingArea (inverte Y per avere l'alto verso l'alto):''</font> | |||
Return New PointF(cx + x2D * 100, cy - y2D * 100) | |||
End | |||
==Rotazione 3D attorno agli assi X, Y e Z== | |||
Nel seguente codice faremo ruotare un triangolo isoscele attorno ai suoi assi X, Y e Z: | |||
Private DrawingArea1 As DrawingArea | |||
Private Timer1 As Timer | |||
<FONT Color=gray>' ''Variabili globali per gli angoli di rotazione su ciascun asse:''</font> | |||
Private angleX As Float | |||
Private angleY As Float | |||
Private angleZ As Float | |||
Public Sub Form_Open() | |||
With Me | |||
.Title = "Rotazione di un Triangolo isoscele attorno agli assi X, Y e Z" | |||
.Move(0, 0, Screen.AvailableWidth, Screen.AvailableHeight) | |||
.Arrangement = Arrange.Fill | |||
End With | |||
With DrawingArea1 = New DrawingArea(Me) As "DrawingArea1" | |||
.Background = Color.White | |||
End With | |||
Timer1 = New Timer As "Timer1" | |||
Timer1.Delay = 16 | |||
Timer1.Start() | |||
End | |||
Public Sub Timer1_Timer() | |||
<FONT Color=gray>' ''Aumenta l’angolo di rotazione:''</font> | |||
angleX += 1 <FONT Color=gray>' ''Ruota di 1 grado sull'asse X''</font> | |||
angleY += 2 <FONT Color=gray>' ''Ruota di 2 gradi sull'asse Y''</font> | |||
angleZ += 1.5 <FONT Color=gray>' ''Ruota di 1.5 gradi sull'asse Z''</font> | |||
<FONT Color=gray>' ''Richiede il ridisegno della DrawingArea:''</font> | |||
DrawingArea1.Refresh | |||
End | |||
Public Sub DrawingArea1_Draw() | |||
<FONT Color=gray>' ''Centro della DrawingArea (origine della scena):''</font> | |||
Dim cx As Float = DrawingArea1.Width / 2 | |||
Dim cy As Float = DrawingArea1.Height / 2 | |||
<FONT Color=gray>' ''Dimensioni del triangolo:''</font> | |||
Dim baseHalf As Float = 2.0 <FONT Color=gray>' ''metà della base (±x)''</font> | |||
Dim height As Float = 3.0 <FONT Color=gray>' ''altezza verticale''</font> | |||
Dim d As Float = 4.0 <FONT Color=gray>' ''distanza "camera", ossia dell'osservatore, per simulare la prospettiva''</font> | |||
<FONT Color=gray>' ''Converte gli angoli da gradi a radianti (richiesto per Sin/Cos):''</font> | |||
Dim ax As Float = Rad(angleX) | |||
Dim ay As Float = Rad(angleY) | |||
Dim az As Float = Rad(angleZ) | |||
<FONT Color=gray>' ''Vertici iniziali del triangolo in 3D (sul piano XZ):''</font> | |||
Dim v1 As Float[] = [0.0, height / 2, 0.0] <FONT Color=gray>' ''vertice superiore (centro in alto)''</font> | |||
Dim v2 As Float[] = [-baseHalf, -height / 2, 0.0] <FONT Color=gray>' ''vertice base sinistra''</font> | |||
Dim v3 As Float[] = [baseHalf, -height / 2, 0.0] <FONT Color=gray>' ''vertice base destra''</font> | |||
<FONT Color=gray>' ''Applica rotazione 3D a ciascun vertice: prima X, poi Y, poi Z:''</font> | |||
v1 = RotateZ(RotateY(RotateX(v1, ax), ay), az) | |||
v2 = RotateZ(RotateY(RotateX(v2, ax), ay), az) | |||
v3 = RotateZ(RotateY(RotateX(v3, ax), ay), az) | |||
<FONT Color=gray>' ''Proietta i vertici ruotati da 3D → 2D (con prospettiva):''</font> | |||
Dim p1 As PointF = Project3D(v1, d, cx, cy) | |||
Dim p2 As PointF = Project3D(v2, d, cx, cy) | |||
Dim p3 As PointF = Project3D(v3, d, cx, cy) | |||
<FONT Color=gray>' ''Costruisce l'array di coordinate 2D [x0, y0, x1, y1, x2, y2]:''</font> | |||
Dim coords As Float[] = [p1.X, p1.Y, p2.X, p2.Y, p3.X, p3.Y] | |||
<FONT Color=gray>' ''Disegna e riempie il triangolo con colore rosso:''</font> | |||
Paint.Brush = Paint.Color(Color.Red) | |||
Paint.Polygon(coords) <FONT Color=gray>' ''Definisce il contorno''</font> | |||
Paint.Fill() <FONT Color=gray>' ''Riempe il triangolo''</font> | |||
End | |||
Private Function RotateX(v As Float[], angle As Float) As Float[] <FONT Color=gray>' ''Ruota un punto attorno all'asse X (varia y, z)''</font> | |||
Dim x As Float = v[0] | |||
Dim y As Float = v[1] | |||
Dim z As Float = v[2] | |||
Dim yr As Float = y * Cos(angle) - z * Sin(angle) | |||
Dim zr As Float = y * Sin(angle) + z * Cos(angle) | |||
Return [x, yr, zr] | |||
End | |||
Private Function RotateY(v As Float[], angle As Float) As Float[] <FONT Color=gray>' ''Ruota un punto attorno all'asse Y (varia x, z)''</font> | |||
Dim x As Float = v[0] | |||
Dim y As Float = v[1] | |||
Dim z As Float = v[2] | |||
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 | |||
Private Function RotateZ(v As Float[], angle As Float) As Float[] <FONT Color=gray>' ''Ruota un punto attorno all'asse Z (varia x, y)''</font> | |||
Dim x As Float = v[0] | |||
Dim y As Float = v[1] | |||
Dim z As Float = v[2] | |||
Dim xr As Float = x * Cos(angle) - y * Sin(angle) | |||
Dim yr As Float = x * Sin(angle) + y * Cos(angle) | |||
Return [xr, yr, z] | |||
End | |||
Private Function Project3D(v As Float[], d As Float, cx As Float, cy As Float) As PointF <FONT Color=gray>' ''Proietta un punto 3D in coordinate 2D con prospettiva''</font> | |||
Dim x As Float = v[0] | |||
Dim y As Float = v[1] | |||
Dim z As Float = v[2] | |||
<FONT Color=gray>' ''Calcola il fattore di scala prospettico:''</font> | |||
Dim factor As Float = d / (z + d + 0.001) <FONT Color=gray>' ''Evita divisione per 0''</font> | |||
<FONT Color=gray>' ''Proietta x e y in base alla profondità (z):''</font> | |||
Dim x2D As Float = x * factor | |||
Dim y2D As Float = y * factor | |||
<FONT Color=gray>' ''Trasla e scala nel sistema di coordinate della DrawingArea:''</font> | |||
Return New PointF(cx + x2D * 100, cy - y2D * 100) <FONT Color=gray>' ''*100 = scala visiva''</font> | |||
End | |||
---- | |||
=Note= | =Note= | ||
[1] Vedere anche queste pagine: | [1] Vedere anche queste pagine: | ||
* [[ | * [[Ruotare un cerchio disegnato in una DrawingArea]] | ||
* [[ | * [[Ruotare un quadrato ed un rettangolo in una DrawingArea]] | ||
* [[ | * [[Ruotare qualsiasi elemento da disegnare in una DrawingArea]] | ||
* [[ | * [[Ruotare una immagine sul proprio asse centrale]] | ||
Versione attuale delle 18:50, 10 ago 2025
Mostriamo due possibili codice per far ruotare su se stesso un Triangolo disegnato su una DrawingArea. [Nota 1]
Rotazione in 2D
Ruotare un Triangolo intorno al suo Baricentro
Di seguito mostreremo un possibile codice per ruotare un Triangolo intorno al suo Baricentro.
Il fulcro del Metodo ".Translate()" agisce da vortice, ossia da centro di rotazione intorno a una ipotetica circonferenza.
La rotazione del triangolo viene effettuata premendo i tasti freccia in su e freccia in giù della tastiera oppure ruotando la rotellina del mouse.
Private DrawingArea1 As DrawingArea
' Imposta le coordinate dei tre vertici del triangolo, con il primo vertice nel punto di rotazione (0, 0):
Private ABC As Single[] = [0, 0, 200, 0, 100, 300]
' Calcoli per ottenere il "Baricentro" del triangolo:
Private xb As Single = (ABC[0] + ABC[2] + ABC[4]) / 3
Private yb As Single = (ABC[1] + ABC[3] + ABC[5]) / 3
' Memorizza i gradi dell'angolo:
Private ang As Float
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 = Screen.AvailableWidth
.H = Screen.AvailableHeight
.Arrangement = Arrange.Fill
End With
With DrawingArea1 = 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(DrawingArea1.W / 2, DrawingArea1.H / 2)
.Rotate(Rad(ang))
.LineWidth = 2.0
' Disegna il Triangolo.
' Giacché l'angolo ruota su se stesso, avendo come centro di rotazione il proprio "Baricentro", ad ogni coordinata del punto, che costituisce un elemento del vettore del Metodo ".Polygon()", si sottrae il valore della corrispondente coordinata del punto del Baricentro. In questo modo si farà coincidere l'angolo di rotazione con il "Baricentro" del Triangolo.
' Non si devono modificare i valori né i segni dei quattro argomenti qui riportati.
.Polygon([ABC[0] - xb, ABC[1] - yb, ABC[2] - xb, ABC[3] - yb, ABC[4] - xb, ABC[5] - yb])
.Stroke
End With
End
Public Sub Form_KeyPress()
Select Case Key.Code
Case Key.Up
ang += 1
If ang = 361 Then ang = 1
Case Key.Down
ang -= 1
If ang = -361 Then ang = -1
End Select
DrawingArea1.Refresh
End
Public Sub Form_MouseWheel()
ang += Mouse.Delta
Select Case ang
Case 361
ang = 1
Case -361
ang = -1
End Select
DrawingArea1.Refresh
End
Public Sub Form_Resize() ' Con questo evento se cambia la dimensione del Form, il disegno non va perso.
DrawingArea1.Refresh
End
oppure anche questo codice:
Private DrawingArea1 As DrawingArea
Private Timer1 As Timer
Private rotationAngle As Float
Public Sub Form_Open()
With Me
.Move(0, 0, Screen.AvailableWidth, Screen.AvailableHeight)
.Arrangement = Arrange.Fill
End With
With DrawingArea1 = New DrawingArea(Me) As "DrawingArea1"
.Background = Color.Lighter(Color.White)
End With
Timer1 = New Timer As "Timer1"
Timer1.Delay = 30
Timer1.Start()
End
Public Sub Timer1_Timer()
rotationAngle += Rad(2) ' ruota di 2 gradi ogni frame
If rotationAngle >= 2 * Pi Then
rotationAngle -= 2 * Pi
End If
DrawingArea1.Refresh()
End
Public Sub DrawingArea1_Draw()
Dim cx As Float = DrawingArea1.W / 2
Dim cy As Float = DrawingArea1.H / 2
Dim size As Float = Min(DrawingArea1.W, DrawingArea1.H) * 0.4
' Definisci i vertici del triangolo (posizionati attorno a (0,0)):
Dim points As New PointF[3]
points[0] = New PointF(0, -size / 2) ' vertice superiore
points[1] = New PointF(-size / 2, size / 2) ' vertice basso sinistro
points[2] = New PointF(size / 2, size / 2) ' vertice basso destro
' Calcola baricentro (centroide):
Dim centroidX As Float = 0
Dim centroidY As Float = 0
For i As Integer = 0 To 2
centroidX += points[i].X
centroidY += points[i].Y
Next
centroidX /= 3
centroidY /= 3
' Ruota i punti attorno al baricentro e trasla al centro DrawingArea:
For i As Integer = 0 To 2
Dim xOld As Float = points[i].X - centroidX
Dim yOld As Float = points[i].Y - centroidY
points[i].X = xOld * Cos(rotationAngle) - yOld * Sin(rotationAngle) + centroidX + cx
points[i].Y = xOld * Sin(rotationAngle) + yOld * Cos(rotationAngle) + centroidY + cy
Next
With Paint
.Brush = Paint.Color(Color.Black)
.LineWidth = 2
.MoveTo(points[0].X, points[0].Y)
For i As Integer = 1 To 2
.LineTo(points[i].X, points[i].Y)
Next
.LineTo(points[0].X, points[0].Y)
.Stroke
' Punto nero sul baricentro (traslato):
.Arc(cx + centroidX, cy + centroidY, 5, Rad(0), Rad(360), False)
.Fill
End With
End
Il seguente codice disegna e ruota un Triangolo scaleno intorno al suo Baricentro:
Private DrawingArea1 As DrawingArea
Private Timer1 As Timer
Private rotationAngle As Float
Public Sub Form_Open()
With Me
.Move(0, 0, Screen.AvailableWidth, Screen.AvailableHeight)
.Arrangement = Arrange.Fill
End With
With DrawingArea1 = New DrawingArea(Me) As "DrawingArea1"
.Background = Color.Lighter(Color.White)
End With
Timer1 = New Timer As "Timer1"
Timer1.Delay = 30
Timer1.Start()
End
Public Sub Timer1_Timer()
rotationAngle += Rad(2)
If rotationAngle >= 2 * Pi Then
rotationAngle -= 2 * Pi
End If
DrawingArea1.Refresh()
End
Public Sub DrawingArea1_Draw()
Dim cx As Float = DrawingArea1.W / 2
Dim cy As Float = DrawingArea1.H / 2
' Vertici di un triangolo scaleno (modificabili):
Dim points As New PointF[3]
points[0] = New PointF(-160, -80) ' 'Vertice A
points[1] = New PointF(210, 50) ' 'Vertice B
points[2] = New PointF(50, 190) ' 'Vertice C
' Calcola il baricentro (media delle coordinate):
Dim baryX As Float = (points[0].X + points[1].X + points[2].X) / 3
Dim baryY As Float = (points[0].Y + points[1].Y + points[2].Y) / 3
' Ruota i punti attorno al baricentro:
For i As Integer = 0 To 2
Dim xOld As Float = points[i].X - baryX
Dim yOld As Float = points[i].Y - baryY
points[i].X = xOld * Cos(rotationAngle) - yOld * Sin(rotationAngle) + baryX
points[i].Y = xOld * Sin(rotationAngle) + yOld * Cos(rotationAngle) + baryY
' Trasla il triangolo per centrarlo nella DrawingArea:
points[i].X += cx
points[i].Y += cy
Next
With Paint
.Brush = Paint.Color(Color.Black)
.LineWidth = 2
' Disegna il triangolo:
.MoveTo(points[0].X, points[0].Y)
For i As Integer = 1 To 2
.LineTo(points[i].X, points[i].Y)
Next
.LineTo(points[0].X, points[0].Y)
.Stroke
' Disegna il punto nero sul baricentro traslato correttamente:
.Arc(cx + baryX, cy + baryY, 5, Rad(0), Rad(360), False)
.Fill
End With
End
Ruotare un Triangolo intorno al suo Incentro
Quest'altro codice servirà per far ruotare un Triangolo intorno al suo Incentro.
La rotazione del triangolo viene effettuata premendo i tasti freccia in su e freccia in giù della tastiera oppure ruotando la rotellina del mouse.
Il fulcro del Metodo ".Translate()" agisce da vortice, ossia da centro di rotazione intorno a una ipotetica circonferenza.
Private DrawingArea1 As DrawingArea ' Imposta le coordinate dei tre vertici del triangolo, con il primo vertice nel punto di rotazione (0, 0): Private ABC As Single[] = [0, 0, 200, 0, 100, 300] ' Calcola la distanza euclidea fra due punti, per ottenere la lunghezza di ciascun lato del triangolo: Private ab As Single = Sqr(((ABC[2] - ABC[0]) ^ 2) + ((ABC[3] - ABC[1]) ^ 2)) Private bc As Single = Sqr(((ABC[4] - ABC[2]) ^ 2) + ((ABC[5] - ABC[3]) ^ 2)) Private ac As Single = Sqr(((ABC[4] - ABC[0]) ^ 2) + ((ABC[5] - ABC[1]) ^ 2)) ' Calcoli per ottenere il "Incentro" del triangolo: Private ix As Single = ((ab * ABC[4]) + (bc * ABC[0]) + (ac * ABC[2])) / (ab + bc + ac) Private iy As Single = ((ab * ABC[5]) + (bc * ABC[1]) + (ac * ABC[3])) / (ab + bc + ac) ' Memorizza i gradi dell'angolo: Private ang As Float 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 = Screen.AvailableWidth .H = Screen.AvailableHeight .Arrangement = Arrange.Fill End With With DrawingArea1 = 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(DrawingArea1.W / 2, DrawingArea1.H / 2) .Rotate(Rad(ang)) .LineWidth = 2.0 ' Disegna il Triangolo. ' Siccome l'angolo ruota su se stesso, avendo come centro di rotazione il proprio "Incentro", ad ogni coordinata del punto, che costituisce un elemento del vettore del Metodo ".Polygon()", si sottrae il valore della corrispondente coordinata del punto dell'Incentro. In questo modo si farà coincidere l'angolo di rotazione con il "Incentro" del Triangolo. ' Non si devono modificare i valori né i segni dei quattro argomenti qui riportati. .Polygon([ABC[0] - ix, ABC[1] - iy, ABC[2] - ix, ABC[3] - iy, ABC[4] - ix, ABC[5] - iy]) .Stroke End With End Public Sub Form_KeyPress() Select Case Key.Code Case Key.Up ang += 1 If ang = 361 Then ang = 1 Case Key.Down ang -= 1 If ang = -361 Then ang = -1 End Select DrawingArea1.Refresh End Public Sub Form_MouseWheel() ang += Mouse.Delta Select Case ang Case 361 ang = 1 Case -361 ang = -1 End Select DrawingArea1.Refresh End Public Sub Form_Resize() ' Con questo evento se cambia la dimensione del Form, il disegno non va perso. DrawingArea1.Refresh End
oppure quest'altro codice:
Private DrawingArea1 As DrawingArea
Private Timer1 As Timer
Private rotationAngle As Float = 0
Public Sub Form_Open()
With Me
.Move(0, 0, Screen.AvailableWidth, Screen.AvailableHeight)
.Arrangement = Arrange.Fill
End With
With DrawingArea1 = New DrawingArea(Me) As "DrawingArea1"
.Background = Color.Lighter(Color.White)
End With
Timer1 = New Timer As "Timer1"
Timer1.Delay = 30
Timer1.Start()
End
Public Sub Timer1_Timer()
rotationAngle += Rad(2)
If rotationAngle >= 2 * Pi Then
rotationAngle -= 2 * Pi
End If
DrawingArea1.Refresh()
End
Public Sub DrawingArea1_Draw()
Dim cx As Float = DrawingArea1.W / 2
Dim cy As Float = DrawingArea1.H / 2
Dim base As Float = Min(DrawingArea1.W, DrawingArea1.H) * 0.5
Dim height As Float = base * 0.7
' Vertici triangolo isoscele (vertice in alto):
Dim points As New PointF[3]
points[0] = New PointF(0, -height / 2) ' vertice superiore A
points[1] = New PointF(-base / 2, height / 2) ' vertice basso sinistro B
points[2] = New PointF(base / 2, height / 2) ' vertice basso destro C
' Calcola lunghezze lati:
Dim a As Float = Sqr((points[1].X - points[2].X) ^ 2 + (points[1].Y - points[2].Y) ^ 2) ' BC
Dim b As Float = Sqr((points[0].X - points[2].X) ^ 2 + (points[0].Y - points[2].Y) ^ 2) ' AC
Dim c As Float = Sqr((points[0].X - points[1].X) ^ 2 + (points[0].Y - points[1].Y) ^ 2) ' AB
' Calcola l'Incentro:
Dim incentroX As Float = (a * points[0].X + b * points[1].X + c * points[2].X) / (a + b + c)
Dim incentroY As Float = (a * points[0].Y + b * points[1].Y + c * points[2].Y) / (a + b + c)
' Ruota attorno all'incentro e trasla nel centro DrawingArea:
For i As Integer = 0 To 2
Dim xOld As Float = points[i].X - incentroX
Dim yOld As Float = points[i].Y - incentroY
points[i].X = xOld * Cos(rotationAngle) - yOld * Sin(rotationAngle) + incentroX + cx
points[i].Y = xOld * Sin(rotationAngle) + yOld * Cos(rotationAngle) + incentroY + cy
Next
With Paint
.Brush = Paint.Color(Color.Black)
.LineWidth = 2
.MoveTo(points[0].X, points[0].Y)
For i As Integer = 1 To 2
.LineTo(points[i].X, points[i].Y)
Next
.LineTo(points[0].X, points[0].Y)
.Stroke
' Punto nero sul incentro:
.Arc(cx + incentroX, cy + incentroY, 5, Rad(0), Rad(360), False)
.Fill
End With
End
Il seguente codice disegna e ruota un Triangolo scaleno intorno al suo Incentro:
Private DrawingArea1 As DrawingArea
Private Timer1 As Timer
Private rotationAngle As Float
Public Sub Form_Open()
With Me
.Move(0, 0, Screen.AvailableWidth, Screen.AvailableHeight)
.Arrangement = Arrange.Fill
End With
With DrawingArea1 = New DrawingArea(Me) As "DrawingArea1"
.Background = Color.Lighter(Color.White)
End With
Timer1 = New Timer As "Timer1"
Timer1.Delay = 30
Timer1.Start()
End
Public Sub Timer1_Timer()
rotationAngle += Rad(2)
If rotationAngle >= 2 * Pi Then
rotationAngle -= 2 * Pi
End If
DrawingArea1.Refresh()
End
Public Sub DrawingArea1_Draw()
Dim cx As Float = DrawingArea1.W / 2
Dim cy As Float = DrawingArea1.H / 2
' Vertici di un triangolo scaleno senza angoli retti:
Dim points As New PointF[3]
points[0] = New PointF(-160, -80) ' Vertice A
points[1] = New PointF(210, 50) ' Vertice B
points[2] = New PointF(50, 190) ' Vertice C
' Calcola le lunghezze dei lati:
Dim a As Float = Sqr((points[1].X - points[2].X) ^ 2 + (points[1].Y - points[2].Y) ^ 2) ' BC
Dim b As Float = Sqr((points[0].X - points[2].X) ^ 2 + (points[0].Y - points[2].Y) ^ 2) ' AC
Dim c As Float = Sqr((points[0].X - points[1].X) ^ 2 + (points[0].Y - points[1].Y) ^ 2) ' AB
' Calcola l'incentro:
Dim incentroX As Float = (a * points[0].X + b * points[1].X + c * points[2].X) / (a + b + c)
Dim incentroY As Float = (a * points[0].Y + b * points[1].Y + c * points[2].Y) / (a + b + c)
' Ruota i punti attorno all'incentro e trasla nel centro della DrawingArea:
For i As Integer = 0 To 2
Dim xOld As Float = points[i].X - incentroX
Dim yOld As Float = points[i].Y - incentroY
points[i].X = xOld * Cos(rotationAngle) - yOld * Sin(rotationAngle) + incentroX + cx
points[i].Y = xOld * Sin(rotationAngle) + yOld * Cos(rotationAngle) + incentroY + cy
Next
With Paint
.Brush = Paint.Color(Color.Black)
.LineWidth = 2
' Disegna il triangolo:
.MoveTo(points[0].X, points[0].Y)
For i As Integer = 1 To 2
.LineTo(points[i].X, points[i].Y)
Next
.LineTo(points[0].X, points[0].Y)
.Stroke
' Disegna il punto nero sull'incentro:
.Arc(cx + incentroX, cy + incentroY, 5, Rad(0), Rad(360), False)
.Fill
End With
End
Rotazione in 3D
Rotazione 3D attorno all'asse Y
Nel seguente codice faremo ruotare un triangolo isoscele attorno all'asse Y (cioè in spazio 3D):
Private DrawingArea1 As DrawingArea Private Timer1 As Timer Private angle As Float ' Variabile globale per memorizzare l'angolo corrente della rotazione Public Sub Form_Open() With Me .Title = "Rotazione di un Triangolo isoscele attorno all'asse Y" .Move(0, 0, Screen.AvailableWidth, Screen.AvailableHeight) .Arrangement = Arrange.Fill End With With DrawingArea1 = New DrawingArea(Me) As "DrawingArea1" .Background = Color.White End With Timer1 = New Timer As "Timer1" Timer1.Delay = 16 Timer1.Start() End Public Sub Timer1_Timer() ' Aumenta l’angolo di rotazione: angle += 2 If angle >= 360 Then angle = 0 ' Richiede il ridisegno della DrawingArea: DrawingArea1.Refresh End Public Sub DrawingArea1_Draw() ' Calcola il centro della DrawingArea: Dim cx As Float = DrawingArea1.Width / 2 Dim cy As Float = DrawingArea1.Height / 2 ' Parametri del triangolo: Dim baseHalf As Float = 1.0 ' Metà base Dim height As Float = 1.5 ' Altezza del triangolo Dim d As Float = 4.0 ' Distanza simulata dalla "camera", ossia dall'osservatore ' Angolo in radianti: Dim radAngle As Float = Rad(angle) ' Definizione dei 3 vertici del triangolo in coordinate 3D (x, y, z): Dim v1 As Float[] = [0.0, height / 2, 0.0] ' Vertice superiore Dim v2 As Float[] = [-baseHalf, -height / 2, 0.0] ' Vertice sinistro della base Dim v3 As Float[] = [baseHalf, -height / 2, 0.0] ' Vertice destro della base ' Applica la rotazione 3D attorno all’asse Y, quindi proietta in 2D: Dim p1 As PointF = Project3D(RotateY(v1, radAngle), d, cx, cy) Dim p2 As PointF = Project3D(RotateY(v2, radAngle), d, cx, cy) Dim p3 As PointF = Project3D(RotateY(v3, radAngle), d, cx, cy) ' Costruisce un array di coordinate [x0, y0, x1, y1, x2, y2]: Dim coords As Float[] = [p1.X, p1.Y, p2.X, p2.Y, p3.X, p3.Y] ' Disegna e riempie il triangolo: Paint.Brush = Paint.Color(Color.Red) ' Imposta il colore rosso Paint.Polygon(coords) ' Definisce la forma Paint.Fill() ' Riempe il triangolo End Private Function RotateY(v As Float[], angle As Float) As Float[] ' Funzione che ruota un punto 3D attorno all’asse Y Dim x As Float = v[0] Dim y As Float = v[1] Dim z As Float = v[2] ' Formula di rotazione attorno all'asse Y: Dim xr As Float = x * Cos(angle) + z * Sin(angle) Dim zr As Float = -x * Sin(angle) + z * Cos(angle) ' Restituisce il punto ruotato: Return [xr, y, zr] End Private Function Project3D(v As Float[], d As Float, cx As Float, cy As Float) As PointF ' Funzione che proietta un punto 3D nello spazio 2D (prospettiva) Dim x As Float = v[0] Dim y As Float = v[1] Dim z As Float = v[2] ' Fattore di proiezione prospettica (più z è grande, più il punto è vicino): Dim factor As Float = d / (z + d + 0.001) ' +0.001 per evitare divisione per zero ' Coordinate proiettate in 2D: Dim x2D As Float = x * factor Dim y2D As Float = y * factor ' Trasla e scala nel sistema della DrawingArea (inverte Y per avere l'alto verso l'alto): Return New PointF(cx + x2D * 100, cy - y2D * 100) End
Rotazione 3D attorno agli assi X, Y e Z
Nel seguente codice faremo ruotare un triangolo isoscele attorno ai suoi assi X, Y e Z:
Private DrawingArea1 As DrawingArea Private Timer1 As Timer ' Variabili globali per gli angoli di rotazione su ciascun asse: Private angleX As Float Private angleY As Float Private angleZ As Float Public Sub Form_Open() With Me .Title = "Rotazione di un Triangolo isoscele attorno agli assi X, Y e Z" .Move(0, 0, Screen.AvailableWidth, Screen.AvailableHeight) .Arrangement = Arrange.Fill End With With DrawingArea1 = New DrawingArea(Me) As "DrawingArea1" .Background = Color.White End With Timer1 = New Timer As "Timer1" Timer1.Delay = 16 Timer1.Start() End Public Sub Timer1_Timer() ' Aumenta l’angolo di rotazione: angleX += 1 ' Ruota di 1 grado sull'asse X angleY += 2 ' Ruota di 2 gradi sull'asse Y angleZ += 1.5 ' Ruota di 1.5 gradi sull'asse Z ' Richiede il ridisegno della DrawingArea: DrawingArea1.Refresh End Public Sub DrawingArea1_Draw() ' Centro della DrawingArea (origine della scena): Dim cx As Float = DrawingArea1.Width / 2 Dim cy As Float = DrawingArea1.Height / 2 ' Dimensioni del triangolo: Dim baseHalf As Float = 2.0 ' metà della base (±x) Dim height As Float = 3.0 ' altezza verticale Dim d As Float = 4.0 ' distanza "camera", ossia dell'osservatore, per simulare la prospettiva ' Converte gli angoli da gradi a radianti (richiesto per Sin/Cos): Dim ax As Float = Rad(angleX) Dim ay As Float = Rad(angleY) Dim az As Float = Rad(angleZ) ' Vertici iniziali del triangolo in 3D (sul piano XZ): Dim v1 As Float[] = [0.0, height / 2, 0.0] ' vertice superiore (centro in alto) Dim v2 As Float[] = [-baseHalf, -height / 2, 0.0] ' vertice base sinistra Dim v3 As Float[] = [baseHalf, -height / 2, 0.0] ' vertice base destra ' Applica rotazione 3D a ciascun vertice: prima X, poi Y, poi Z: v1 = RotateZ(RotateY(RotateX(v1, ax), ay), az) v2 = RotateZ(RotateY(RotateX(v2, ax), ay), az) v3 = RotateZ(RotateY(RotateX(v3, ax), ay), az) ' Proietta i vertici ruotati da 3D → 2D (con prospettiva): Dim p1 As PointF = Project3D(v1, d, cx, cy) Dim p2 As PointF = Project3D(v2, d, cx, cy) Dim p3 As PointF = Project3D(v3, d, cx, cy) ' Costruisce l'array di coordinate 2D [x0, y0, x1, y1, x2, y2]: Dim coords As Float[] = [p1.X, p1.Y, p2.X, p2.Y, p3.X, p3.Y] ' Disegna e riempie il triangolo con colore rosso: Paint.Brush = Paint.Color(Color.Red) Paint.Polygon(coords) ' Definisce il contorno Paint.Fill() ' Riempe il triangolo End Private Function RotateX(v As Float[], angle As Float) As Float[] ' Ruota un punto attorno all'asse X (varia y, z) Dim x As Float = v[0] Dim y As Float = v[1] Dim z As Float = v[2] Dim yr As Float = y * Cos(angle) - z * Sin(angle) Dim zr As Float = y * Sin(angle) + z * Cos(angle) Return [x, yr, zr] End Private Function RotateY(v As Float[], angle As Float) As Float[] ' Ruota un punto attorno all'asse Y (varia x, z) Dim x As Float = v[0] Dim y As Float = v[1] Dim z As Float = v[2] 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 Private Function RotateZ(v As Float[], angle As Float) As Float[] ' Ruota un punto attorno all'asse Z (varia x, y) Dim x As Float = v[0] Dim y As Float = v[1] Dim z As Float = v[2] Dim xr As Float = x * Cos(angle) - y * Sin(angle) Dim yr As Float = x * Sin(angle) + y * Cos(angle) Return [xr, yr, z] End Private Function Project3D(v As Float[], d As Float, cx As Float, cy As Float) As PointF ' Proietta un punto 3D in coordinate 2D con prospettiva Dim x As Float = v[0] Dim y As Float = v[1] Dim z As Float = v[2] ' Calcola il fattore di scala prospettico: Dim factor As Float = d / (z + d + 0.001) ' Evita divisione per 0 ' Proietta x e y in base alla profondità (z): Dim x2D As Float = x * factor Dim y2D As Float = y * factor ' Trasla e scala nel sistema di coordinate della DrawingArea: Return New PointF(cx + x2D * 100, cy - y2D * 100) ' *100 = scala visiva End
Note
[1] Vedere anche queste pagine: