15,943,245 members
5.00/5 (1 vote)
See more:
I have been try to work this problem out for months (If not a year). I can't seem to get the direction of rotation relative the 3D model on screen. I can work out the axis directions (as angles) but can't get the mouse direction to orbit the model(Just like a modelling software like Sketchup).

I have added code which seems to be poor but I have tried so many different ways & it has got so complex. So I have stripped it down to simple bones to start understanding what is really controlling what. I feel like giving up but I think I need to ask for help.

I have tried googling but nothing seems to quite fit or I can apply to the application.

The rotation code was from Rotating Solid Cube Using VB.NET and GDI+ | codeNtronix[^]

What I have tried:

VB
```Dim Distance_Between As Integer = 0 'How much rotation

Distance_Between = Math.Sqrt(((e.X - m_PanStartPoint.X) ^ 2) + ((e.Y - m_PanStartPoint.Y) ^ 2))

Dim X_Angle_Diff As Integer = Angle_Axis_X - Angle_Mouse
Dim Y_Angle_Diff As Integer = (Angle_Axis_Y) - Angle_Mouse

If X_Angle_Diff <> 0 Then
X_Rotate = Orig_X_Rot - (X_Angle_Diff * (Distance_Between / 2000))
End If

If Y_Angle_Diff <> 0 Then
Y_Rotate = Orig_Y_Rot + (Y_Angle_Diff * (Distance_Between / 2000))
End If```

Sorry for not being clear.
You are correct the rotation point is not stated but it will be (until I can workout the shift relative to the different rotation point i.e. distance from drawn zero point & mouse rotation) the drawing zero point. The drawing zero point is positioned by Matrix Translate (& Scale is done also at this time).

VB
```Dim translateMatrix1 As New Matrix
translateMatrix1.Scale(Scale_Path, Scale_Path, MatrixOrder.Append)
translateMatrix1.Translate(Offset_X_Path, Offset_Y_Path, MatrixOrder.Append)
Temp_Path.Transform(translateMatrix1)```

Where I am now after help from Ralf Meier:-
```Dim Correct_Speed_Factor As Decimal = Scale_Path * 0.5 ' set speed of rotation relative to scale

Dim Angle_Mouse As Decimal = Math.Atan2(Orbit_Start.Y - e.Y, Orbit_Start.X - e.X) * 180 / Math.PI

If Angle_Mouse < 0 Then
Angle_Mouse = 360 + Angle_Mouse
End If

Dim Distance_Between As Decimal = 0 ' To account how much rotation

'Get distance of coord from mousedown to mouse postion
Distance_Between = Math.Sqrt(((e.X - Orbit_Start.X) ^ 2) + ((e.Y - Orbit_Start.Y) ^ 2))

'Get Positive differance between mouse & axis direction
Dim X_Angle_Diff As Decimal = Calc_Angle_dif(Y_Direction_Angle, Angle_Mouse) 'Y_Direction_Angle - Angle_Mouse

Dim Y_Angle_Diff As Decimal = Calc_Angle_dif(X_Direction_Angle, Angle_Mouse)
Dim Z_Angle_Diff As Decimal = (Calc_Angle_dif(X_Direction_Angle, Angle_Mouse) + Calc_Angle_dif(Y_Direction_Angle, Angle_Mouse)) / 2

X_Rotate = Orig_X_Rot - ((Distance_Between * ((X_Angle_Diff - 90) / 90)) / Correct_Speed_Factor)

Y_Rotate = Orig_Y_Rot - ((Distance_Between * ((Y_Angle_Diff - 90) / 90)) / Correct_Speed_Factor)
Z_Rotate = Orig_Z_Rot - ((Distance_Between * ((Z_Angle_Diff - 90) / 90)) / Correct_Speed_Factor)

'Then redraw
```

With function
```Private Function Calc_Angle_dif(ByVal firstAngle As Single, ByVal secondAngle As Single) As Decimal
Dim difference As Decimal = secondAngle - firstAngle
Select Case difference
Case Is < -180
difference += 360
Case Is > 180
difference -= 360
End Select
If secondAngle = firstAngle Then
Return 0
Else
Return (Math.Abs(difference))
End If
End
End Function
```

This works quite well but I seem to a rotation lock when the X & Y are on the same plane. The other problem is some time(not always when upside down) the roll direction is reversed.

Weird & I am not quite sure what is the cause. Any help is welcome as my math are getting very much stretched.

I think I may of found the reason for the errors. the 3D rotation formula works in X rotation but Y & Z are in screen rotation. This is matrices calculation which maybe a bit to far for my math expertices. Maybe need some help finding the reason.

```Public Function RotateX(ByVal angle As Integer) As Point3D
Dim rad As Double, cosa As Double, sina As Double, yn As Double, zn As Double

rad = angle * Math.PI / 180
cosa = Math.Cos(rad)
sina = Math.Sin(rad)
yn = Me.Y * cosa - Me.Z * sina
zn = Me.Y * sina + Me.Z * cosa
Return New Point3D(Me.X, yn, zn)
End Function

Public Function RotateY(ByVal angle As Integer) As Point3D
Dim rad As Double, cosa As Double, sina As Double, Xn As Double, Zn As Double

rad = angle * Math.PI / 180
cosa = Math.Cos(rad)
sina = Math.Sin(rad)
Zn = Me.Z * cosa - Me.X * sina
Xn = Me.Z * sina + Me.X * cosa

Return New Point3D(Xn, Me.Y, Zn)
End Function

Public Function RotateZ(ByVal angle As Integer) As Point3D
Dim rad As Double, cosa As Double, sina As Double, Xn As Double, Yn As Double

rad = angle * Math.PI / 180
cosa = Math.Cos(rad)
sina = Math.Sin(rad)
Xn = Me.X * cosa - Me.Y * sina
Yn = Me.X * sina + Me.Y * cosa
Return New Point3D(Xn, Yn, Me.Z)
End Function```

Using Solution 2 from Ralf Meier

Here is the problem I am having with changing rotation point by snap point.
Updated after Ralf Meier comments.
```Imports System.Drawing.Graphics

Public Class Form2
'Inherits Control

Protected m_vertices(8) As Point3D
Protected m_faces(6, 4) As Integer
Protected m_colors(6) As Color
Protected m_brushes(6) As Brush

Dim Offset_X As Integer
Dim Offset_Y As Integer
Dim Scale As Integer = 100

Sub New()
' Enable double-buffering to eliminate flickering.
Me.SetStyle(ControlStyles.AllPaintingInWmPaint, True)
Me.SetStyle(ControlStyles.OptimizedDoubleBuffer, True)

' Create the cube vertices.

m_vertices = New Point3D() {
New Point3D(-1, 1, -1),
New Point3D(1, 1, -1),
New Point3D(1, -1, -1),
New Point3D(-1, -1, -1),
New Point3D(-1, 1, 1),
New Point3D(1, 1, 1),
New Point3D(1, -1, 1),
New Point3D(-1, -1, 1)}

' Create an array representing the 6 faces of a cube. Each face is composed by indices to the vertex array
' above.
m_faces = New Integer(,) {{0, 1, 2, 3}, {1, 5, 6, 2}, {5, 4, 7, 6}, {4, 0, 3, 7}, {0, 4, 5, 1}, {3, 2, 6, 7}}

' Define the colors of each face.
m_colors = New Color() {Color.BlueViolet, Color.Cyan, Color.Green, Color.Yellow, Color.Violet, Color.LightSkyBlue}

' Create the brushes to draw each face. Brushes are used to draw filled polygons.
For i = 0 To 5
m_brushes(i) = New SolidBrush(m_colors(i))
Next

End Sub

Property xAngle As Integer
Get
Return my_xAngle
End Get
Set(value As Integer)
my_xAngle = (value + 360) Mod 360
Me.Invalidate()
End Set
End Property

Private my_xAngle As Integer

Property yAngle As Integer
Get
Return my_yAngle
End Get
Set(value As Integer)
my_yAngle = (value + 360) Mod 360
Me.Invalidate()
End Set
End Property
Private my_yAngle As Integer

Property zAngle As Integer
Get
Return my_zAngle
End Get
Set(value As Integer)
my_zAngle = (value + 360) Mod 360
Me.Invalidate()
End Set
End Property

Private my_zAngle As Integer

Dim Shift_X As Integer 'Shift in X Pivot point
Dim Shift_Y As Integer 'Shift in Y Pivot point
Dim Shift_Z As Integer 'Shift in Z Pivot point

' Used for Panning
Dim Orig_X_Shift As Integer
Dim Orig_Y_Shift As Integer

Dim X_Zero_Track As Integer 'Track Origin point in X
Dim Y_Zero_Track As Integer 'Track Origin point in Y

Protected Overrides Sub OnMouseDown(e As System.Windows.Forms.MouseEventArgs)

If e.Button = Windows.Forms.MouseButtons.Left Then
MousePress = True
MousePosLast = e.Location
End If

'Pan
If e.Button = Windows.Forms.MouseButtons.Middle Then
MousePosLast = e.Location
Orig_X_Shift = Offset_X
Orig_Y_Shift = Offset_Y
End If

MyBase.OnMouseDown(e)
End Sub
Private MousePress As Boolean = False
Protected Overrides Sub OnMouseUp(e As System.Windows.Forms.MouseEventArgs)
MousePress = False

'Reset it back to position of Origin on No Snap
snap = False
Offset_X = X_Zero_Track
Offset_Y = Y_Zero_Track
Shift_X = 0 ' Zero Pivot point X
Shift_Y = 0 ' Zero Pivot point Y
Shift_Z = 0  'Zero Pivot point Z

MyBase.OnMouseUp(e)
End Sub

Private snap As Boolean = False

Protected Overrides Sub OnMouseMove(e As System.Windows.Forms.MouseEventArgs)

'Orbit
If MousePress Then

MouseMoveHorizontal = MousePosLast.X - e.X
MouseMoveVertical = MousePosLast.Y - e.Y
MousePosLast = e.Location

Dim Speed_Reducer As Integer = 5

Dim xxAngle As Integer = (xAngle + 360) Mod 180
Dim yyAngle As Integer = (yAngle + 360) Mod 180

If (yyAngle > 135) Or (yyAngle <= 45) Then
yAngle += MouseMoveHorizontal / Speed_Reducer
xAngle -= MouseMoveVertical / Speed_Reducer
Else
xxAngle = (xAngle + 360) Mod 180
If (xxAngle > 135) Or (xxAngle <= 45) Then
yAngle += MouseMoveHorizontal / Speed_Reducer
xAngle -= MouseMoveVertical / Speed_Reducer
Else
xAngle += MouseMoveHorizontal / Speed_Reducer
yAngle -= MouseMoveVertical / Speed_Reducer
End If
End If

Me.Invalidate()
End If

'Pan
If e.Button = Windows.Forms.MouseButtons.Middle Then
Offset_X = Orig_X_Shift + (e.X - MousePosLast.X)
Offset_Y = Orig_Y_Shift + (e.Y - MousePosLast.Y)
Me.Invalidate()
End If

MyBase.OnMouseMove(e)
End Sub
Private MouseMoveVertical As Integer = 0
Private MouseMoveHorizontal As Integer = 0
Private MousePosLast As Point

Protected Overrides Sub OnPaint(e As System.Windows.Forms.PaintEventArgs)
Dim t(8) As Point3D
Dim f(4) As Integer
Dim v As Point3D
Dim avgZ(6) As Double
Dim order(6) As Integer
Dim tmp As Double
Dim iMax As Integer

' Clear the window
e.Graphics.Clear(Color.LightBlue)

'Save to the original offset to set it back later
Dim Zero_Offset_X As Integer = Offset_X
Dim Zero_Offset_y As Integer = Offset_Y

'Reset offset (point of orgin) realitive to pivot point
Dim Pivot_Point As Point3D
Pivot_Point = New Point3D(Shift_X, Shift_Y, Shift_Z)
Pivot_Point = Pivot_Point.RotateX(xAngle).RotateY(yAngle).RotateZ(zAngle)
Offset_X -= ((Pivot_Point.X) * Scale)
Offset_Y -= ((Pivot_Point.Y) * Scale)

Dim Stringf As String = "SNAP ---- X" & Shift_X & " ------ Y" & Shift_X & " ------ Z" & Shift_Z
e.Graphics.DrawString(Stringf, New Font("Ariel", 12), New SolidBrush(Color.Black), 10, 10)

' Transform all the points and store them on the "t" array.
For i = 0 To 7
Dim b As Brush = New SolidBrush(Color.White)
v = m_vertices(i)
t(i) = v.RotateX(xAngle).RotateY(yAngle).RotateZ(zAngle)
't(i) = t(i).Project(Me.ClientSize.Width, Me.ClientSize.Height, 256, 10) 'Not Used

'Would do this as Transform Matrix to Graphicspath
'Scale
t(i).X *= Scale
t(i).Y *= Scale

'Shift Pivot Point for view
t(i).X += Offset_X
t(i).Y += Offset_Y
Next

' Compute the average Z value of each face.
For i = 0 To 5
avgZ(i) = (t(m_faces(i, 0)).Z + t(m_faces(i, 1)).Z + t(m_faces(i, 2)).Z + t(m_faces(i, 3)).Z) / 4.0
order(i) = i
Next

' Next we sort the faces in descending order based on the Z value.
' The objective is to draw distant faces first. This is called
' the PAINTERS ALGORITHM. So, the visible faces will hide the invisible ones.
' The sorting algorithm used is the SELECTION SORT.
For i = 0 To 4
iMax = i
For j = i + 1 To 5
If avgZ(j) > avgZ(iMax) Then
iMax = j
End If
Next
If iMax <> i Then
tmp = avgZ(i)
avgZ(i) = avgZ(iMax)
avgZ(iMax) = tmp

tmp = order(i)
order(i) = order(iMax)
order(iMax) = tmp
End If
Next

' Draw the faces using the PAINTERS ALGORITHM (distant faces first, closer faces last).
For i = 0 To 5
Dim points() As Point
Dim index As Integer = order(i)
points = New Point() {
New Point(CInt(t(m_faces(index, 0)).X), CInt(t(m_faces(index, 0)).Y)),
New Point(CInt(t(m_faces(index, 1)).X), CInt(t(m_faces(index, 1)).Y)),
New Point(CInt(t(m_faces(index, 2)).X), CInt(t(m_faces(index, 2)).Y)),
New Point(CInt(t(m_faces(index, 3)).X), CInt(t(m_faces(index, 3)).Y))
}
e.Graphics.FillPolygon(m_brushes(index), points)
Next

'Draw active pivot point
Pivot_Point = New Point3D(Shift_X, Shift_Y, Shift_Z)
Pivot_Point = Pivot_Point.RotateX(xAngle).RotateY(yAngle).RotateZ(zAngle)
e.Graphics.DrawString("X", New Font("Ariel", 12, FontStyle.Bold), New SolidBrush(Color.Red), ((Pivot_Point.X * Scale) + Offset_X) - 10, ((Pivot_Point.Y * Scale) + Offset_Y) - 10)

'Draw Orgin point
e.Graphics.DrawString("O", New Font("Ariel", 10), New SolidBrush(Color.Black), Offset_X - 8, Offset_Y - 8)

'Track Last place of Origin
X_Zero_Track = Offset_X ' (Zero.X * Scale) + Offset_X
Y_Zero_Track = Offset_Y ' (Zero.X * Scale) + Offset_X

'Reset Offset adjustments
Offset_X = Zero_Offset_X
Offset_Y = Zero_Offset_y

MyBase.OnPaint(e)
End Sub

Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load

Me.WindowState = FormWindowState.Maximized

'Set Offsets
Offset_X = Me.Width / 2
Offset_Y = Me.Height / 2

'Set Scale/Size
Scale = 100

End Sub

Private Sub Form2_MouseWheel(sender As Object, e As MouseEventArgs) Handles Me.MouseWheel

Dim scale_Factor As Decimal = 1.1

'Zoom
If e.Delta > 0 Then 'Zoom In
Scale *= scale_Factor

Else 'Zoom Out
If Scale / scale_Factor <= 0 Then 'Zoom to Small
Exit Sub
Else
Scale /= scale_Factor
End If

End If

Me.Invalidate()
End Sub

Private Sub Form2_KeyUp(sender As Object, e As KeyEventArgs) Handles Me.KeyUp

isKeyDown = False

'Reset it back to position of Origin on No Snap
snap = False
Offset_X = X_Zero_Track
Offset_Y = Y_Zero_Track
Shift_X = 0 ' Zero Pivot point X
Shift_Y = 0 ' Zero Pivot point Y
Shift_Z = 0  'Zero Pivot point Z

Me.Invalidate()
End Sub

Dim isKeyDown As Boolean = False

Private Sub Form2_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown

'Makesure there is only fire
If isKeyDown = True Then
Exit Sub
End If

Select Case e.KeyCode
Case Keys.NumPad1
snap = True
'Shift pivot to 1st point
Shift_X = m_vertices(0).X 'Shift in X Pivot point
Shift_Y = m_vertices(0).Y  'Shift in Y Pivot point
Shift_Z = m_vertices(0).Z  'Shift in Z Pivot point.

Case Keys.NumPad2
snap = True
'Shift pivot to 2nd point
Shift_X = m_vertices(1).X 'Shift in X Pivot point
Shift_Y = m_vertices(1).Y  'Shift in Y Pivot point
Shift_Z = m_vertices(1).Z  'Shift in Z Pivot point

Case Keys.NumPad3
snap = True
'Shift pivot to one 3rd point
Shift_X = m_vertices(2).X 'Shift in X Pivot point
Shift_Y = m_vertices(2).Y  'Shift in Y Pivot point
Shift_Z = m_vertices(2).Z  'Shift in Z Pivot point

Case Keys.NumPad4
snap = True
'Shift pivot to 4th point
Shift_X = m_vertices(3).X 'Shift in X Pivot point
Shift_Y = m_vertices(3).Y  'Shift in Y Pivot point
Shift_Z = m_vertices(3).Z  'Shift in Z Pivot point

Case Keys.NumPad5
snap = True
'Shift pivot to 5th point
Shift_X = m_vertices(4).X 'Shift in X Pivot point
Shift_Y = m_vertices(4).Y  'Shift in Y Pivot point
Shift_Z = m_vertices(4).Z  'Shift in Z Pivot point

Case Keys.NumPad6
snap = True
'Shift pivot to  6th point
Shift_X = m_vertices(5).X 'Shift in X Pivot point
Shift_Y = m_vertices(5).Y  'Shift in Y Pivot point
Shift_Z = m_vertices(5).Z  'Shift in Z Pivot point

Case Keys.NumPad7
snap = True
'Shift pivot to 7th point
Shift_X = m_vertices(6).X 'Shift in X Pivot point
Shift_Y = m_vertices(6).Y  'Shift in Y Pivot point
Shift_Z = m_vertices(6).Z  'Shift in Z Pivot point

Case Keys.NumPad8
snap = True
'Shift pivot to 8th point
Shift_X = m_vertices(7).X 'Shift in X Pivot point
Shift_Y = m_vertices(7).Y  'Shift in Y Pivot point
Shift_Z = m_vertices(7).Z  'Shift in Z Pivot point

Case Else
snap = False
'Shift point back to Zero/Origin
Shift_X = 0 ' Zero Pivot point X
Shift_Y = 0 ' Zero Pivot point Y
Shift_Z = 0  'Zero Pivot point Z

End Select

'Make adjustments offsets to compensate for new pivot point. Only once fire
Dim Pivot_Point As Point3D = New Point3D(Shift_X, Shift_Y, Shift_Z)
Pivot_Point = Pivot_Point.RotateX(xAngle).RotateY(yAngle).RotateZ(zAngle)
Offset_X += ((Pivot_Point.X) * Scale)
Offset_Y += ((Pivot_Point.Y) * Scale)

isKeyDown = True

Me.Invalidate()
End Sub
End Class```
Posted
Updated 26-Nov-17 6:31am
v9
Comments
RedDk 4-Oct-17 14:47pm
Great question. Unanswerable and not really a "good" QA post fodderpiece ... BUT, as software goes, at least the kind of software I buy, the best implementation of mouse movement would have to be ... ANY & ALL OF THEM!

Good luck, my friend!
Knight school 4-Oct-17 14:59pm
Thank you for reading & replying. At least I am not going mad.
Ralf Meier 5-Oct-17 4:40am
Your question is not clear for me.
You want to create a 3D-Vector, corresponding to a Centerpoint on the Screen, with the Mouse ?
At which point do you stuck ?
Your code-snippet doesn't show me anything about your issue ...
Ralf Meier 6-Oct-17 6:20am
I improved your question with your posted "Solution" ...
You should see it different :
- you have one centerpoint and one base-vector for your calculation
- your mouse-movement only allows you to detect it's x- and y-movement. If you want to rotate your calculated vector results on this movement. When moving horizontal you rotate the vector around the y-axis. When moving vertical you rotate around the x-axis. Depending on each movement you will get a new vector which is the base for your next movement. Only with this vector you can do the rotation/roll calculation and finally you could draw that.

I don't believe that Scale-Translate-Transform is very helpful for this ...
Knight school 6-Oct-17 13:59pm
Thanks. What happens if the axis are are already rotated (i.e. X= 45° Y =30° & the Z=5°). Will the roll/rotation be not relative to the true model because the axis is not aligned horizontal/vertical?

## Solution 2

I beg for apologize ... but I have forgotten what we have spoken about ...
According to my suggestion I modified the code from the Link you are refering to.
Here is my Solution : I build a Control which has the Behaviour that allows to rotate a cube with/by the Mouse-Movement.

VB
```Imports System.Drawing.Graphics

Public Class RotatingCube
Inherits Control

Protected m_vertices(8) As Point3D
Protected m_faces(6, 4) As Integer
Protected m_colors(6) As Color
Protected m_brushes(6) As Brush

Sub New()
' Enable double-buffering to eliminate flickering.
Me.SetStyle(ControlStyles.AllPaintingInWmPaint, True)
Me.SetStyle(ControlStyles.OptimizedDoubleBuffer, True)

' Create the cube vertices.
m_vertices = New Point3D() {
New Point3D(-1, 1, -1),
New Point3D(1, 1, -1),
New Point3D(1, -1, -1),
New Point3D(-1, -1, -1),
New Point3D(-1, 1, 1),
New Point3D(1, 1, 1),
New Point3D(1, -1, 1),
New Point3D(-1, -1, 1)}

' Create an array representing the 6 faces of a cube. Each face is composed by indices to the vertex array
' above.
m_faces = New Integer(,) {{0, 1, 2, 3}, {1, 5, 6, 2}, {5, 4, 7, 6}, {4, 0, 3, 7}, {0, 4, 5, 1}, {3, 2, 6, 7}}

' Define the colors of each face.
m_colors = New Color() {Color.BlueViolet, Color.Cyan, Color.Green, Color.Yellow, Color.Violet, Color.LightSkyBlue}

' Create the brushes to draw each face. Brushes are used to draw filled polygons.
For i = 0 To 5
m_brushes(i) = New SolidBrush(m_colors(i))
Next
End Sub

Property xAngle As Integer
Get
Return my_xAngle
End Get
Set(value As Integer)
my_xAngle = (value + 360) Mod 360
Me.Invalidate()
End Set
End Property
Private my_xAngle As Integer

Property yAngle As Integer
Get
Return my_yAngle
End Get
Set(value As Integer)
my_yAngle = (value + 360) Mod 360
Me.Invalidate()
End Set
End Property
Private my_yAngle As Integer

Property zAngle As Integer
Get
Return my_zAngle
End Get
Set(value As Integer)
my_zAngle = (value + 360) Mod 360
Me.Invalidate()
End Set
End Property
Private my_zAngle As Integer

Protected Overrides Sub OnMouseDown(e As System.Windows.Forms.MouseEventArgs)
If e.Button = Windows.Forms.MouseButtons.Left Then
MousePress = True
MousePosLast = e.Location
End If
MyBase.OnMouseDown(e)
End Sub
Private MousePress As Boolean = False
Protected Overrides Sub OnMouseUp(e As System.Windows.Forms.MouseEventArgs)
MousePress = False
MyBase.OnMouseUp(e)
End Sub

Protected Overrides Sub OnMouseMove(e As System.Windows.Forms.MouseEventArgs)
If MousePress Then
MouseMoveHorizontal = MousePosLast.X - e.X
MouseMoveVertical = MousePosLast.Y - e.Y
MousePosLast = e.Location

Dim xxAngle As Integer = (xAngle + 360) Mod 180
Dim yyAngle As Integer = (yAngle + 360) Mod 180

If (yyAngle > 135) Or (yyAngle <= 45) Then
yAngle += MouseMoveHorizontal
xAngle -= MouseMoveVertical
Else
xxAngle = (xAngle + 360) Mod 180
If (xxAngle > 135) Or (xxAngle <= 45) Then
yAngle += MouseMoveHorizontal
xAngle -= MouseMoveVertical
Else
xAngle += MouseMoveHorizontal
yAngle -= MouseMoveVertical
End If
End If

Me.Invalidate()
End If

MyBase.OnMouseMove(e)
End Sub
Private MouseMoveVertical As Integer = 0
Private MouseMoveHorizontal As Integer = 0
Private MousePosLast As Point

Protected Overrides Sub OnPaint(e As System.Windows.Forms.PaintEventArgs)
Dim t(8) As Point3D
Dim f(4) As Integer
Dim v As Point3D
Dim avgZ(6) As Double
Dim order(6) As Integer
Dim tmp As Double
Dim iMax As Integer

' Clear the window
e.Graphics.Clear(Color.LightBlue)

' Transform all the points and store them on the "t" array.
For i = 0 To 7
Dim b As Brush = New SolidBrush(Color.White)
v = m_vertices(i)
t(i) = v.RotateX(xAngle).RotateY(yAngle).RotateZ(zAngle)
t(i) = t(i).Project(Me.ClientSize.Width, Me.ClientSize.Height, 256, 4)
Next

' Compute the average Z value of each face.
For i = 0 To 5
avgZ(i) = (t(m_faces(i, 0)).Z + t(m_faces(i, 1)).Z + t(m_faces(i, 2)).Z + t(m_faces(i, 3)).Z) / 4.0
order(i) = i
Next

' Next we sort the faces in descending order based on the Z value.
' The objective is to draw distant faces first. This is called
' the PAINTERS ALGORITHM. So, the visible faces will hide the invisible ones.
' The sorting algorithm used is the SELECTION SORT.
For i = 0 To 4
iMax = i
For j = i + 1 To 5
If avgZ(j) > avgZ(iMax) Then
iMax = j
End If
Next
If iMax <> i Then
tmp = avgZ(i)
avgZ(i) = avgZ(iMax)
avgZ(iMax) = tmp

tmp = order(i)
order(i) = order(iMax)
order(iMax) = tmp
End If
Next

' Draw the faces using the PAINTERS ALGORITHM (distant faces first, closer faces last).
For i = 0 To 5
Dim points() As Point
Dim index As Integer = order(i)
points = New Point() {
New Point(CInt(t(m_faces(index, 0)).X), CInt(t(m_faces(index, 0)).Y)),
New Point(CInt(t(m_faces(index, 1)).X), CInt(t(m_faces(index, 1)).Y)),
New Point(CInt(t(m_faces(index, 2)).X), CInt(t(m_faces(index, 2)).Y)),
New Point(CInt(t(m_faces(index, 3)).X), CInt(t(m_faces(index, 3)).Y))
}
e.Graphics.FillPolygon(m_brushes(index), points)
Next

MyBase.OnPaint(e)
End Sub

End Class```

VB
```Public Class Point3D
Protected m_x As Double, m_y As Double, m_z As Double

Public Sub New(ByVal x As Double, ByVal y As Double, ByVal z As Double)
Me.X = x
Me.Y = y
Me.Z = z
End Sub

Public Property X() As Double
Get
Return m_x
End Get
Set(ByVal value As Double)
m_x = value
End Set
End Property

Public Property Y() As Double
Get
Return m_y
End Get
Set(ByVal value As Double)
m_y = value
End Set
End Property

Public Property Z() As Double
Get
Return m_z
End Get
Set(ByVal value As Double)
m_z = value
End Set
End Property

Public Function RotateX(ByVal angle As Integer) As Point3D
Dim rad As Double, cosa As Double, sina As Double, yn As Double, zn As Double

rad = angle * Math.PI / 180
cosa = Math.Cos(rad)
sina = Math.Sin(rad)
yn = Me.Y * cosa - Me.Z * sina
zn = Me.Y * sina + Me.Z * cosa
Return New Point3D(Me.X, yn, zn)
End Function

Public Function RotateY(ByVal angle As Integer) As Point3D
Dim rad As Double, cosa As Double, sina As Double, Xn As Double, Zn As Double

rad = angle * Math.PI / 180
cosa = Math.Cos(rad)
sina = Math.Sin(rad)
Zn = Me.Z * cosa - Me.X * sina
Xn = Me.Z * sina + Me.X * cosa

Return New Point3D(Xn, Me.Y, Zn)
End Function

Public Function RotateZ(ByVal angle As Integer) As Point3D
Dim rad As Double, cosa As Double, sina As Double, Xn As Double, Yn As Double

rad = angle * Math.PI / 180
cosa = Math.Cos(rad)
sina = Math.Sin(rad)
Xn = Me.X * cosa - Me.Y * sina
Yn = Me.X * sina + Me.Y * cosa
Return New Point3D(Xn, Yn, Me.Z)
End Function

Public Function Project(ByVal viewWidth, ByVal viewHeight, ByVal fov, ByVal viewDistance)
Dim factor As Double, Xn As Double, Yn As Double
factor = fov / (viewDistance + Me.Z)
Xn = Me.X * factor + viewWidth / 2
Yn = Me.Y * factor + viewHeight / 2
Return New Point3D(Xn, Yn, Me.Z)
End Function
End Class```

v5
Comments
Knight school 28-Oct-17 12:01pm
Sorry for the delay & many thanks for the solution. I have been away on holiday & I was on strict order no laptop & on top of that my PC has decided to have windows meltdown. I will be up & running soon & will test the update.
Many thanks (it was making me mad).
Ralf Meier 28-Oct-17 18:11pm
I'm glad to hear from you again and await your answer.
Knight school 29-Oct-17 10:21am
Many thanks.
One question is still bugging me is how to change the rotation point.
I did think I should just move the points to make the rotation point on the origin but this causes errors (i.e. cube shifts). Then I tried to correct it by rotating a virtual point (Same XYZ shift as move) but this seems to go completely wrong.

Any ideas?

Sorry the question after a question.
Ralf Meier 29-Oct-17 15:43pm
I'm not complete sure what you mean ... I suppose you mean this :
In the moment the 'Rotation-Point' lays in the Center of the cube. You want to move it outside ...? If I'm right I think you should add an Offset to the Points defined in m_vertices. The Offset must work with the Point3D.Project-Method. The Points from m_vertices are factors for the Display-Width.
But ... how do you want to move this Offset-Point ? Right Mousebutton and MouseMove ...?
Knight school 30-Oct-17 16:06pm
Sorry for once again not explaining the problem.
You are correct I want to rotate around a point that is not the Origin/Center point (i.e. one of the corners - I already have a way of snapping to a point which I will rotate it from. I have also got it to rotate around that point (As you pointed out offset the point/vertices but when I do this it makes the cube jump with the snapped corner where the origin/center used to be. What I am aiming to do is spin/rotate relative to the snapped point but not make the model jump but just rotate.
My thinking (also trying) is to have smooth rotation relative to the snapped point. I have tried to change the translateMatrix1.Translate including the new shift but this is where it all goes wrong.I can't seem to get over this is just shift-rotate- shift back.

once again sorry to add to the original question.

## Solution 1

```Sorry for not being clear.
You are correct the rotation point is not stated but it will be (until I can workout the shift relative to the different rotation point i.e. distance from drawn zero point & mouse rotation) the drawing zero point. The drawing zero point is positioned by Matrix Translate (& Scale is done also at this time).

<pre lang="vb">Dim translateMatrix1 As New Matrix
translateMatrix1.Scale(Scale_Path, Scale_Path, MatrixOrder.Append)
translateMatrix1.Translate(Offset_X_Path, Offset_Y_Path, MatrixOrder.Append)
Temp_Path.Transform(translateMatrix1)```

I need to have the orbital roll relative to mouse move/gesture.

Comments
Richard Deeming 5-Oct-17 14:26pm
If you want to reply to a comment, use the "Reply" button next to that comment.

DO NOT post your reply as a "solution"!

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Top Experts
Last 24hrsThis month
 Pete O'Hanlon 40 RickZeeland 30 Member 16312379 10 Sandeep Mewara 5
 Pete O'Hanlon 905 OriginalGriff 800 Richard Deeming 715 merano99 345 Dave Kreskowiak 305

CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900