70 lines
2.4 KiB
Erlang
70 lines
2.4 KiB
Erlang
-module(bearings).
|
|
|
|
%% API
|
|
-export([angle_sub_degrees/2,test/0]).
|
|
|
|
-define(RealAngleMultiplier,16#10000000000).
|
|
-define(DegreesPerTurn,360).
|
|
-define(Precision,9).
|
|
%%%===================================================================
|
|
%%% API
|
|
%%%===================================================================
|
|
|
|
%%--------------------------------------------------------------------
|
|
%% @doc
|
|
%% @spec
|
|
%% @end
|
|
%%--------------------------------------------------------------------
|
|
%%
|
|
angle_sub_degrees(B1,B2) when is_integer(B1), is_integer(B2) ->
|
|
angle_sub(B2-B1,?DegreesPerTurn);
|
|
angle_sub_degrees(B1,B2) ->
|
|
NewB1 = trunc(B1*?RealAngleMultiplier),
|
|
NewB2 = trunc(B2*?RealAngleMultiplier),
|
|
round(angle_sub(NewB2 - NewB1,
|
|
?DegreesPerTurn*?RealAngleMultiplier)
|
|
/?RealAngleMultiplier,?Precision).
|
|
|
|
%%%===================================================================
|
|
%%% Internal functions
|
|
%%%===================================================================
|
|
|
|
%% delta normalises the angle difference. Consider a turn from 350 degrees
|
|
%% to 20 degrees. Subtraction results in 330 degress. This is equivalent of
|
|
%% a turn in the other direction of 30 degrees, thus 330 degrees is equal
|
|
%% to -30 degrees.
|
|
|
|
|
|
angle_sub(Value,TurnSize) ->
|
|
NormalisedValue = Value rem TurnSize,
|
|
minimise_angle(NormalisedValue,TurnSize).
|
|
|
|
% X rem Turn result in 0..Turn for X > 0 and -Turn..0 for X < 0
|
|
% specification requires -Turn/2 < X < Turn/2. This is achieved
|
|
% by adding or removing a turn as required.
|
|
% bsr 1 divides an integer by 2
|
|
minimise_angle(Angle,Turn) when Angle + (Turn bsr 1) < 0 ->
|
|
Angle+Turn;
|
|
minimise_angle(Angle,Turn) when Angle - (Turn bsr 1) > 0 ->
|
|
Angle-Turn;
|
|
minimise_angle(Angle,_) ->
|
|
Angle.
|
|
|
|
round(Number,Precision) ->
|
|
P = math:pow(10,Precision),
|
|
round(Number*P)/P.
|
|
|
|
test() ->
|
|
25 = angle_sub_degrees(20,45),
|
|
90 = angle_sub_degrees(-45,45),
|
|
175 = angle_sub_degrees(-85,90),
|
|
-175 = angle_sub_degrees(-95,90),
|
|
170 = angle_sub_degrees(-45,125),
|
|
-170 = angle_sub_degrees(-45,145),
|
|
-118.1184 = angle_sub_degrees( 29.4803,-88.6381),
|
|
-139.583283124=angle_sub_degrees(-70099.742338109,29840.674378767),
|
|
-72.343918514=angle_sub_degrees( -165313.66662974,33693.989451746),
|
|
-161.50295231=angle_sub_degrees( 1174.8380510598,-154146.66490125),
|
|
37.298855589=angle_sub_degrees( 60175.773067955,42213.071923544),
|
|
|
|
passed.
|