Post

 Resources 

Console

Home | Profile | Active Topics | Members | Search | FAQ
Username:
Password:
Save Password
Forgot your Password?

 All Forums
 VBGamer
 VBGamer
 Creating a better GetRotation function!
 New Topic  Reply to Topic
 Printer Friendly
Author Previous Topic Topic Next Topic  

cbx
Swordmaster

Canada
296 Posts

Posted - Jul 24 2004 :  01:27:03 AM  Show Profile  Visit cbx's Homepage  Send cbx an ICQ Message  Click to see cbx's MSN Messenger address  Send cbx a Yahoo! Message  Reply with Quote
OK, I have this code I have been using that I wrote my self some time ago (aka vb5 era) and have been using it ever since. It works,... but it's rather messy means of calculation and slow to boot!. I have left it alone until now (If it ain't broke don't fix it!) but now I would like to find a better algorithmic version of my GetRotation function. So my question or rather request is that if anyone out there can provide a function that can calculate the angle between two 2D points could you please post it on this thread so I can stop using this god awfull contraption I have been using for so long... Also the GetRotation function you provide must return a single that represents either a degree or a radian. It must also be contained within a single function and not call any outside methods. And lastly the code can be written in either vb5/6 or vb.net code. Although I prefer vb.net The code below was written in vb.net. If anyone needs help understanding the code below just let me know and I will do my best to describe it.


Public Shared Function GetRotation(ByVal Source As Vector2, ByVal Destination As Vector2) As Single
        Dim Angle As Single
        Angle = GetAngle(Source, Destination)  
        Return CorrectDegree(Source, Destination, Angle)  
    End Function
  
Public Shared Function GetSlope(ByVal Source As Vector2, ByVal Destination As Vector2) As Single
        Return Math.Abs(Destination.Y - Source.Y) / Math.Abs(Destination.X - Source.X)  
    End Function
  
    Public Shared Function GetAngle(ByVal Source As Vector2, ByVal Destination As Vector2) As Single
        Dim Slope, Ang As Single
  
        Slope = GetSlope(Source, Destination)  
        Ang = CSng(Math.Atan(Slope))  
        Return Ang  
    End Function
  
    Public Shared Function CorrectDegree(ByVal Source As Vector2, ByVal Destination As Vector2, ByVal Angle As Single) As Single
        If Destination.Y < Source.Y Then
            If Destination.X < Source.X Then ' upleft  
                Return RadianToDegree(Angle) + 180  
            Else                 ' upright  
                Return -RadianToDegree(Angle) + 360  
            End If
        Else
            If Destination.X < Source.X Then ' low left  
                Return -RadianToDegree(Angle) + 180  
            Else       'low right  
                ' do nothing  
                Return RadianToDegree(Angle)  
            End If
        End If
    End Function



Created by: X
http://www.createdbyx.com/

Edited by - cbx on Jul 24 2004 02:13:00 AM

Eric Coleman
Gladiator

USA
811 Posts

Posted - Jul 24 2004 :  1:34:07 PM  Show Profile  Visit Eric Coleman's Homepage  Reply with Quote
Your code doesn't return the correct answer for the angle between two vectors. Here is a sample project that demonstrates the problem.

If you use the vectors <1,0> and <1,1> your code generates an error, so I used <1,0> and <2,2>, which should return the same angle, and your code generates the wrong value. The sample program also shows another way of calculating the angle between two vectors and compares your funtion to one that I created.

Download Attachment: GetRotation.zip
7.05 KB

Go to Top of Page

game_maker
Knave

Saudi Arabia
83 Posts

Posted - Jul 25 2004 :  03:10:40 AM  Show Profile  Visit game_maker's Homepage  Reply with Quote
Same as "Eric" Method

  
Public Function GetRotation(V1 As Vector2, V2 As Vector2) As Single
Dim S As Single
S = (V1.X * V2.X + V1.Y * V2.Y) / _  
(Sqr(V1.X * V1.X + V1.Y * V1.Y) * Sqr(V2.X * V2.X + V2.Y * V2.Y))  
GetRotation = Atn(Sqr(1 / (S * S) - 1)) * 57.29578  
End Function
  


the Idea behind this (vector calculations)

  
A.B = |A| |B| cost  
cost = (A.B) / (|A| |B|)  
t = arccos( (A.B) / (|A| |B|) )  
  
and there is no arccos in vb.6 so we use arctan to got arccos :  
  
arccos = arctan(Sqr(1 / (X * X) - 1))  
  
arctan named atn in vb  
  
but if you are using .Net then you can use arccos directly as built-in function
  


regards
Go to Top of Page

cbx
Swordmaster

Canada
296 Posts

Posted - Jul 25 2004 :  10:28:11 AM  Show Profile  Visit cbx's Homepage  Send cbx an ICQ Message  Click to see cbx's MSN Messenger address  Send cbx a Yahoo! Message  Reply with Quote
Um,... I really don't know how to say this. Eric and Game_Maker, I don't think your GetRotation functions work. You two oviously know more about advanced math then I do, but unless I'm not understanding something properly your GetRotation methods are not returning acurate rotation values.

For example. Download erics GetRotation zip file and modify the form code to do the fallowing

Public L, R As Vector2  
  
    Private Sub frmTest_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove  
        Select Case e.Button  
            Case Windows.Forms.MouseButtons.Left  
                L.X = e.X  
                L.Y = e.Y  
  
            Case Windows.Forms.MouseButtons.Right  
                R.X = e.X  
                R.Y = e.Y  
        End Select
  
        With Me.CreateGraphics  
            .Clear(Me.BackColor)  
            .DrawLine(New Pen(Me.ForeColor), L.X, L.Y, R.X, R.Y)  
        End With
  
         Me.Text = cbx.GetRotation(L, R).ToString & " - " & eric.GetRotation(L, R).ToString  
    End Sub


The code is written on vb.net but can be converted to vb6 easy enough. This is how I have been testing your GetRotation methods. By using the left and right mouse buttons to position a line on the form and then setting the forms title bar text to the values from your GetRotation methods.

Now when when you run erics program you will see that my GetRotation method is returning proper rotational values from 0 to 359.999. But your guys GetRotation methods don't appear to be returning either degrees (0 to 359.999) or radians (0 to (PI * 2)).


Download the attached video for a demonstration.
Download Attachment: GetRotationVid.zip
67.36 KB

Created by: X
http://www.createdbyx.com/
Go to Top of Page

game_maker
Knave

Saudi Arabia
83 Posts

Posted - Jul 25 2004 :  3:56:22 PM  Show Profile  Visit game_maker's Homepage  Reply with Quote
It's really works very fine...

It's depends on how do you want your angle ... I mean Eric code gives you the angle from (0,180) (witch you may want this type of angle)

My first code returns the same type of angle too

I have added another function that returns the angle with range (0,360)

Download Attachment: GetRotation.zip
7.99 KB
Go to Top of Page

cbx
Swordmaster

Canada
296 Posts

Posted - Jul 25 2004 :  7:17:38 PM  Show Profile  Visit cbx's Homepage  Send cbx an ICQ Message  Click to see cbx's MSN Messenger address  Send cbx a Yahoo! Message  Reply with Quote
Damit! I screwed up my post I was making,... now I have to start all over. Soo much typing lost forever! Grrrr!

Anyway, turns out my code is actually 2x faster then both eric and game_makers when placed in a single method. My new code...

Public Function GetRotation(ByRef SX As Single, ByVal SY As Single, ByVal DX As Single, ByVal DY As Single) As Single
        Dim Slope As Single
        Dim Angle As Single
  
        Slope = System.Math.Abs(DY - SY) / System.Math.Abs(DX - SX)  
        Angle = System.Math.Atan(Slope)  
        If DY < SY Then
            If DX < SX Then ' upleft  
                Return (Angle * 57.29578!) + 180  
            Else ' upright  
                Return -(Angle * 57.29578!) + 360  
            End If
        Else
            If DX < SX Then ' low left  
                Return -(Angle * 57.29578!) + 180  
            Else 'low right  
                ' do nothing  
                Return Angle * 57.29578!  
            End If
        End If
    End Function


... Replace the code in the GetRotation project eric originally provided and replace my old GetRotation code with the new code provided above.

So having said that are there any challengers out there who think they can make a faster GetRotation method If so make a post!

Created by: X
http://www.createdbyx.com/
Go to Top of Page

game_maker
Knave

Saudi Arabia
83 Posts

Posted - Jul 25 2004 :  7:38:47 PM  Show Profile  Visit game_maker's Homepage  Reply with Quote
BTW: Vector Calculus is a simple math subject

You know that vectors are independent of space(x,y,z)

It's only represent direction and magnitude

Assume VecA = (4i,8j) = <4,8> , VecB = <8,4>



The magnitude (length) of vecA =
|vecA| = sqr(x^2 + y^2) = sqr(16+64) = 8.94
|VecB| = sqr(64+64) = 8.94

The Dot Product definition is:

VecA (Dot product) VecB = |VecA| |VecB| cost

Where t is the angle between them

VecA (Dot product) VecB = VecA.X * VecB.X + VecA.Y * VecB.Y

= 4 * 8 + 8 * 4 = 64

So cost = VecA . VecB / (|VecA| |VecB|)

Therefore t = arccos( VecA . VecB / (|VecA| |VecB|) )

And 0 <= t <= 180

So t = arccos (64 / (8.94 * 8.94) = arccos(0.8) = 36.8

____________________________

Let's find t using another method (Equation of Line)

If we find the angle t1 between VecB and the X-Axis
And The Angle t2 between VecA and the X-Axis
The Subtract t2-t1 it will equal t .... Isn't it

to find t1 we find the slope of line m1 then using atn() that's return t1

t1 = atn(m1) = atn(dy/dx) = atn(4/8) = atn(0.5) = 26.57
t2 = atn(m1) = atn(dy/dx) = atn(8/4) = atn(2) = 63.43
t = t2-t1 = 63.43-26.57 = 36.8

In gm module I used method1

In gm2 module I used method2

Regards


Edited by - game_maker on Jul 25 2004 7:49:23 PM
Go to Top of Page

game_maker
Knave

Saudi Arabia
83 Posts

Posted - Jul 25 2004 :  8:18:14 PM  Show Profile  Visit game_maker's Homepage  Reply with Quote
Are you tring to Get the rotation angle between to points and not 2 lines or vectors .... oops

Because Me & Eric we ware sloving another problem

hmmmmm .... this code is a bit faster

  
Public Function GetRotation(V1 As Vector2, V2 As Vector2) As Single
    Dim dX As Single, dY As Single
    dX = V2.X - V1.X  
    dY = V2.Y - V1.Y  
    GetRotation = Atn(dY / dX) * 57.29578  
    If dX < 0 Then GetRotation = GetRotation + (dY > 0) * 360 + 180  
    If GetRotation < 0 Then GetRotation = 360 + GetRotation  
End Function
  


BTW : You should Put Condition if dx = 0 (slope is infnite)

Edited by - game_maker on Jul 25 2004 8:19:34 PM
Go to Top of Page

cbx
Swordmaster

Canada
296 Posts

Posted - Jul 26 2004 :  12:06:28 AM  Show Profile  Visit cbx's Homepage  Send cbx an ICQ Message  Click to see cbx's MSN Messenger address  Send cbx a Yahoo! Message  Reply with Quote

Yah, um, see all that fancy spread you did describing the equation of how to get rotation. You lost me even before you started typing it. Same goes for the graph image you displayed.

The only way I have found for me to effectively understand math concepts in any coherent way is with code. Weather it be in C C++ pascal, basic, vb what ever, if it's code, I can understand it. If it's a math equasion -> "Eh, forget about it"

Yes BTW we do appear to be describing 2 different things, What I wanted was the rotation value of 2 points in 2D space and you guys were giving me a rotation value using lines/vectors.

"I see, said the blind man to the deaf man, who really was'nt listening anyway."

Created by: X
http://www.createdbyx.com/
Go to Top of Page

Eric Coleman
Gladiator

USA
811 Posts

Posted - Jul 26 2004 :  11:42:27 AM  Show Profile  Visit Eric Coleman's Homepage  Reply with Quote
The fact that you are passing a "vector" to your GetRotation function instead of a "point" is very misleading. The function I supplied is identical to game_maker's code except my function is optimized to minimize data type conversions. VB's math functions require Double data types as both input and output, so passing a data type of Single to the function and assinging it to a Single data type will mean there are 2 implicit data type conversions going on.

Dim A As Single
A = Sin(A)

is the same as
A = CSng(Sin(CDbl(A)))

Visual Basic hides a LOT of data conversion for you, which makes programming simple and easy. However, if you do not know about this implicit Data Type conversion, then you can easily write sloppy code.

Here is game_maker's function
Public Function GetRotation(V1 As Vector2, V2 As Vector2) As Single
Dim S As Single
S = (V1.X * V2.X + V1.Y * V2.Y) / _  
(Sqr(V1.X * V1.X + V1.Y * V1.Y) * Sqr(V2.X * V2.X + V2.Y * V2.Y))  
GetRotation = Atn(Sqr(1 / (S * S) - 1)) * 57.29578  
End Function


And here is mine,
Public Function GetRotation(V1 As Vector2, V2 As Vector2) As Single
    Dim p As Double, q As Double, r As Double
    Dim X1 As Double, X2 As Double, Y1 As Double, Y2 As Double
    Dim Ret As Single
    X1 = V1.X  
    Y1 = V1.Y  
    X2 = V2.X  
    Y2 = V2.Y  
  
    p = X1 * X2 + Y1 * Y2  
    q = Sqr(X1 * X1 + Y1 * Y1) * Sqr(X2 * X2 + Y2 * Y2)  
    'if q = 0 then this will not work.  
    If q = 0 Then Exit Function
    r = p / q  
    r = Atn(-r / Sqr(-r * r + 1)) + 1.5707963267949  
    GetRotation = CSng(r) * 57.29578!  
End Function


game_maker's code uses ArcSin, which is wrong. But other than that, they're nearly identical. You will notice that I use temporary variables of type Double so that there are no hidden data type conversions from Single to Double or Double to Single. In fact, their are only 4 data type conversions, at the beginning of the function when I assign the variables X1, X2, Y1, Y2, and at the end when I explicitly convert "r" to be a number of type Single. I also multiply by 180 / pi, but I tell VB that it should treat it as a constant of type Single by using the "!". A double number uses #, Long is &, and Integer is %.

Go to Top of Page

game_maker
Knave

Saudi Arabia
83 Posts

Posted - Jul 26 2004 :  8:42:29 PM  Show Profile  Visit game_maker's Homepage  Reply with Quote
Eric : You are really an advanced programmer , you know exactly what you are doing ...

And about my first code (rotation between to vectors method 1)

  
Public Function GetRotation(V1 As Vector2, V2 As Vector2) As Single
Dim S As Single, B1 As Byte, B2 As Byte
S = (V1.X * V2.X + V1.Y * V2.Y) / _  
(Sqr(V1.X * V1.X + V1.Y * V1.Y) * Sqr(V2.X * V2.X + V2.Y * V2.Y))  
GetRotation = Atn(Sqr(1 / (S * S) - 1)) * 57.29578  
If S < 0 Then GetRotation = 180 - GetRotation  
End Function
  


0 < theta < 180

It uses ArcCos And Not ArcSin .. because I am using

  
Atn(Sqr(1 / (S * S) - 1))  
  


Witch is ArcCos ... because

  
tan(t) = x  
t = arctan(x)  
t= arctan(tan(t)) .... (1)  
  
Sin(t)^2 + Cos(t)^2 = 1 (equation of Unit Circle)  
devide by Cos(t)^2  
tan(t)^2 + 1 = 1/cos(t)^2  
tan(t)^2 = 1/cos(t)^2 - 1  
tan(t) = sqr( (1/cos(t)^2 ) - 1 ) .... (2)  
using (1) into (2)  
t = arctan( (1/(cos(t)*cos(t) ) - 1 )  
t = arctan( (1/(s*s)) - 1 )  
  

so it's must be arccos .... and it gives 100% same result as your function gives ...

cbx : yup ...sorry about the "Headache" ... I think I should wear from now on
Go to Top of Page

Eric Coleman
Gladiator

USA
811 Posts

Posted - Jul 26 2004 :  11:16:51 PM  Show Profile  Visit Eric Coleman's Homepage  Reply with Quote
I didn't realize that your ArcCos function was different. I only noticed that you didn't add pi/2 to the result, so I assumed you were calculating ArcSin.

I don't follow your derivation. I'm not sure what "s" is supposed to be in your last substitution from t = arctan( (1/(cos(t)*cos(t) ) - 1 ) => t = arctan( (1/(s*s)) - 1 ), which is missing a Sqrt from your original function, Atn(Sqr(1 / (S * S) - 1)).


The function I used for ArcCos is from the VB help file,
Inverse Sine, Arcsin(X) = Atn(X / Sqr(-X * X + 1))
Inverse Cosine, Arccos(X) = Atn(-X / Sqr(-X * X + 1)) + 2 * Atn(1)


Here is another proof that I found online that is a bit easier to understand,
quote:

  
                       C  
                      /|  
                     / |  
                    /  |  
                   /   |  
               1  /    |  
                 /     |  
                /      |  sqrt(1-x^2)  
               /       |  
              /        |  
             /_________|  
            A           B  
                  x  
  


Now, consider both the cosine and the tangent of angle A:

cos A = x/1 = x
tan A = (sqrt(1-x^2))/x

Clearly, A = arccos(x) and also A = arctan((sqrt(1-x^2))/x).

Therefore, arcos(x) = arctan((sqrt(1-x^2))/x).

from http://mathforum.org/library/drmath/view/54020.html

Go to Top of Page

game_maker
Knave

Saudi Arabia
83 Posts

Posted - Jul 27 2004 :  4:31:37 PM  Show Profile  Visit game_maker's Homepage  Reply with Quote
Ya I forget about sqr()

The derivation I wrote is easy one too...

t = arctan ( tan(x) ) .... (1)

and we want to find a function of cos(x) = tan(x)

tan(x) = a function of cos(x)

tan(x) = sqr( (1/ (cos(t)*cos(t) ) - 1 )

By (1) :

t = arctan( sqr( (1/ (cos(t)*cos(t) ) - 1 )))
Let S = cos(t)
t = arctan( sqr( (1/ (S*S ) - 1 )))

Your formula:
arcos(x) = arctan((sqr(1-x^2))/x)
and mine
arcos(x) = arctan(sqr( (1/ (x*x ) - 1 )))

we can check mine if we equalize them

arctan((sqr(1-x^2))/x) = arctan(sqr( (1/ (x*x ) - 1 )))
(sqr(1-x^2))/x = sqr( (1/ (x*x ) - 1 ))
square both sides
(1-(x*x))/(x*x) = (1/(x*x)) - 1
we take the left side
(1-(x*x))/(x*x)
= (1 / (x*x)) - (x*x)/(x*x)
= (1 / (x*x)) - 1 = the right side

BTW : I have a question about atn(arctan) ; how VB calculate this function at first place ..... I don't think that he used a series !!

Maclaurian Series Says: arctan(x) = (-1)^n * ( x^(2*n - 1) / ( 2*n - 1 )

But using this in (for-loop) with precious counter will take very long time!
Go to Top of Page

Eric Coleman
Gladiator

USA
811 Posts

Posted - Jul 27 2004 :  5:34:34 PM  Show Profile  Visit Eric Coleman's Homepage  Reply with Quote
I'm not sure how VB calculates functions like that either.
Go to Top of Page
  Previous Topic Topic Next Topic  
 New Topic  Reply to Topic
 Printer Friendly
Jump To:
VBGamer © Go To Top Of Page
This page was generated in 0.56 seconds. Snitz Forums 2000

Copyright © 2002 - 2004 Eric Coleman, Peter Kuchnio , et. al.