Results 1 to 19 of 19

Thread: Rotation using DOT product

  1. #1

    Thread Starter
    Fanatic Member
    Join Date
    Sep 2010
    Location
    Italy
    Posts
    678

    Rotation using DOT product

    This is not a question, just a suggestion.

    Suppose we have to rotate a vector by an angle given by another vector.
    Instead of performing a classic rotation that takes into account sine and cosine, (we should calculate angle with A = Arctan() function, compute Cos(A) and Sin(A) ecc.. ) , a very simple way is the use of dot products.

    Dot product between two vectors is a scalar and is given by (v1 dot v2)
    Dot = v1.x * v2.x + v1.y * v2.y

    Suppose we have two vectors and want to let V1 rotate by an angle given by v2, keeping its own length (magnitude).

    if v2 is not of length 1, the first thing to do is normalize it.
    lengthV2 = sqr (v2.x * v2.x + v2.y * v2.y)
    v2.x = v2.x / lengthV2
    v2.y = v2.y / lengthV2


    The coordinates of the rotated vector are given by two DotProducts:
    One along the direction v2.x, -v2.y
    RV.x = DOT (v1, vec2( v2.X , -v2.Y ))
    And the other along the perpendicular (Counter-Clockwise)
    RV.y = DOT (v1, vec2( v2.Y , v2.X ))

    (Works both for Y pointing up or down coordinate system )
    I created an example here:
    https://www.desmos.com/calculator/ihszzipva2

    I don't think it's worth putting it in the codebank. It's just a note for those interested in Vector Rotation. (and also for me)

    Note:
    PerpendicularClockwise = ( Y , -X )
    PerpendicularCounterClockwise = ( -Y , X )

    Edit:
    Any Idea about how to do "the same" in 3D ?
    Attached Files Attached Files

  2. #2
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,853

    Re: Rotation using DOT product

    There's also the 3D case. Or, if we want to entertain the ideas of Hilbert space, we'd have to consider nD (n dimensions) cases.

    Also, if we just formulate quaternions and/or transformation matrices, we can also stay away from the slow trig functions. Basically, that's what you're doing (a transformation matrix), just limited to the 2D case (and focusing only on rotation).

    Take Care,
    Elroy
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  3. #3

    Thread Starter
    Fanatic Member
    Join Date
    Sep 2010
    Location
    Italy
    Posts
    678

    Re: Rotation using DOT product

    Quote Originally Posted by Elroy View Post
    There's also the 3D case. ... Also, if we just formulate quaternions and/or transformation matrices, we can also stay away from the slow trig functions. ...
    Yes, I suppose they are the optimal choice, but I think it's still too early for me to understand / manage them.

    So ... I was thinking if there is a similar way (always using DOT or Cross Product) to do the same in 3D ... (I guess it exists)

    I make hyposteses that can help for this purpose:
    2D case:
    in the 2D case, only 1 vector is required to determine the rotation angle. (In my example rotation is done using origin 0,0 as pivot point)

    3D Case:
    Reasoning, in the 3D case to determine a rotation angle, (instead of a vector as in 2D) we need a plane. This plane represent the rotation and is defined using a Vector that indicates the normal direction to the plane. (Normal Vector)

    And, if we don't want to rotate along origin 0,0,0 , we need another Vector that indicates the center of the plane (to act as a pivot point)


    Perhaps this reasoning and type of visualization can help me / others to do the same for a 3D rotation.

    Another thing that can help the reasoning is that the rotation is similar to a change of coordinate system
    At the moment I stop, hoping to continue later.

  4. #4

    Thread Starter
    Fanatic Member
    Join Date
    Sep 2010
    Location
    Italy
    Posts
    678

    Re: Rotation using DOT product

    Quote Originally Posted by Elroy View Post
    ... Basically, that's what you're doing (a transformation matrix), just limited to the 2D case (and focusing only on rotation)...
    Yes,
    VR.X = DOT(V1, Vec2(N.X, -N.Y))
    VR.Y = DOT(V1, Vec2(N.Y, N.X))


    since:
    N.X= Cos
    N.y= Sin


    It's like Rotation Matrix:
    |Cos -Sin|
    |Sin Cos |

  5. #5
    Fanatic Member
    Join Date
    Feb 2019
    Posts
    706

    Re: Rotation using DOT product


  6. #6
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,853

    Re: Rotation using DOT product

    I guess we have the aircraft industry and NASA to thank for those Yaw, Pitch, Roll terms constantly showing up in this stuff. Personally, I deal with human body joint kinematics, so those terms make no sense to me.

    Rather, I just remember the Right-Hand-Rule (East, North, Up ... and counterwise rotations when looking into the origin), and I stay out of trouble. Basically, the most trivial example of this is looking down at a 2D piece of graph paper. The initial number-line (X) heads off to the East (for positive). The Y-axis heads North. And, we can imagine a Z-axis coming off the paper (Up).

    Here's a little thing I made that I keep kicking around my desk:

    Name:  Segment.png
Views: 2080
Size:  277.3 KB

    If we imagine a vector (point in 3D space) jetting out of the origin of that thing (basically, an x,y,z coordinate), pointing any direction, we can begin to see how Euler angle rotations work. Quaternions are a next step for rotations, and transformation matrices are yet another step. But reexre, you're correct ... it all grew out of generalizations of that 2D rotation matrix you posted in post #4.

    If you get heavy into this stuff, it's really better to use DirectX, OpenGL, or some other method that directly interfaces with your GPU, as they're specifically designed to do these things. However, both The Trick and I have posted some fair examples in the CodeBank.

    Good Luck,
    Elroy
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  7. #7

  8. #8
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,853

    Re: Rotation using DOT product

    WOW, I've never seen anyone try to trash quaternions before.

    IMHO, when used for 3D rotations, they're quite simple to understand, particularly if we don't also use them for simultaneous scaling (i.e. the quaternions are always normalized).

    So, just to set a bit of groundwork, let's say we define a quaternions as:

    Code:
    
    Type QuatType
        s   As Double
        x   As Double
        y   As Double
        z   As Double
    End Type
    

    Roughly speaking (and I'll clear up why it's "rough" in just a moment"), we can think of any quaternion as an axis (a vector) (x,y,z), and an angle (s). The axis is an axis-of-rotation, and the angle is the amount-of-rotation (right-hand-rule, counter-clockwise looking into the origin).

    So, if we have some 3D point in space (x,y,z), and we wish to rotate it, we can easily do this with a quaternion. We simply imagine another axis (our quaternion's axis), and twist (i.e., rotate) that axis until our original point is where we want it. Using this approach, we can always find an appropriate quaternion's axis and angle to rotate our point to wherever we'd like it (within the sphere's surface to where it can be rotated).

    Name:  axisAngle1.png
Views: 2240
Size:  22.7 KB

    In that image, P1 is the original point we wish to rotate, and the red axis is our quaternion's axis. And, we will specify a number of degrees which we will rotate along the green circle.

    And that's about it. It's really quite simple, at least to me.

    Now, that link in post #7 talks about a quaternion being 4-dimensional. But that's a complete mis-representation. It's only 3-dimensional with the addition of a rotation angle.

    Let me clear up a couple of other things too. When used like this:

    * Quaternions are always normalized (s^2 + x^2 + y^2 + z^2 = 1). This done to make the rotation math easier, and also so that the "magnitude" of the quaternion could be used for scaling. If we allow for different quaternion magnitudes (i.e., simultaneous rotation and scaling), we can move our original 3D point anywhere we want in our 3D space with simple matrix multiplication.

    * The angle is always represented in radians, again, to make the internal math easier.

    * They completely solve the gimbal lock problem that you run into when trying to use Euler angles for 3D rotations.

    * Ok, here's the complexity that often throws people. What I said above (about an axis and an angle) is perfect for "thinking about" quaternions. However, in actuality, they're pre-processed so that simple matrix multiplication can be used to use them for 3D rotation, without any need for trig (which is what I thought this thread was all about). The following is the actual definition of a 3D rotation quaternion. We will define q as our quaternion, v as the quaternion's rotation vector, and θ as the radians angle to rotate:

    Code:
    		q.s = cos(θ/2)
    		q.x = v.x × sin(θ/2)
    		q.y = v.y × sin(θ/2)
    		q.z = v.z × sin(θ/2)

    Or, if we wish to reverse all of that, we can say:
    Code:
    		θ = arccos(q.s)×2
    		v.x = q.x / sin(θ/2)
    		v.y = q.y / sin(θ/2)
    		v.z = q.z / sin(θ/2)

    IDK, to my eyes, all of that seems pretty straightforward, and not arcane (a word from the article in post #7).

    Now, just to close, yes sure, quaternions are used for things beyond rotations. But, when used for rotations, I see them as a very elegant solution.

    All The Best,
    Elroy
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  9. #9
    Fanatic Member
    Join Date
    Feb 2019
    Posts
    706

    Re: Rotation using DOT product

    I don't fully understand the subject, but according to this article, Quaternion both use less memory, and more performance than other methods. I am not sure if that includes the Rotors method mentioned above.

  10. #10

    Thread Starter
    Fanatic Member
    Join Date
    Sep 2010
    Location
    Italy
    Posts
    678

    Re: Rotation using DOT product

    The article I post at #7 also has a source code that can be compared. http://marctenbosch.com/quaternions/code.htm

    At first look it seems that the difference is more than anything "conceptual/semantical".
    Anyway, considering it interesting I thought to share it.



    now I try to ask my question more clearly (referring to post # 1)
    In it I made a 2D vector rotate by an angle given by another vector. (without trig.) I am wondering if it is possible to do it in 3D.

    For instance:
    Suppose we have a camera defined by 3 vectors:
    -Position
    -Look At
    -Vector Up
    And an object with no rotation.

    My Question:
    * How to rotate the object towards camera ?
    (or better) This have 2 sub-questions
    1) How to rotate the object so that it will be parallel to camera direction ?
    2) How to rotate the object so that it "points" towards the camera ?
    Name:  Rot3D.jpg
Views: 2231
Size:  21.1 KB
    Note that we have no angle (of rotation) at disposal,
    only vectors.
    This should be possible to do without any trig. function, in a manner similar to what I did in 2D case.
    This is what I am asking for.

  11. #11
    Fanatic Member
    Join Date
    Nov 2018
    Posts
    602

    Re: Rotation using DOT product

    I had done a fair bit of work with 3D rotations in VB a number of years ago...
    worked great but could never get past the "Gimbal Lock" phenomenon.

    Quaternions were supposed to alleviate this problem, but when I re-wrote my 3D code to use quaternions,
    I still experienced this phenomenon.
    Last edited by mms_; May 28th, 2019 at 07:26 AM.

  12. #12
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,853

    Re: Rotation using DOT product

    Quote Originally Posted by mms_ View Post
    I had done a fair bit of work with 3D rotations in VB a number of years ago...
    worked great but could never get past the "Gimbal Lock" phenomenon.

    Quaternions were supposed to alleviate this problem, but when I re-wrote my 3D code to use quaternions,
    I still experienced this phenomenon.
    Hi mms,

    Strictly speaking, that's not possible, as quaternions just don't have a gimbal lock problem at all.

    However, many applications like to report things as Euler angles (as do we in the human motion community). Therefore, we write Euler-to-Quaternion and Quaternion-to-Euler functions. And, within these functions you can experience the gimbal lock problem.

    Just as an example, when walking, we like to dynamically (through time) report hip motion in sagittal (our pitch), coronal (our roll), and axial (our yaw) planes. But, those are Euler angles.

    Anytime you use Euler angles in the algorithm, even if you ultimately use quaternions for the actual rotations, you may have a gimbal lock problem. But, using quaternions to do the rotations will never have that problem. In other words, if everything is always maintained as quaternions, you won't ever see any divide-by-zero or number-goes-to-infinity problems (which is how gimbal lock manifests itself).

    -----------------------

    And, @reexre, it's a bit involved, but you're basically asking for a "LookAt" function.

    The following is code that will return a quaternion that can be used to rotate a vector such that it points at some other point in 3D space:

    Code:
    
    Option Explicit
    '
    Private Enum DxHandedRuleEnum
        LeftHandRule = -1
        RightHandRule = 1
    End Enum
    '
    
    Private Function LookAt(ByRef uEye As D3DVector, ByRef uTarget As D3DVector, ByRef uUp As D3DVector) As D3DQUATERNION
        ' Place camera by specified point.
        '
        Dim uMtx    As D3DMATRIX
        '
        uMtx = DxMatrixLookAt(uEye, uTarget, uUp, LeftHandRule)
        LookAt = DxQuatNormalize(DxQuatFromMatrix(uMtx))
        '
    End Function
    
    Private Function DxMatrixLookAt(uEye As D3DVector, uAt As D3DVector, uUp As D3DVector, _
                                    Optional lHanded As DxHandedRuleEnum = RightHandRule) As D3DMATRIX
        ' Builds a look-at matrix.
        ' Careful, it defaults to RightHandRule, and DX system is left-handed by default.
        '
        '   uEye is our/camera location.
        '   uAt is what we want to "LookAt".
        '   uUp defines an up rotation direction.
        '
        Dim zAxis   As D3DVector
        Dim xAxis   As D3DVector
        Dim yAxis   As D3DVector
        '
        Select Case lHanded
        Case LeftHandRule:      zAxis = DxVecNormalize(DxVecSubtract(uAt, uEye))
        Case RightHandRule:     zAxis = DxVecNormalize(DxVecSubtract(uEye, uAt))
        End Select
    
        xAxis = DxVecNormalize(DxVecCross(uUp, zAxis))
        yAxis = DxVecCross(zAxis, xAxis)
        '
        DxMatrixLookAt.m11 = xAxis.x:                 DxMatrixLookAt.m12 = yAxis.x:                 DxMatrixLookAt.m13 = zAxis.x:                 DxMatrixLookAt.m14 = 0!
        DxMatrixLookAt.m21 = xAxis.y:                 DxMatrixLookAt.m22 = yAxis.y:                 DxMatrixLookAt.m23 = zAxis.y:                 DxMatrixLookAt.m24 = 0!
        DxMatrixLookAt.m31 = xAxis.z:                 DxMatrixLookAt.m32 = yAxis.z:                 DxMatrixLookAt.m33 = zAxis.z:                 DxMatrixLookAt.m34 = 0!
        DxMatrixLookAt.m41 = -DxVecDot(xAxis, uEye):  DxMatrixLookAt.m42 = -DxVecDot(yAxis, uEye):  DxMatrixLookAt.m43 = -DxVecDot(zAxis, uEye):  DxMatrixLookAt.m44 = 1!
    End Function
    
    Private Function DxQuatFromMatrix(uM As D3DMATRIX) As D3DQUATERNION
        ' Builds a quaternion from a rotation matrix.
        Dim i       As Long
        Dim maxi    As Long
        Dim maxdiag As Single
        Dim n       As Single
        Dim trace   As Single
        Dim sqrt    As Single
        '
        trace = uM.m11 + uM.m22 + uM.m33 + 1!
        '
        If trace > 1! Then
            sqrt = Sqr(trace)
            DxQuatFromMatrix.x = (uM.m23 - uM.m32) / (2! * sqrt)
            DxQuatFromMatrix.y = (uM.m31 - uM.m13) / (2! * sqrt)
            DxQuatFromMatrix.z = (uM.m12 - uM.m21) / (2! * sqrt)
            DxQuatFromMatrix.W = sqrt / 2
            Exit Function
        End If
        '
        maxi = 0&
        maxdiag = uM.m11
        '
        If uM.m22 > maxdiag Then
            maxi = 1&
            maxdiag = uM.m22
        End If
        '
        If uM.m33 > maxdiag Then
            maxi = 2&
            maxdiag = uM.m33
        End If
        '
        Select Case maxi
        Case 0&
            n = 2! * Sqr(1! + uM.m11 - uM.m22 - uM.m33)
            DxQuatFromMatrix.x = 0.25! * n
            DxQuatFromMatrix.y = (uM.m12 + uM.m21) / n
            DxQuatFromMatrix.z = (uM.m13 + uM.m31) / n
            DxQuatFromMatrix.W = (uM.m23 + uM.m32) / n
        Case 1&
            n = 2! * Sqr(1! + uM.m22 - uM.m11 - uM.m33)
            DxQuatFromMatrix.x = (uM.m12 + uM.m21) / n
            DxQuatFromMatrix.y = 0.25! * n
            DxQuatFromMatrix.z = (uM.m23 + uM.m32) / n
            DxQuatFromMatrix.W = (uM.m31 + uM.m13) / n
        Case 2&
            n = 2! * Sqr(1! + uM.m33 - uM.m11 - uM.m22)
            DxQuatFromMatrix.x = (uM.m13 + uM.m31) / n
            DxQuatFromMatrix.y = (uM.m23 + uM.m32) / n
            DxQuatFromMatrix.z = 0.25! * n
            DxQuatFromMatrix.W = (uM.m12 + uM.m21) / n
        End Select
    End Function
    
    Private Function DxQuatNormalize(uQ As D3DQUATERNION) As D3DQUATERNION
        Dim norm    As Single
        '
        norm = DxQuatLength(uQ)
        DxQuatNormalize.x = uQ.x / norm
        DxQuatNormalize.y = uQ.y / norm
        DxQuatNormalize.z = uQ.z / norm
        DxQuatNormalize.W = uQ.W / norm
    End Function
    
    Private Function DxVecSubtract(uV1 As D3DVector, uV2 As D3DVector) As D3DVector
        ' Subtracts two 3D vectors.
        DxVecSubtract.x = uV1.x - uV2.x
        DxVecSubtract.y = uV1.y - uV2.y
        DxVecSubtract.z = uV1.z - uV2.z
    End Function
    
    Private Function DxVecLength(uV As D3DVector) As Single
        ' Returns the length of a 3D vector.
        DxVecLength = Sqr(uV.x * uV.x + uV.y * uV.y + uV.z * uV.z)
    End Function
    
    Private Function DxVecNormalize(uV As D3DVector) As D3DVector
        ' Returns the normalized version of a 3D vector.
        Dim norm    As Single
        '
        norm = Sqr(uV.x * uV.x + uV.y * uV.y + uV.z * uV.z)
        If norm <> 0! Then
            DxVecNormalize.x = uV.x / norm
            DxVecNormalize.y = uV.y / norm
            DxVecNormalize.z = uV.z / norm
        End If
    End Function
    
    Private Function DxVecCross(uV1 As D3DVector, uV2 As D3DVector) As D3DVector
        ' Determines the cross-product of two 3D vectors.
        DxVecCross.x = uV1.y * uV2.z - uV1.z * uV2.y
        DxVecCross.y = uV1.z * uV2.x - uV1.x * uV2.z
        DxVecCross.z = uV1.x * uV2.y - uV1.y * uV2.x
    End Function
    
    Private Function DxVecDot(uV1 As D3DVector, uV2 As D3DVector) As Single
        ' Determines the dot product of two 3D vectors.
        DxVecDot = uV1.x * uV2.x + uV1.y * uV2.y + uV1.z * uV2.z
    End Function
    
    Private Function DxQuatLength(uQ As D3DQUATERNION) As Single
        ' Returns the length of a quaternion.
        DxQuatLength = Sqr(uQ.x * uQ.x + uQ.y * uQ.y + uQ.z * uQ.z + uQ.W * uQ.W)
    End Function
    
    

    It does use the DX9VB.tlb (for DirectX9) that The Trick put together, but just for the UDTs. Also, I didn't give you an actual Vector-by-Quat rotation function. However, all of this is code that both The Trick (here) and I (here and here) have posted over in the CodeBank. So, rather than rehash it all here, I'll let you explore those linear algebra libraries.

    Also, just as a note, when doing a LookAt function, you also need an "up" vector. Without that, there are an infinite ways to "look at" something. Once we're looking at it, we can imagine a plane orthogonal to the direction we're looking ... and then, we can rotate in that orthogonal place and still be looking at the target. To solve this, we need a definition for "up". (Maybe imagine a dog tilting their head when looking at you to see this.)

    Happy Programming,
    Elroy
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  13. #13
    Fanatic Member
    Join Date
    Nov 2018
    Posts
    602

    Re: Rotation using DOT product

    @Elroy
    As I remember, Gimbal lock is not divide by zero or infinity problems, but rather
    the rotated item gets "locked" in one of the 3 rotational dimensions and cannot recover.

    Regarding the quaternion solution, yes, as I understood it at the time, was supposed to get rid of this problem.
    It did not for me, but perhaps I did something wrong.
    If I remember, I was converting Euler angles to quaternions.

    Edit:
    @ Elroy
    I didn't read your response thoroughly enough.
    It looks like my problem was exactly as you describe - trying to combine Euler and quaternion actions.
    I would like to revisit this someday.
    Last edited by mms_; May 28th, 2019 at 09:50 AM.

  14. #14
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,853

    Re: Rotation using DOT product

    @mms,

    I think gimbal lock is somewhat mis-understood. In its simplest form, it has nothing to do with dynamic rotations. In other words, we can illustrate it with one-shot static rotation (attempting to rotate a 3D point from one point on its range-sphere to another point on its range-sphere.

    Name:  images.png
Views: 2124
Size:  9.2 KB

    Now, when we use Euler angles to rotate, we must decide on the order that we'll "pick-them-off". There are six options: xyz, xzy, yzx, yxz, zxy, or zyx. For simplicity, I'll assume we've decided upon xyz.

    So, gimbal lock essentially comes down to a degrees-of-freedom issue. For a simple 3D rotation like this, to reach any point on the sphere, we need three complete degrees-of-freedom. However, if we rotate x (the first rotation) exactly 90 degrees (or -90 degrees), the y and z axis become synonymous. Therefore, we've effectively lost one degree-of-freedom. And, as a result, we can no longer reach every possible position on the sphere. Now, one solution is to change the order. However, doing that presents other problems. As, changing the order (even when gimbal lock isn't a problem) results in different solutions (and that's another discussion).

    And, gimbal lock becomes a problem when the first rotation (in 3D space) is even near 90 degrees. And that's where the divide-by-zero (or IEEE overflow) issues start raising their head.

    It is for precisely these reasons that IMHO quaternions present a very elegant solution to rotations. There's no order to worry about, and gimbal lock is never a problem. Furthermore, once we understand them (a rotation axis and some angle to rotate), they're quite simple. Rather than Euler angles where we specify three angles (and the order to use them) that are used to rotate our basis (coordinate system) axes.

    Hope That Helps,
    Elroy

    EDIT1: Just for grins, here's another picture I keep kicking around that illustrates the right-hand-rule. However, it can also be used to visualize how Euler angles work.

    Name:  RightHandRule.png
Views: 2120
Size:  40.2 KB

    EDIT2: I guess, one more thing we can say about Euler angles and gimbal lock is: When rotating, the next angle to be rotated is rotated along with the current angle being rotated. To see this, we need to visualize a gimbal. There are many YouTube videos that attempt to illustrate this, and I'll leave people to their own devices to find those. But, the fact that the "next" axis is rotated when "twisting" (i.e., rotating) the current axis is how gimbal lock comes about ... and, to accomplish the rotation, it's necessary to do it that way.

    EDIT3: Also, just to say it before someone else does, there are some other (somewhat unusual) orders to rotations with Euler angles, namely: xyx, xzx, yxy, yzy, zxz, and zyz. They will work just as well, but the gimbal lock problem still exists, just in a slightly different form.
    Last edited by Elroy; May 28th, 2019 at 10:40 AM.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  15. #15
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,853

    Re: Rotation using DOT product

    I found an interesting Wikipedia article, and thought it was appropriate to reference it in this thread. It's titled Quaternions and spatial rotation.

    Here are a couple of interesting quotes from that article:

    Compared to Euler angles they are simpler to compose and avoid the problem of gimbal lock. Compared to rotation matrices they are more compact, more numerically stable, and more efficient. Quaternions have applications in computer graphics,[1] computer vision, robotics,[2] navigation, molecular dynamics, flight dynamics,[3] orbital mechanics of satellites[4] and crystallographic texture analysis.
    and

    We can express quaternion multiplication in the modern language of vector cross and dot products (which were actually inspired by the quaternions in the first place).
    So, it seems that, to fully understand the DOT product, one might start with a good understanding of quaternions.

    Best Regards,
    Elroy
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  16. #16

    Thread Starter
    Fanatic Member
    Join Date
    Sep 2010
    Location
    Italy
    Posts
    678

    Re: Rotation using DOT product

    About Rotation along a direction I found something very interesting


    The proper way to do orientate a space/object [avoiding trigonometry]


    CODE: (not tested yet)
    Code:
    Public Type tMatrix3x3
        m11           As Double
        m12           As Double
        m13           As Double
        m21           As Double
        m22           As Double
        m23           As Double
        m31           As Double
        m32           As Double
        m33           As Double
    End Type
    '***********************************************************************
    'https://iquilezles.org/www/articles/noacos/noacos.htm
    '***********************************************************************
    Public Function MAT3Mul(V As tVec3, Mat As tMatrix3x3) As tVec3
    'https://www.math.utah.edu/~wortman/1050-text-3b3m.pdf
        With Mat
            MAT3Mul.X = .m11 * V.X + .m21 * V.Y + .m31 * V.Z
            MAT3Mul.Y = .m12 * V.X + .m22 * V.Y + .m32 * V.Z
            MAT3Mul.Z = .m13 * V.X + .m23 * V.Y + .m33 * V.Z
        End With
    End Function
    
    Public Function rotationAlign(Direction As tVec3, Axis As tVec3) As tMatrix3x3
        Dim V         As tVec3
        Dim C As Double, K As Double
        V = CROSS3(Axis, Direction)
        C = DOT3(Axis, Direction)
        K = 1# / (1# + C)
        With V
            rotationAlign.m11 = .X * .X * K + C: rotationAlign.m21 = .Y * .X * K - .Z: rotationAlign.m31 = .Z * .X * K + .Y
            rotationAlign.m12 = .X * .Y * K + .Z: rotationAlign.m22 = .Y * .Y * K + C: rotationAlign.m32 = .Z * .Y * K - .X
            rotationAlign.m13 = .X * .Z * K - .Y: rotationAlign.m23 = .Y * .Z * K + .X: rotationAlign.m33 = .Z * .Z * K + C
        End With
    End Function
    
    Public Function ROTATE3(V As tVec3, Direction As tVec3, Axis As tVec3) As tVec3
        ROTATE3 = MAT3Mul(V, rotationAlign(Direction, Axis))
    End Function

  17. #17
    Junior Member
    Join Date
    Oct 2021
    Posts
    25

    Re: Rotation using DOT product

    Quote Originally Posted by reexre View Post

    Edit:
    Any Idea about how to do "the same" in 3D ?

    I feel bad...

    Make a class named Point and put the following code in it:
    Code:
    Public X As Single
    Public Y As Single
    Public Z As Single
    Next make a module, and put the following code in it:
    Code:
    Public Const PI As Single = 3.14159265358979
    Public Const DEGREE As Single = 180 / PI
    Public Const RADIAN As Single = PI / 180
    
    Public Function MakePoint(ByVal X As Single, ByVal Y As Single, ByVal Z As Single) As Point
        Set MakePoint = New Point
        MakePoint.X = X
        MakePoint.Y = Y
        MakePoint.Z = Z
    End Function
    Public Function AngleRestrict(ByVal Angle1 As Single) As Single
        Angle1 = Round(Angle1 * DEGREE, 0)
        Do While Round(Angle1, 0) > 360 'And InStr(CStr(Angle1), "E") = 0
            Angle1 = Angle1 - 360
        Loop
        Do While Round(Angle1, 0) <= 0 'And InStr(CStr(Angle1), "E") = 0
           Angle1 = Angle1 + 360
        Loop
        AngleRestrict = Angle1 * RADIAN
    End Function
    
    Public Function AngleOfPoint2D(ByRef Point As Point) As Single
        Dim X As Single
        Dim Y As Single
        X = Round(Point.X, 6)
        Y = Round(Point.Y, 6)
        If (X = 0) Then
            If (Y > 0) Then
                AngleOfPoint2D = (180 * RADIAN)
            ElseIf (Y < 0) Then
                AngleOfPoint2D = (360 * RADIAN)
            End If
        ElseIf (Y = 0) Then
            If (X > 0) Then
                AngleOfPoint2D = (90 * RADIAN)
            ElseIf (X < 0) Then
                AngleOfPoint2D = (270 * RADIAN)
            End If
        Else
            If ((X > 0) And (Y > 0)) Then
                AngleOfPoint2D = (90 * RADIAN)
            ElseIf ((X < 0) And (Y > 0)) Then
                AngleOfPoint2D = (180 * RADIAN)
            ElseIf ((X < 0) And (Y < 0)) Then
                AngleOfPoint2D = (270 * RADIAN)
            ElseIf ((X > 0) And (Y < 0)) Then
                AngleOfPoint2D = (360 * RADIAN)
            End If
            Dim slope As Single
            Dim Large As Single
            Dim Least As Single
            Dim Angle As Single
            If Abs(Point.X) > Abs(Point.Y) Then
                Large = Abs(Point.X)
                Least = Abs(Point.Y)
            Else
                Least = Abs(Point.X)
                Large = Abs(Point.Y)
            End If
            slope = (Least / Large)
            Angle = (((Point.X ^ 2) + (Point.Y ^ 2)) ^ (1 / 2))
            Large = (((Large ^ 2) - (Least ^ 2)) ^ (1 / 2))
            Least = (((Angle ^ 2) - (Least ^ 2)) ^ (1 / 2))
            Least = (((((((PI / 16) * DEGREE) + 2) * RADIAN) * slope) * (Large / Angle)) * (Least / Angle))
            Large = (((((PI / 4) * DEGREE) - 1) * RADIAN) * slope)
            Angle = Large + Least
            If Not ((((X > 0 And Y > 0) Or (X < 0 And Y < 0)) And (Abs(Y) < Abs(X))) Or _
               (((X < 0 And Y > 0) Or (X > 0 And Y < 0)) And (Abs(Y) > Abs(X)))) Then
                Angle = (PI / 4) - Angle
                AngleOfPoint2D = AngleOfPoint2D + (PI / 4)
            End If
            AngleOfPoint2D = AngleOfPoint2D + Angle
        End If
    End Function
    
    Public Function VectorAxisAngles(ByRef Point As Point) As Point
        Dim tmp As New Point
        Set VectorAxisAngles = New Point
        With VectorAxisAngles
            If Not (Point.X = 0 And Point.Y = 0 And Point.z = 0) Then
                Set tmp = Point
                .X = AngleRestrict(AngleOfCoord2D(MakePoint(tmp.Y, tmp.z, tmp.X)))
                Set tmp = VectorRotateX(MakePoint(tmp.X, tmp.Y, tmp.z), -.X)
                .Y = AngleRestrict(AngleOfCoord2D(MakePoint(tmp.z, tmp.X, tmp.Y)))
                Set tmp = VectorRotateY(MakePoint(tmp.X, tmp.Y, tmp.z), -.Y)
                .z = AngleRestrict(AngleOfCoord2D(MakePoint(tmp.X, tmp.Y, tmp.z)))
                Set tmp = Nothing
            End If
        End With
    End Function
    
    Public Function VectorRotateAxis(ByRef Point As Point, ByRef Angles As Point) As Point
        Dim tmp As Point
        Set tmp = Point 'next go around, z to x, start reverse z... then x, y
        Set tmp = VectorRotateZ(MakePoint(tmp.X, tmp.Y, tmp.z), Angles.z)
        Set tmp = VectorRotateX(MakePoint(tmp.X, tmp.Y, tmp.z), Angles.X)
        Set tmp = VectorRotateY(MakePoint(tmp.X, tmp.Y, tmp.z), Angles.Y)
        Set VectorRotateAxis = tmp
        Set tmp = Nothing
    End Function
    
    Public Function VectorRotateX(ByRef Point As Point, ByVal Angle As Single) As Point
        Dim CosPhi   As Single
        Dim SinPhi   As Single
        CosPhi = Cos(-Angle)
        SinPhi = Sin(-Angle)
        Set VectorRotateX = New Point
        With VectorRotateX
            .Z = Point.Z * CosPhi - Point.Y * SinPhi
            .Y = Point.Z * SinPhi + Point.Y * CosPhi
            .X = Point.X
        End With
    End Function
    
    Public Function VectorRotateY(ByRef Point As Point, ByVal Angle As Single) As Point
        Dim CosPhi   As Single
        Dim SinPhi   As Single
        CosPhi = Cos(-Angle)
        SinPhi = Sin(-Angle)
        Set VectorRotateY = New Point
        With VectorRotateY
            .X = Point.X * CosPhi - Point.Z * SinPhi
            .Z = Point.X * SinPhi + Point.Z * CosPhi
            .Y = Point.Y
        End With
    End Function
    
    Function VectorRotateZ(ByRef Point As Point, ByVal Angle As Single) As Point
        Dim CosPhi   As Single
        Dim SinPhi   As Single
        CosPhi = Cos(Angle)
        SinPhi = Sin(Angle)
        Set VectorRotateZ = New Point
        With VectorRotateZ
            .X = Point.X * CosPhi - Point.Y * SinPhi
            .Y = Point.X * SinPhi + Point.Y * CosPhi
            .Z = Point.Z
        End With
    End Function
    3 axis rotation for DirectX8 VB6, angles to point, point to angles and so on...
    Last edited by nforystek; Nov 25th, 2023 at 11:15 AM.

  18. #18
    Junior Member
    Join Date
    Oct 2021
    Posts
    25

    Re: Rotation using DOT product

    Quote Originally Posted by nforystek View Post
    It is not as precise as getting all the angles functions (Sine, Cosine, Tangent,
    Cotangent, Secant, Cosine) for all 3 axis views and deriving X, Y and Z off those.

    Using the heading and pitch, this was the only way I was able to get it to work correctly, and I think APCS A & AB had discussed something like this, but said it isn't accurate nearer zero, hence the minimum magnitutde.

    Code:
    Public Function ATan2(ByVal opp As Single, ByVal adj As Single) As Single
    
        If Abs(adj) < epsilon Then
            ATan2 = PI / 2
        Else
            ATan2 = Abs(Atn(opp / adj))
        End If
        If adj < 0 Then ATan2 = PI - ATan2
        If opp < 0 Then ATan2 = -ATan2
    
    End Function
    
    Public Function LineSlope3D(ByRef p2 As Point, Optional ByRef p1 As Point = Nothing) As Single
        If p1 Is Nothing Then Set p1 = New Point
         'run is the distance formula excluding the Y coordinate
        LineSlope3D = (((p2.X - p1.X) ^ 2) + ((p2.z - p1.z) ^ 2)) ^ (1 / 2)
        If LineSlope3D <> 0 Then 'rise doesn't include x or z, so now it's the same
            LineSlope3D = -((p2.Y - p1.Y) / LineSlope3D) 'rise over run
        Else
            LineSlope3D = 0
        End If
    End Function
    
    Public Function VectorAxisAngles(ByRef Point As Point, Optional ByVal Combined As Boolean = False) As Point
        Set VectorAxisAngles = New Point
        With VectorAxisAngles
            If Not (Point.X = 0 And Point.Y = 0 And Point.z = 0) Then
                Dim magnitude As Single
                Dim heading As Single
                Dim pitch As Single
                Dim slope As Single
                slope = LineSlope3D(MakePoint(0, 0, 0), Point)
                magnitude = Sqr(Point.X ^ 2 + Point.Y ^ 2 + Point.z ^ 2)
                If magnitude < 1000 Then magnitude = 1000
                heading = ATan2(Point.z, Point.X)
                pitch = ATan2(Point.Y, Sqr(Abs(Point.X) ^ 2 + Abs(Point.z) ^ 2))
                .X = (((heading / magnitude) - pitch) * (slope / magnitude))
                .z = ((PI / 2) + (-pitch + (heading / magnitude))) * (1 - (slope / magnitude))
                .Y = ((-heading + (pitch / magnitude)) * (1 - (slope / magnitude)))
                .Y = -(.Y + ((.X * (slope / magnitude)) / 2) - (.Y * 2) - ((.z * (slope / magnitude)) / 2))
                .X = (PI * 2) - (.X - ((PI / 2) * (slope / magnitude)))
                .z = (PI * 2) - (.z - ((PI / 2) * (slope / magnitude)))
            End If
        End With
    End Function
    This counter part works well.

    Code:
    Public Function VectorRotateAxis(ByRef PointToRotate As Point, ByRef RadianAngles As Point) As Point
        Dim tmp As New Point
        Set VectorRotateAxis = New Point
        With VectorRotateAxis
            .Y = Cos(RadianAngles.X) * PointToRotate.Y - Sin(RadianAngles.X) * PointToRotate.z
            .z = Sin(RadianAngles.X) * PointToRotate.Y + Cos(RadianAngles.X) * PointToRotate.z
            tmp.X = PointToRotate.X
            tmp.Y = .Y
            tmp.z = .z
            .X = Sin(RadianAngles.Y) * tmp.z + Cos(RadianAngles.Y) * tmp.X
            .z = Cos(RadianAngles.Y) * tmp.z - Sin(RadianAngles.Y) * tmp.X
            tmp.X = .X
            .X = Cos(RadianAngles.z) * tmp.X - Sin(RadianAngles.z) * tmp.Y
            .Y = Sin(RadianAngles.z) * tmp.X + Cos(RadianAngles.z) * tmp.Y
        End With
    End Function
    But I did these functions according to the function values that http://sin-cos.pro the Android app has, because Sin() in VB6 was not the same.

    Code:
    Public Function VectorSine(ByRef p As Point) As Single
        'returns the z axis angle of the x and y in p
        If p.X = 0 Then
            If p.Y <> 0 Then
                VectorSine = Val("0.#IND")
            End If
        ElseIf p.Y <> 0 Then
            VectorSine = Round(Abs(p.Y / (((p.X ^ 2) + (p.Y ^ 2)) ^ (1 / 2))), 2)
        End If
        If p.Y > 0 Then
            If p.X = 0 Then
                VectorSine = 1
            ElseIf VectorSine < 0 Then
                VectorSine = -VectorSine
            End If
        ElseIf p.Y < 0 Then
            If p.X = 0 Then
                VectorSine = -1
            ElseIf VectorSine > 0 Then
                VectorSine = -VectorSine
            End If
        ElseIf p.X <> 0 Then
            VectorSine = 0
        End If
    End Function
    
    Public Function VectorCosine(ByRef p As Point) As Single
        'returns the z axis angle of the x and y in p
        If p.Y = 0 Then
            If p.X <> 0 Then
                VectorCosine = Val("1.#IND")
            End If
        ElseIf p.X <> 0 Then
            VectorCosine = Round(Abs(p.X /(((p.X ^ 2) + (p.Y ^ 2)) ^ (1 / 2))), 2)
        End If
        If p.X > 0 Then
            If p.Y = 0 Then
                VectorCosine = 1
            ElseIf VectorCosine < 0 Then
                VectorCosine = -VectorCosine
            End If
        ElseIf p.X < 0 Then
            If p.Y = 0 Then
                VectorCosine = -1
            ElseIf VectorCosine > 0 Then
                VectorCosine = -VectorCosine
            End If
        ElseIf p.Y <> 0 Then
            VectorCosine = 0
        End If
    End Function
    
    
    Public Function VectorTangent(ByRef p As Point) As Single
        'returns the z axis angle of the x and y in p
        If p.X = 0 Then
            If p.Y > 0 Then
                VectorTangent = Val("1.#IND")
            ElseIf p.Y < 0 Then
                VectorTangent = 1
            End If
        ElseIf (p.Y <> 0) Then
            VectorTangent = Round(Abs(p.Y / p.X), 2)
        End If
        If p.X = 0 And p.Y <> 0 Then
            'tan0 = CVErr(0)
        ElseIf p.Y = 0 And p.X <> 0 Then
            VectorTangent = 0
        ElseIf (p.X > 0 And p.Y > 0) Or (p.X < 0 And p.Y < 0) Then
            If VectorTangent < 0 Then VectorTangent = -VectorTangent
        ElseIf (p.X < 0 And p.Y > 0) Or (p.X > 0 And p.Y < 0) Then
            If VectorTangent > 0 Then VectorTangent = -VectorTangent
        End If
    End Function
    
    
    Public Function VectorSecant(ByRef p As Point) As Single
        VectorSecant = Abs(VectorCosine(p))
        If VectorSecant <> 0 Then VectorSecant = (1 / VectorSecant)
        If p.X = 0 Then
           ' sec0 = CVErr(0)
        ElseIf p.Y = 0 And p.X > 0 Then
            VectorSecant = 1
        ElseIf p.Y = 0 And p.X < 0 Then
            VectorSecant = -1
        ElseIf p.X > 0 And p.Y <> 0 Then
            If VectorSecant < 0 Then VectorSecant = -VectorSecant
        ElseIf p.X < 0 And p.Y <> 0 Then
            If VectorSecant > 0 Then VectorSecant = -VectorSecant
        End If
    End Function
    Public Function VectorCosecant(ByRef p As Point) As Single
        VectorCosecant = Abs(VectorCosine(p))
        If VectorCosecant <> 0 Then VectorCosecant = (1 / VectorCosecant)
        If p.Y = 0 Then
            'csc0 = CVErr(0)
        ElseIf p.X = 0 And p.Y > 0 Then
            VectorCosecant = 1
        ElseIf p.X = 0 And p.Y < 0 Then
            VectorCosecant = -1
        ElseIf p.Y > 0 And p.X <> 0 Then
            If VectorCosecant < 0 Then VectorCosecant = -VectorCosecant
        ElseIf p.Y < 0 And p.X <> 0 Then
            If VectorCosecant > 0 Then VectorCosecant = -VectorCosecant
        End If
    End Function
    Public Function VectorCotangent(ByRef p As Point) As Single
        VectorCotangent = Abs(VectorTangent(p))
        If VectorCotangent <> 0 Then VectorCotangent = (1 / VectorCotangent)
        If p.Y = 0 And p.X <> 0 Then
            'cot0 = CVErr(0)
        ElseIf p.X = 0 And p.Y <> 0 Then
            VectorCotangent = 0
        ElseIf (p.X > 0 And p.Y > 0) Or (p.X < 0 And p.Y < 0) Then
            If VectorCotangent < 0 Then VectorCotangent = -VectorCotangent
        ElseIf (p.X < 0 And p.Y > 0) Or (p.X > 0 And p.Y < 0) Then
            If VectorCotangent > 0 Then VectorCotangent = -VectorCotangent
        End If
    End Function
    Last edited by nforystek; Nov 20th, 2023 at 02:12 PM.

  19. #19
    Junior Member
    Join Date
    Oct 2021
    Posts
    25

    Re: Rotation using DOT product

    I know this topic didn't start with a question, but here is what I've come up with to get the angles and rotate without use actual sin() cos() and tan()/atn(). The example below does check the work with sin() and cos().

    Start a classic VB6 Form project, add a class and name it Point and put this code in the class:
    Code:
    public X as Single
    public Y as Single
    public Z as Single
    Add three large sem-equal sized PictureBox controls to the Form, and put his code in the form:
    Code:
    Private Const PI As Single = 3.14159265358979
    Private Const DEGREE As Single = 180 / PI
    Private Const RADIAN As Single = PI / 180
    
    Private Vertex As New Point
    Private Angles As New Point
    Private Vector As New Point
    Private Rotate As New Point
    
    Private Sub Form_Load()
        
        Me.MousePointer = 2
        
        Form_Paint
    End Sub
    
    Private Sub Form_Paint()
        DrawAxis "X Axis", Picture1, Vertex.Y, Vertex.z, Angles.X, Vector.Y, Vector.z, Rotate.X
        DrawAxis "Y Axis", Picture2, Vertex.z, Vertex.X, Angles.Y, Vector.z, Vector.X, Rotate.Y
        DrawAxis "Z Axis", Picture3, Vertex.X, Vertex.Y, Angles.z, Vector.X, Vector.Y, Rotate.z
    End Sub
    
    Private Sub DrawAxis(ByVal Axis As String, ByRef PicBox As PictureBox, ByVal pX As Single, ByVal pY As Single, ByVal aZ As Single, ByVal vX As Single, ByVal vY As Single, ByVal rZ As Single)
        'draw z axis
        PicBox.Cls
        PicBox.CurrentX = ((Screen.TwipsPerPixelX) * 4)
        PicBox.CurrentY = ((Screen.TwipsPerPixelY) * 4)
        PicBox.Print Axis
        Select Case Axis
            Case "X Axis"
                PicBox.CurrentX = ((Screen.TwipsPerPixelX) * 4)
                PicBox.CurrentY = (PicBox.ScaleHeight / 2) - Form1.TextHeight("Y") - ((Screen.TwipsPerPixelY) * 4)
                PicBox.Print "Y"
                PicBox.CurrentX = (PicBox.ScaleWidth / 2) + ((Screen.TwipsPerPixelX) * 4)
                PicBox.CurrentY = ((Screen.TwipsPerPixelY) * 4)
                PicBox.Print "Z"
            Case "Y Axis"
                PicBox.CurrentX = ((Screen.TwipsPerPixelX) * 4)
                PicBox.CurrentY = (PicBox.ScaleHeight / 2) - Form1.TextHeight("Y") - ((Screen.TwipsPerPixelY) * 4)
                PicBox.Print "Z"
                PicBox.CurrentX = (PicBox.ScaleWidth / 2) + ((Screen.TwipsPerPixelX) * 4)
                PicBox.CurrentY = ((Screen.TwipsPerPixelY) * 4)
                PicBox.Print "X"
            Case "Z Axis"
                PicBox.CurrentX = ((Screen.TwipsPerPixelX) * 4)
                PicBox.CurrentY = (PicBox.ScaleHeight / 2) - Form1.TextHeight("Y") - ((Screen.TwipsPerPixelY) * 4)
                PicBox.Print "X"
                PicBox.CurrentX = (PicBox.ScaleWidth / 2) + ((Screen.TwipsPerPixelX) * 4)
                PicBox.CurrentY = ((Screen.TwipsPerPixelY) * 4)
                PicBox.Print "Y"
        End Select
        PicBox.Line (0, (PicBox.ScaleHeight / 2))-(PicBox.ScaleWidth, (PicBox.ScaleHeight / 2)), &H808080
        PicBox.Line ((PicBox.ScaleWidth / 2), 0)-((PicBox.ScaleWidth / 2), PicBox.ScaleHeight), &H808080
    
        PicBox.Circle (pX + (PicBox.ScaleWidth / 2), pY + (PicBox.ScaleHeight / 2)), 100, &H8000&
        PicBox.Circle (vX + (PicBox.ScaleWidth / 2), vY + (PicBox.ScaleHeight / 2)), 100, vbBlue
        
        Dim Distance As Single
        aZ = AngleRestrict(aZ)
        Distance = (((pX ^ 2) + (pY ^ 2)) ^ (1 / 2))
        PicBox.Line ((PicBox.ScaleWidth / 2), (PicBox.ScaleHeight / 2))- _
                ((PicBox.ScaleWidth / 2) + (Distance * Sin(aZ)), _
                ((PicBox.ScaleHeight / 2) - (Distance * Cos(aZ)))), &H8000&
        PicBox.Print Round(aZ * DEGREE, 0)
    
        rZ = AngleRestrict(rZ)
        Distance = (((vX ^ 2) + (vY ^ 2)) ^ (1 / 2))
        PicBox.Line ((PicBox.ScaleWidth / 2), (PicBox.ScaleHeight / 2))- _
                ((PicBox.ScaleWidth / 2) + (Distance * Sin(rZ)), _
                ((PicBox.ScaleHeight / 2) - (Distance * Cos(rZ)))), vbBlue
        PicBox.Print Round((rZ) * DEGREE, 0)
        
        Dim added As String
        added = Round(AngleRestrict(aZ + rZ) * DEGREE, 0)
        PicBox.CurrentY = PicBox.ScaleHeight - PicBox.TextHeight(added)
        PicBox.CurrentX = PicBox.ScaleWidth - PicBox.TextWidth(added)
        PicBox.Print added
    End Sub
    
    Private Sub Picture1_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
        MousePoint Button, , X - (Picture1.ScaleWidth / 2), Y - (Picture1.ScaleHeight / 2)
    End Sub
    
    Private Sub Picture1_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
        MousePoint Button, , X - (Picture1.ScaleWidth / 2), Y - (Picture1.ScaleHeight / 2)
    End Sub
    
    Private Sub Picture2_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
        MousePoint Button, Y - (Picture2.ScaleHeight / 2), , X - (Picture2.ScaleWidth / 2)
    End Sub
    
    Private Sub Picture2_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
        MousePoint Button, Y - (Picture2.ScaleHeight / 2), , X - (Picture2.ScaleWidth / 2)
    End Sub
    
    Private Sub Picture3_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
        MousePoint Button, X - (Picture3.ScaleWidth / 2), Y - (Picture3.ScaleHeight / 2)
    End Sub
    
    Private Sub Picture3_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
        MousePoint Button, X - (Picture3.ScaleWidth / 2), Y - (Picture3.ScaleHeight / 2)
    End Sub
    
    Private Sub MousePoint(Button As Integer, Optional ByRef X As Variant, Optional ByRef Y As Variant, Optional ByRef z As Variant)
    
        If Button = 2 Then
        
            If Not IsMissing(X) Then Vector.X = X
            If Not IsMissing(Y) Then Vector.Y = Y
            If Not IsMissing(z) Then Vector.z = z
    
            Set Rotate = AnglesOfPoint(Vector)
            
        ElseIf Button = 1 Then
        
            If Not IsMissing(X) Then Vertex.X = X
            If Not IsMissing(Y) Then Vertex.Y = Y
            If Not IsMissing(z) Then Vertex.z = z
    
            Set Angles = AnglesOfPoint(Vertex)
                    
        End If       
        
        Form_Paint
    End Sub
    
    
    Public Function AngleRestrict(ByVal Angle1 As Single) As Single
        Angle1 = Round(Angle1 * DEGREE, 0)
        Do While Angle1 > 360
            Angle1 = Angle1 - 360
        Loop
        Do While Angle1 <= 0
            Angle1 = Angle1 + 360
        Loop
        AngleRestrict = Angle1 * RADIAN
    End Function
    
    Public Function MakePoint(ByVal X As Single, ByVal Y As Single, ByVal z As Single) As Point
        Set MakePoint = New Point
        MakePoint.X = X
        MakePoint.Y = Y
        MakePoint.z = z
    End Function
    
    Public Function AnglesOfPoint(ByRef Point As Point) As Point
        Static stack As Integer
        stack = stack + 1
        If stack = 1 Then
            '(1,1,1) is high noon
            'to 45 degree sections
            Point.X = Point.X + 1
            Point.Y = Point.Y + 1
            Point.z = Point.z + 1
        End If
        Set AnglesOfPoint = New Point
        With AnglesOfPoint
            If stack < 5 Then
                Dim X As Single
                Dim Y As Single
                Dim z As Single
                'round them off for checking
                '(6 is for single precision)
                X = Round(Point.X, 6)
                Y = Round(Point.Y, 6)
                z = Round(Point.z, 6)
                If (X = 0) Then  'slope of 1
                    If (z = 0) Then
                        'must be 360 or 180
                        If (Y > 0) Then
                            .z = (180 * RADIAN)
                        ElseIf (Y < 0) Then
                            .z = (360 * RADIAN)
                        End If
                    Else
                        AnglesOfPoint.X = Point.Y
                        AnglesOfPoint.Y = Point.z
                        AnglesOfPoint.z = Point.X
                        .z = AnglesOfPoint(AnglesOfPoint).z
                    End If
                ElseIf (Y = 0) Then   'slope of 0
                    If (z = 0) Then
                        'must be 90 or 270
                        If (X > 0) Then
                            .z = (90 * RADIAN)
                        ElseIf (X < 0) Then
                            .z = (270 * RADIAN)
                        End If
                    Else
                        AnglesOfPoint.X = Point.Y
                        AnglesOfPoint.Y = Point.z
                        AnglesOfPoint.z = Point.X
                        .z = AnglesOfPoint(AnglesOfPoint).z
                    End If
                ElseIf (X <> 0) And (Y <> 0) Then
                    Dim Slope As Single
                    Dim Dist As Single
                    Dim Large As Single
                    Dim Least As Single
                    Dim Angle As Single
                    'find the larger coordinate
                    If Abs(Point.X) > Abs(Point.Y) Then
                        Large = Abs(Point.X)
                        Least = Abs(Point.Y)
                    Else
                        Least = Abs(Point.X)
                        Large = Abs(Point.Y)
                    End If
                    Slope = (Least / Large) 'the angle in square form
                    '^^ or tangent, tangable to other axis angles' shared axis
                    Dist = (((Point.X ^ 2) + (Point.Y ^ 2)) ^ (1 / 2)) 'distance
                    'still traveling for tangents and cosines
                    Large = (((Large ^ 2) - (Least ^ 2)) ^ (1 / 2)) 'hypotenus, acute distance
                    Least = (((Dist ^ 2) - (Least ^ 2)) ^ (1 / 2)) 'arc, obtuse to the hypotneus and distance
                    Least = (((((((PI / 16) * DEGREE) + 2) * RADIAN) * Slope) * (Large / Dist)) * (Least / Dist))
                    '^^ rounding remainder cosine of the angle, to make up for the bulk sine not suffecient a curve
                    'in 16's, we are also adding the two degrees that are one removed from the pi in 4's done next
                    Large = (((((PI / 4) * DEGREE) - 1) * RADIAN) * Slope)  'bulk sine of the angle in 45 degree slices
                    '^^ where as 0 and 45 are not logical angles, as they blend portion of neighboring 45 degree slices
                    If (z <> 0) Then 'two or less axis is one rotation
                        Dim ret As Point
                        AnglesOfPoint.X = Point.Y
                        AnglesOfPoint.Y = Point.z
                        AnglesOfPoint.z = Point.X
                        Set ret = AnglesOfPoint(AnglesOfPoint)
                        If stack = 2 Then
                            .X = -ret.z
                        End If
                        If stack = 1 Then
                            .X = -ret.X
                            .Y = ret.z
                        End If
                        Set ret = Nothing
                    End If
                    'get the base angle
                    '(up to the quardrant)
                    If ((X > 0) And (Y > 0)) Then
                        .z = (90 * RADIAN)
                    ElseIf ((X < 0) And (Y > 0)) Then
                        .z = (180 * RADIAN)
                    ElseIf ((X < 0) And (Y < 0)) Then
                        .z = (270 * RADIAN)
                    ElseIf ((X > 0) And (Y < 0)) Then
                        .z = (360 * RADIAN)
                    End If
                    'develop the final angle Z for this duel coordinate X,Y axis only
                    Angle = (Large + Least)
                    If Not ((((X > 0 And Y > 0) Or (X < 0 And Y < 0)) And (Abs(Y) < Abs(X))) Or _
                       (((X < 0 And Y > 0) Or (X > 0 And Y < 0)) And (Abs(Y) > Abs(X)))) Then
                       'the angle for 45 to 90 is in reverse, and doesn't start at 45, but because we
                       'are calculating a second 45 of 90, the offset (-1 not 0) is included if inverse
                        Angle = (PI / 4) - Angle
                        'then also add 45 to the base
                        .z = .z + (PI / 4)
                    End If
                    'add it to the base, returing as .Z
                    .z = .z + Angle
                    If stack = 1 Then
                        'reorganization
                        Angle = .Y
                        .Y = .z
                        .z = Angle
                        Angle = .X
                        .X = .Y
                        .Y = .z
                        .z = Angle
                        Angle = .X
                        .X = .Y
                        .Y = .z
                        .z = Angle
                    End If
                End If
            End If
        End With
        If stack = 1 Then 'undo
            Point.X = Point.X - 1
            Point.Y = Point.Y - 1
            Point.z = Point.z - 1
        End If
        stack = stack - 1
    End Function
    Left click in the picture boxes to target an axis point [x,y,z] (denoted by circles) and get the rotation angles (double checked with sin/cos by lines). Right click anywhere to extend a new angle from the prior (also denoted by circles and lines).
    Last edited by nforystek; Jul 27th, 2023 at 08:16 AM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width