|
-
Mar 20th, 2003, 11:32 PM
#1
Thread Starter
Frenzied Member
is there a better way...?
is there a faster (better) way of doing this?
VB Code:
Private Function GetAngle(X1 As Single, Y1 As Single, X2 As Single, Y2 As Single) As Single
On Error Resume Next
Dim XDiff As Long
Dim YDiff As Long
Dim Angle As Single
XDiff = Abs(X1 - X2)
YDiff = Abs(Y2 - Y1)
Angle = Atn(XDiff / YDiff)
Angle = Angle * 180 / Pi
If Y2 > Y1 Then Angle = 180 - Angle
If X2 < X1 Then Angle = 0 - Angle
If Angle < 0 Then Angle = 360 + Angle
If YDiff = 0 And X1 - X2 < 0 Then
Angle = 90
End If
If YDiff = 0 And X1 - X2 > 0 Then
Angle = 270
End If
GetAngle = Angle
End Function
-
Mar 21st, 2003, 12:04 AM
#2
Fanatic Member
Did you want to get the Reference Angle?

prog_tom
JOIN THE REVOLUTION!!!! Dual T3 backedup science community.
http://physics.sviesoft.com/forum
-
Mar 21st, 2003, 01:52 AM
#3
Thread Starter
Frenzied Member
-
Mar 21st, 2003, 02:26 AM
#4
Hi, my function also uses 5 "IF'S" but I arranged them a bit different, faster ?? I don't know. But for sure I don'T have a division by 0 if dy=0 ( in yours YDif=0)!
Sorry for any typos, I had to change some GERMAN Variable-names to ENGLISH.
VB Code:
Public Function Bearing(X1 As Single, Y1 As Single, X2 As Single, Y2 As Single)
'Input X1, Y1, X2, Y2
'Calculates Bearing from X1,Y1 to X2,Y2 (0-360)
Const PI = 3.141592654
Dim dx As Single
Dim dy As Single
dx = X2 - X1
dy = Y2 - Y1
If dy <> 0 Then
Bearing = (Atn(dx / dy) * 180 / PI)
If X2 > X1 Then
If Y2 > Y1 Then
Bearing = Bearing
Else
Bearing = 180 + Bearing
End If
Else
If Y2 > Y1 Then
Bearing = 360 + Bearing
Else
Bearing = 180 + Bearing
End If
End If
Else
If X1 > X2 Then
Bearing = 270
Else
Bearing= 90
End If
End If
End Function
You're welcome to rate this post!
If your problem is solved, please use the Mark thread as resolved button
Wait, I'm too old to hurry!
-
Mar 21st, 2003, 02:50 AM
#5
Fanatic Member
I've made a sample project. It has only one form and one command button. The form code is shown here.
If you convert all parameters and the return value to double floating point values, it will give a performance boost of about 20 %, when run in the VB IDE (see function GetAngle1). The reason for this is that most functions use doubles, instead of singles. So there is less type conversion. Another strange thing in your code is that you dimmed XDiff and YDiff as longs. All decimals will then be cut off.
The best performance gives the last function (GetAngle2), which also uses arctan extensively. The extra code in the arctan2 function is to guarantee that opposite directions will give opposite angles. The extra performance boost between this function and GetAngle1 is not much, but the code is much simpler.
Good luck!
VB Code:
Option Explicit
Private Const m_iTimes = 100000
Private Const PI = 3.14159265358979
Private Const HALFPI = 1.5707963267949
Private Declare Function GetTickCount Lib "kernel32" () As Long
Private Sub Command1_Click()
Dim l As Long
Dim ang As Single
Dim t1 As Long, t2 As Long, t3 As Long, t4 As Long
Randomize Timer
t1 = GetTickCount()
For l = 1 To m_iTimes
ang = GetAngle(Rnd, Rnd, Rnd, Rnd)
Next l
t2 = GetTickCount()
For l = 1 To m_iTimes
ang = GetAngle1(Rnd, Rnd, Rnd, Rnd)
Next l
t3 = GetTickCount()
For l = 1 To m_iTimes
ang = GetAngle2(Rnd, Rnd, Rnd, Rnd)
Next l
t4 = GetTickCount()
MsgBox "First function: " & (t2 - t1) & vbCrLf & _
"Second function: " & (t3 - t2) & vbCrLf & _
"Third function: " & (t4 - t3)
End Sub
Private Function GetAngle(X1 As Single, Y1 As Single, X2 As Single, Y2 As Single) As Single
On Error Resume Next
Dim XDiff As Long
Dim YDiff As Long
Dim Angle As Single
XDiff = Abs(X1 - X2)
YDiff = Abs(Y2 - Y1)
Angle = Atn(XDiff / YDiff)
Angle = Angle * 180 / PI
If Y2 > Y1 Then Angle = 180 - Angle
If X2 < X1 Then Angle = 0 - Angle
If Angle < 0 Then Angle = 360 + Angle
If YDiff = 0 And X1 - X2 < 0 Then
Angle = 90
End If
If YDiff = 0 And X1 - X2 > 0 Then
Angle = 270
End If
GetAngle = Angle
End Function
Private Function GetAngle1(X1 As Double, Y1 As Double, X2 As Double, Y2 As Double) As Double
On Error Resume Next
Dim XDiff As Double
Dim YDiff As Double
Dim Angle As Double
XDiff = Abs(X1 - X2)
YDiff = Abs(Y2 - Y1)
Angle = Atn(XDiff / YDiff)
Angle = Angle * 180 / PI
If Y2 > Y1 Then Angle = 180 - Angle
If X2 < X1 Then Angle = 0 - Angle
If Angle < 0 Then Angle = 360 + Angle
If YDiff = 0 And X1 - X2 < 0 Then
Angle = 90
End If
If YDiff = 0 And X1 - X2 > 0 Then
Angle = 270
End If
GetAngle1 = Angle
End Function
Private Function GetAngle2(X1 As Double, Y1 As Double, X2 As Double, Y2 As Double) As Double
Dim XDiff As Double, YDiff As Double
XDiff = X2 - X1
YDiff = Y2 - Y1
GetAngle2 = Arctan2(YDiff, XDiff)
If GetAngle2 < 0 Then GetAngle2 = GetAngle2 + 2 * PI
GetAngle2 = GetAngle2 * 180 / PI
End Function
Public Function Arctan2(y As Double, x As Double) As Double
If x = 0 Then
If y > 0 Then
Arctan2 = HALFPI
Else
Arctan2 = -HALFPI
End If
ElseIf x > 0 Then
Arctan2 = Atn(y / x)
Else
If y < 0 Then
Arctan2 = Atn(y / x) - PI
Else
Arctan2 = Atn(y / x) + PI
End If
End If
End Function
-
Mar 21st, 2003, 03:54 AM
#6
Thanks riis, I think i'll use your code (GetAngle2) instead of mine.
Anybody using GetAngle or GetAngle1 should keep in mind, that the division by Zero is only stepped over by:
You're welcome to rate this post!
If your problem is solved, please use the Mark thread as resolved button
Wait, I'm too old to hurry!
-
Mar 21st, 2003, 04:00 AM
#7
Or after testing my function with your "test-code" (using it in VBA-EXCEL) I think I stick to my approach.
GetAngle2 290 vs. Bearing 280
And I didn't change my single declaritions!
You're welcome to rate this post!
If your problem is solved, please use the Mark thread as resolved button
Wait, I'm too old to hurry!
-
Mar 21st, 2003, 04:15 AM
#8
Looked at it more closely.
The difference between GetAngle2 and Bearing is the most if the Division by Zero comes into the game.
In my Function, this event is handled earlier, i.e. faster.
You're welcome to rate this post!
If your problem is solved, please use the Mark thread as resolved button
Wait, I'm too old to hurry!
-
Mar 21st, 2003, 10:30 AM
#9
Fanatic Member
The disadvantage of the GetAngle2 function is that it uses an extra function call, i.e. ArcTan2. Of course it is possible to integrate the ArcTan2 function into the GetAngle2 function.
By the way, it looks like your and Cyborg's function has North as 0 degrees and the angle increases clockwise. By using Arctan2 the way I did East is 0 degrees and the angle increases counterclockwise. If anyone is going to work with it, he should keep this in mind!
-
Mar 22nd, 2003, 12:02 PM
#10
Yes Riis,
you are using this function in the more "technical" way.
Since I'm using it more for navigational stuff, I need North to be Zero and East to be 90.
You're right, anybody who is using one of this functions should keep that in mind.
I had to learn it the hard way, on work I have to use a simulation-system build by people who think more in the "technical" way. So they are using the Degrees like you (0 is East and counting counterclockwise).
That was no problem as long they didin't show anything on the UserInterface.
But that system is a simulation for Naval Things, so they have to show bearings, and these have to be "understandable" be Navigators.
So far I found about 5 places in the system that they had to change (soetimes more than once), and I'm still looking.............
You're welcome to rate this post!
If your problem is solved, please use the Mark thread as resolved button
Wait, I'm too old to hurry!
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|