Angle difference
#1
I was working collisions of spiders and 2 spiders going in same direction or nearly so needed collision code different from spiders coming head on or perpendicular to each other.

So how do I tell if spiders are going in same direction or nearly so, say their headings are within 30 degrees of each other or not?

Just subtract the angles right? Or take the ABS of the difference right?

Well what if one has a heading of 0 degrees and the other a heading of 350 degrees the difference is 350, I am wanting 10 degrees so make 0 360 instead, easy right?

So now what if one was x and the other y when do I know to add 360? like with 0.

I came up with a function AngleDifference to handle this because this issue has come up before but it seems kind of clunky. I think the time before I used Major and Minor arc differences, two answers to angle difference. This time one answer but again seems cluncky.

I won't show my code because I don't want to bias someone coming up with maybe a more elegant solution which I suspect exists.

So if you can do it in a line or 2 I'd be interested.
b = b + ...
Reply
#2
(01-31-2023, 05:04 PM)bplus Wrote: I was working collisions of spiders and 2 spiders going in same direction or nearly so needed collision code different from spiders coming head on or perpendicular to each other.

So how do I tell if spiders are going in same direction or nearly so, say their headings are within 30 degrees of each other or not?

Just subtract the angles right? Or take the ABS of the difference right?

Well what if one has a heading of 0 degrees and the other a heading of 350 degrees the difference is 350, I am wanting 10 degrees so make 0 360 instead, easy right?

So now what if one was x and the other y when do I know to add 360? like with 0.

I came up with a function AngleDifference to handle this because this issue has come up before but it seems kind of clunky. I think the time before I used Major and Minor arc differences, two answers to angle difference. This time one answer but again seems cluncky.

I won't show my code because I don't want to bias someone coming up with maybe a more elegant solution which I suspect exists.

So if you can do it in a line or 2 I'd be interested.

Hi ! I know the problem. I've been using this for a long time and it works.

"unit" is the unit of measure expressing a complete revolution. If you count in 360, write 360! If 2*_pi -t, then 2*_pi !

Code: (Select All)
Function dif_ang (a, b, unit): a2 = a: b2 = b
    Do While Abs(a2 - b2) > Abs((a2 - unit) - b2): a2 = a2 - unit: Loop: Do While Abs(a2 - b2) > Abs((a2 + unit) - b2): a2 = a2 + unit: Loop: dif_ang = a2 - b2
End Function
Reply
#3
If I'm understanding the problem correctly, I put this in terms of your code, more or less. It's just a dot product function that checks if the angle projection is greater than the COS of 30 degrees. It worked for the example at least.

Code: (Select All)
TYPE SpinnerType
    x AS SINGLE
    y AS SINGLE
    dx AS SINGLE
    dy AS SINGLE
    a AS SINGLE
    sz AS SINGLE
    c AS _UNSIGNED LONG
END TYPE

less30 = COS(_D2R(30))

DIM AS SpinnerType s1, s2, s3
s1.dx = 5
s1.dy = 5
s2.dx = 5
s2.dy = 0
s3.dx = 5
s3.dy = 4
PRINT "s1 & s2"
IF Spinner_Dot(s1, s2) >= less30 THEN
    PRINT "same general direction"
ELSE
    PRINT "Divergent direction"
END IF
PRINT "s1 & s3"
IF Spinner_Dot(s1, s3) >= less30 THEN
    PRINT "same general direction"
ELSE
    PRINT "Divergent direction"
END IF
END



FUNCTION Spinner_Dot! (a AS SpinnerType, b AS SpinnerType)
    ha! = _HYPOT(a.dx, a.dy)
    hb! = _HYPOT(b.dx, b.dy)
    Spinner_Dot! = (a.dx / ha!) * (b.dx / hb!) + (a.dy / ha!) * (b.dy / hb!)
END FUNCTION
DO: LOOP: DO: LOOP
sha_na_na_na_na_na_na_na_na_na:
Reply
#4
@MasterGy yours looks more clunky than mine, if mine is always correct you will be interested, it will save you from loops.

@OldMoses yours I can immediately apply with spider code and not even have to convert dx, dy's to an angle heading. Mine might be less calculation if I had the heading already calculated which for spiders I don't.
But I am thinking it might be handy to use speed with heading for dx, dy calc's. It is also interesting that a vector solution has crept into my trig problem. I might get an insight into vector stuff from this.  Smile

But what is SpinnerDot? It looks like you compare to Cos(30 degrees) not straight 30 degrees.


Next how to test all our solutions to 
1. make sure they are always correct and then 2. which is speediest?

Hmm... also I was assuming the difference as absolute value, always positive. But if I want to apply to one or the other angles I guess I need both pos and neg solutions.

BTW I was thinking Function looks like:
AngleDifferenceD(degrees1, degrees2)
AngleDifferenceR(radians1, radians2)
b = b + ...
Reply
#5
My understanding of the dot product is that it projects one vector onto another such that its projection creates a right triangle. If both are unit vectors, which Spinner_Dot converts to, then the amount of the projection should be a cos function of whatever the angle is.
DO: LOOP: DO: LOOP
sha_na_na_na_na_na_na_na_na_na:
Reply
#6
While writing test code, I very quickly came to insight that the ABS of the answer has to be <=180 degrees for degrees.

This led me to a more elegant and correct solution of:
Code: (Select All)
' 2023-01-31  Best! because in terms of +/- to angle1 a negative sign means a2 is clockwise to angle 1
Function DiffAngleD (A1Degrees, A2Degrees)
    ' This might be assuming both angles are between >= 0  and < 360
    If Abs(A1Degrees - A2Degrees) <= 180 Then
        DiffAngleD = A1Degrees - A2Degrees
    ElseIf Abs((A1Degrees + 360) - A2Degrees) <= 180 Then
        DiffAngleD = (A1Degrees + 360) - A2Degrees
    Else
        DiffAngleD = A1Degrees - (A2Degrees + 360)
    End If
End Function

EDIT: when I changed variable names I missed one

Test code:
Code: (Select All)
_Title "Angle Difference" ' b+ 2023-01-31 set up test code for AngleDifference Function tests
$Console:Only
' test code
For a1 = 0 To 360 Step 10
    For a2 = 0 To 360 Step 10
        Print a1, a2, DiffAngleD(a1, a2), dif_ang(a1, a2, 360)
        If DiffAngleD(a1, a2) <> dif_ang(a1, a2, 360) Then Beep: Sleep
    Next
Next

' 2023-01-31  Best! because in terms of +/- to angle1 a negative sign means a2 is clockwise to angle 1
Function DiffAngleD (A1Degrees, A2Degrees)
    ' This might be assuming both angles are between >= 0  and < 360
    If Abs(A1Degrees - A2Degrees) <= 180 Then
        DiffAngleD = A1Degrees - A2Degrees
    ElseIf Abs((A1Degrees + 360) - A2Degrees) <= 180 Then
        DiffAngleD = (A1Degrees + 360) - A2Degrees
    Else
        DiffAngleD = A1Degrees - (A2Degrees + 360)
    End If
End Function

'MasterGy version 2023-01-31   https://staging.qb64phoenix.com/showthread.php?tid=1434&pid=13123#pid13123
Function dif_ang (a, b, unit): a2 = a: b2 = b
    Do While Abs(a2 - b2) > Abs((a2 - unit) - b2): a2 = a2 - unit: Loop: Do While Abs(a2 - b2) > Abs((a2 + unit) - b2): a2 = a2 + unit: Loop: dif_ang = a2 - b2
End Function

EDIT: cleaned out stuff no longer useful

When I was trying to include OldMoses code I got stuck a bit on converting Spinner_Dot to an angle but I went ahead with my adjustment to +/- returns of Angle Degree measure.

If the AngleDiffD is negative it means the 2nd angle is Clockwise to the first, whereas if positive it means the 2nd angle is CCW to first.

PS MasterGy's looks more complicated but he is not assuming the angles input are between 0 and 360. +1 his code was very helpful in getting mine turned the right way.
b = b + ...
Reply
#7
From what I read, it appears you're looking for something like this to determine if they're on a collision course:

Code: (Select All)
PRINT collision(0, 10)
PRINT collision(10, 0)
PRINT collision(350, 0)
PRINT collision(0, 350)
PRINT collision(0, 11)
PRINT collision(11, 0)
PRINT collision(349, 0)
PRINT collision(0, 349)


FUNCTION collision (a, b)
    t = ABS((a - b + 360) MOD 360)
    collision = t <= 10 OR t >= 350
END FUNCTION
Reply
#8
(01-31-2023, 09:29 PM)SMcNeill Wrote: From what I read, it appears you're looking for something like this to determine if they're on a collision course:

Code: (Select All)
PRINT collision(0, 10)
PRINT collision(10, 0)
PRINT collision(350, 0)
PRINT collision(0, 350)
PRINT collision(0, 11)
PRINT collision(11, 0)
PRINT collision(349, 0)
PRINT collision(0, 349)


FUNCTION collision (a, b)
    t = ABS((a - b + 360) MOD 360)
    collision = t <= 10 OR t >= 350
END FUNCTION

No the collision detection was being done with thePixelCollision code. The problem was what to do after collision was detected. Do I reverse the spider do I reverse both spiders, do I turn them same direction if head on but opposite direction if their headings almost the same.... 

I figured if both going in approximately same direction to turn one one way and the other the opposite but with my first angle diff code that didn't work maybe with code developed today. I kept getting spiders stuck or spinning, yuck!

Big spiders were setup to go faster than little ones so if on same heading they will collide because the big one overtook the smaller. That's when I needed to know the angle difference in their headings, to swerve the two apart. The angle difference problem had me stumped for awhile and my solution yesterday failed to stop the problems.

Anyway for spider collisions the solution was to just speed up both in direction they were going, looks about right actually.

Maybe I should try this new DiffAngleD and try again.
b = b + ...
Reply
#9
(01-31-2023, 08:12 PM)bplus Wrote: When I was trying to include OldMoses code I got stuck a bit on converting Spinner_Dot to an angle but I went ahead with my adjustment to +/- returns of Angle Degree measure.

If you want the angle between two spiders movement vectors <.dx, .dy>, based on the return from Spinner_Dot :

angle in degrees = _R2D(_ACOS(Spinner_Dot(s1, s2)))

Spinner_Dot should return a SINGLE between 1 and -1. The same range as COS(0 - 180)

-1 = moving 180 degrees opposite each other
0 = moving on perpendicular courses
1 = moving parallel in same direction

Note: this only applies to unit vectors, which is why Spinner_Dot divides the components by the magnitudes

Dot product doesn't care about 180-360, it's treated the same as 0 to 180
DO: LOOP: DO: LOOP
sha_na_na_na_na_na_na_na_na_na:
Reply




Users browsing this thread: 5 Guest(s)