cbx
Swordmaster
   
Canada
296 Posts |
Posted - Jul 24 2004 : 01:27:03 AM
|
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 Return RadianToDegree(Angle) + 180 Else Return -RadianToDegree(Angle) + 360 End If Else If Destination.X < Source.X Then Return -RadianToDegree(Angle) + 180 Else 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
|
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
|
 |
|
game_maker
Knave
 
Saudi Arabia
83 Posts |
|
cbx
Swordmaster
   
Canada
296 Posts |
Posted - Jul 25 2004 : 10:28:11 AM
|
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/ |
 |
|
game_maker
Knave
 
Saudi Arabia
83 Posts |
Posted - Jul 25 2004 : 3:56:22 PM
|
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 |
 |
|
cbx
Swordmaster
   
Canada
296 Posts |
|
game_maker
Knave
 
Saudi Arabia
83 Posts |
Posted - Jul 25 2004 : 7:38:47 PM
|
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 |
 |
|
game_maker
Knave
 
Saudi Arabia
83 Posts |
|
cbx
Swordmaster
   
Canada
296 Posts |
Posted - Jul 26 2004 : 12:06:28 AM
|
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/ |
 |
|
Eric Coleman
Gladiator
   
USA
811 Posts |
Posted - Jul 26 2004 : 11:42:27 AM
|
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 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 %.
|
 |
|
game_maker
Knave
 
Saudi Arabia
83 Posts |
|
Eric Coleman
Gladiator
   
USA
811 Posts |
Posted - Jul 26 2004 : 11:16:51 PM
|
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
|
 |
|
game_maker
Knave
 
Saudi Arabia
83 Posts |
Posted - Jul 27 2004 : 4:31:37 PM
|
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!  |
 |
|
Eric Coleman
Gladiator
   
USA
811 Posts |
Posted - Jul 27 2004 : 5:34:34 PM
|
I'm not sure how VB calculates functions like that either. |
 |
|
|
|