Click here to Skip to main content
15,943,245 members
Please Sign up or sign in to vote.
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?

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
 
Share this answer
 
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.
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.
 
Share this answer
 
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)



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