Given two unit/direction vectors, A and B, this code gives the shortest angular distance from A to B, and whether that is travelling clockwise or counter-clockwise (the orientation, or right- and left-handedness as I've referred to it in the code).
Details.
code (requires M1U, Advanced2D plugins)
+ Code Snippetset display mode desktop width(), desktop height(), 32, 1
sync on : sync rate 30 : sync
scrW = screen width()
scrH = screen height()
type vec2d x as float y as float endtype
vecA as vec2d
vecPerpA as vec2d
vecB as vec2d
// initial values (returns bad results if vectors are 0, that is, not unit length)
vecA.x = 1.0 : vecA.y = 0 : vecPerpA.x = 0 : vecPerpA.y = 1.0 : vecB.x = -0.707106781 : vecB.y = 0.707106781
// define circular area where we'll draw
r# = 160
cx# = scrW/2
cy# = scrH/2
do
// ---- input poll ----
mx = mousex()
my = mousey()
mc = mouseclick()
time = hitimer()
// change A vector (red)
if mc = 1
vecA.x = mx - cx#
vecA.y = my - cy#
l# = sqrt(vecA.x*vecA.x + vecA.y*vecA.y)
vecA.x = vecA.x / l#
vecA.y = vecA.y / l#
vecPerpA.x = -vecA.y
vecPerpA.y = vecA.x
endif
// change B vector (blue)
if mc = 2
vecB.x = mx - cx#
vecB.y = my - cy#
l# = sqrt(vecB.x*vecB.x + vecB.y*vecB.y)
vecB.x = vecB.x / l#
vecB.y = vecB.y / l#
endif
// ---- maths bit ----
// A.B = 1, A and B point in same direction; A.B = 0, A and B are perpendicular; A.B = -1, A and B point in exact opposite directions.
// PerpA is a vector 90deg clockwise from A. Combination of A.B and PerpA.B can identify in which quadrant - of the imaginary circle with A at 0deg - that B is in.
// AToB is the angle from A to B in the 0-180 interval (ie. without handedness).
ADotB# = (vecA.x*vecB.x) + (vecA.y*vecB.y)
PerpADotB# = (vecPerpA.x*vecB.x) + (vecPerpA.y*vecB.y)
AToB# = acos(ADotB#)
// as mentioned above, A.B and PerpA.B give B's A-relative quadrant, but we don't need the quadrant to find handedness - just the 'halfdrant'
// (that is, we want to know which of the two semicircular areas (on either side of A) B is in.)
if PerpADotB# >= 0
AToB_handedness = 1
else
AToB_handedness = -1
endif
// ---- drawing ----
// main circle
a2circle cx#, cy#, r#, 0xffffffff
a2line cx#-r#, cy#, cx#+r#, cy#, 0x80ffffff
a2line cx#, cy#-r#, cx#, cy#+r#, 0x40ffffff
// A (red), PerpA (orange, faded), and B (blue).
a2line cx#, cy#, cx#+vecA.x*r#, cy#+vecA.y*r#, 0xffff0000
a2line cx#, cy#, cx#+vecPerpA.x*r#, cy#+vecPerpA.y*r#, 0x40d06000
a2line cx#, cy#, cx#+vecB.x*r#, cy#+vecB.y*r#, 0xff1040f0
// radial gradient from A to B through the relevant semicircular area, plus a "ball bearing" to reinforce A-to-B directionality.
t# = time%%2000
if vecA.y > 0 then minA = acos(vecA.x) else minA = 360.0 - acos(vecA.x)
maxA = int(AToB#)
if maxA <> 0
for a = 0 to maxA
if AToB_handedness = -1 then a# = minA - a else a# = a + minA
if t# <= (2000.0/maxA*a) then a2fillcircle cx#+cos(a#)*r#*0.96, cy#+sin(a#)*r#*0.96, r#*0.02, 0x40ffffff : t# = 2001.0
a2filltriangle cx#, cy#, cx#+cos(a#)*r#, cy#+sin(a#)*r#, cx#+cos(a#+1)*r#, cy#+sin(a#+1)*r#, 0x40000000 || int(255.0 / maxA * a) || int(255.0 / maxA * (maxA-a)) << 16
next a
endif
// A to B angular distance label and vector labels.
if AToB_handedness = -1 then halfA# = minA - maxA*0.5 else halfA# = maxA*0.5 + minA
center text cx#+cos(halfA#)*(r#+25), cy# + sin(halfA#)*(r#+25) - 7, str$(AToB#*AToB_handedness,1)
center text cx#+vecA.x*(r#+25), cy#+vecA.y*(r#+25) - 7, "A"
center text cx#+vecB.x*(r#+25), cy#+vecB.y*(r#+25) - 7, "B"
// an arrow on A pointing in the direction of B.
drawArrow(cx#+cos(minA)*r#, cy#+sin(minA)*r#, cx#+cos(minA)*r# + cos(minA+90)*AToB_handedness*100, cy#+sin(minA)*r# + sin(minA+90)*AToB_handedness*100, 6, 0xffff0000)
// some debug output.
print "A: ", str$(vecA.x,1), ", ", str$(vecA.y,1)
print "B: ", str$(vecB.x,1), ", ", str$(vecB.y,1)
print "A.B: ", str$(ADotB#,1), " (", str$(AToB#,1), ")"
print "PerpA.B: ", str$(PerpADotB#,1), " (", str$(acos(PerpADotB#),1), ")"
print "A to B Handedness: ", AToB_handedness, " (", left$("left", 4*(AToB_handedness=-1)), left$("right", 5*(AToB_handedness=1)), ")"
center text scrW/2, scrH - 40, "Left-click: Set A Vector - Right-click: Set B Vector"
sync
cls 0
nice wait 20
loop
// by: neuro fuzzy
function drawArrow(fromx,fromy,tox,toy,size,color as dword)
a2line fromx,fromy,tox,toy,color
//type 2, arrow
x=fromx-tox
y=fromy-toy
d#=sqrt(x*x+y*y)
x2#=x/d#
y2#=y/d# `<x1#,x2#> is just the direction from <tox,toy> to <fromx,fromy>
a2line tox,toy,tox+size*0.707106781*(x2#-y2#),toy+size*0.707106781*(x2#+y2#), color
a2line tox,toy,tox+size*0.707106781*(y2#+x2#),toy+size*0.707106781*(y2#-x2#), color
endfunction
code (no plugins):
+ Code Snippetset display mode desktop width(), desktop height(), 32, 1
sync on : sync rate 30 : sync
scrW = screen width()
scrH = screen height()
type vec2d x as float y as float endtype
vecA as vec2d
vecPerpA as vec2d
vecB as vec2d
// initial values (returns bad results if vectors are 0, that is, not unit length)
vecA.x = 1.0 : vecA.y = 0 : vecPerpA.x = 0 : vecPerpA.y = 1.0 : vecB.x = -0.707106781 : vecB.y = 0.707106781
// define circular area where we'll draw
r# = 160
cx# = scrW/2
cy# = scrH/2
do
// ---- input poll ----
mx = mousex()
my = mousey()
mc = mouseclick()
time = timer()
// change A vector (red)
if mc = 1
vecA.x = mx - cx#
vecA.y = my - cy#
l# = sqrt(vecA.x*vecA.x + vecA.y*vecA.y)
vecA.x = vecA.x / l#
vecA.y = vecA.y / l#
vecPerpA.x = -vecA.y
vecPerpA.y = vecA.x
endif
// change B vector (blue)
if mc = 2
vecB.x = mx - cx#
vecB.y = my - cy#
l# = sqrt(vecB.x*vecB.x + vecB.y*vecB.y)
vecB.x = vecB.x / l#
vecB.y = vecB.y / l#
endif
// ---- maths bit ----
// A.B = 1, A and B point in same direction; A.B = 0, A and B are perpendicular; A.B = -1, A and B point in exact opposite directions.
// PerpA is a vector 90deg clockwise from A. Combination of A.B and PerpA.B can identify in which quadrant - of the imaginary circle with A at 0deg - that B is in.
// AToB is the angle from A to B in the 0-180 interval (ie. without handedness).
ADotB# = (vecA.x*vecB.x) + (vecA.y*vecB.y)
PerpADotB# = (vecPerpA.x*vecB.x) + (vecPerpA.y*vecB.y)
AToB# = acos(ADotB#)
// as mentioned above, A.B and PerpA.B give B's A-relative quadrant, but we don't need the quadrant to find handedness - just the 'halfdrant'
// (that is, we want to know which of the two semicircular areas (on either side of A) B is in.)
if PerpADotB# >= 0
AToB_handedness = 1
else
AToB_handedness = -1
endif
// ---- drawing ----
// radial gradient from A to B through the relevant semicircular area, plus a "ball bearing" to reinforce A-to-B directionality.
t# = time%%2000
if vecA.y > 0 then minA = acos(vecA.x) else minA = 360.0 - acos(vecA.x)
maxA = int(AToB#)
if maxA <> 0
ink 0xff404040, 0
for a = 0 to maxA
if AToB_handedness = -1 then a# = minA - a else a# = a + minA
if t# <= (2000.0/maxA*a) then circle cx#+cos(a#)*r#*0.96, cy#+sin(a#)*r#*0.96, r#*0.02 : t# = 2001.0
line cx#+cos(a#)*r#*0.5, cy#+sin(a#)*r#*0.5, cx#+cos(a#)*r#, cy#+sin(a#)*r#
next a
endif
// main circle
ink 0xffffffff, 0
circle cx#, cy#, r#
line cx#-r#, cy#, cx#+r#, cy#
line cx#, cy#-r#, cx#, cy#+r#
// A (red), PerpA (orange, faded), and B (blue).
ink 0xffff0000, 0 : line cx#, cy#, cx#+vecA.x*r#, cy#+vecA.y*r#
ink 0xff341800, 0 : line cx#, cy#, cx#+vecPerpA.x*r#, cy#+vecPerpA.y*r#
ink 0xff1040f0, 0 : line cx#, cy#, cx#+vecB.x*r#, cy#+vecB.y*r#
ink 0xffffffff, 0
// A to B angular distance label and vector labels.
if AToB_handedness = -1 then halfA# = minA - maxA*0.5 else halfA# = maxA*0.5 + minA
center text cx#+cos(halfA#)*(r#+25), cy# + sin(halfA#)*(r#+25) - 7, str$(AToB#*AToB_handedness,1)
center text cx#+vecA.x*(r#+25), cy#+vecA.y*(r#+25) - 7, "A"
center text cx#+vecB.x*(r#+25), cy#+vecB.y*(r#+25) - 7, "B"
// an arrow on A pointing in the direction of B.
drawArrow(cx#+cos(minA)*r#, cy#+sin(minA)*r#, cx#+cos(minA)*r# + cos(minA+90)*AToB_handedness*100, cy#+sin(minA)*r# + sin(minA+90)*AToB_handedness*100, 6, 0xffff0000)
// some debug output.
print "A: ", str$(vecA.x,1), ", ", str$(vecA.y,1)
print "B: ", str$(vecB.x,1), ", ", str$(vecB.y,1)
print "A.B: ", str$(ADotB#,1), " (", str$(AToB#,1), ")"
print "PerpA.B: ", str$(PerpADotB#,1), " (", str$(acos(PerpADotB#),1), ")"
print "A to B Handedness: ", AToB_handedness, " (", left$("left", 4*(AToB_handedness=-1)), left$("right", 5*(AToB_handedness=1)), ")"
center text scrW/2, scrH - 40, "Left-click: Set A Vector - Right-click: Set B Vector"
sync
cls 0
`nice wait 20
loop
// by: neuro fuzzy
function drawArrow(fromx,fromy,tox,toy,size,color as dword)
line fromx,fromy,tox,toy
//type 2, arrow
x=fromx-tox
y=fromy-toy
d#=sqrt(x*x+y*y)
x2#=x/d#
y2#=y/d# `<x1#,x2#> is just the direction from <tox,toy> to <fromx,fromy>
line tox,toy,tox+size*0.707106781*(x2#-y2#),toy+size*0.707106781*(x2#+y2#)
line tox,toy,tox+size*0.707106781*(y2#+x2#),toy+size*0.707106781*(y2#-x2#)
endfunction
.