My agentic slop goes here. Not intended for anyone else!
1(** Longitude module *)
2
3type t = float
4
5let normalize_180 f =
6 let x = mod_float (f +. 180.0) 360.0 in
7 if x < 0.0 then x +. 360.0 -. 180.0
8 else x -. 180.0
9
10let normalize_360 f =
11 let x = mod_float f 360.0 in
12 if x < 0.0 then x +. 360.0 else x
13
14let create f = normalize_180 f
15
16let unsafe_create f = f
17
18let of_dms ~degree ~minute ~second =
19 let sign = if degree < 0 || minute < 0 || second < 0.0 then -1.0 else 1.0 in
20 let d = abs degree in
21 let m = abs minute in
22 let s = abs_float second in
23 let decimal = float_of_int d +. (float_of_int m /. 60.0) +. (s /. 3600.0) in
24 create (sign *. decimal)
25
26let to_float t = t
27
28let to_range_180 t = normalize_180 t
29let to_range_360 t = normalize_360 t
30
31let degree t = int_of_float t
32
33let decimal_minute t =
34 let d = abs_float t in
35 (d -. floor d) *. 60.0
36
37let minute t = int_of_float (decimal_minute t)
38
39let second t =
40 let dm = decimal_minute t in
41 (dm -. floor dm) *. 60.0
42
43let hemisphere t = if t < 0.0 then `W else `E
44
45let add t delta = create (t +. delta)
46let sub t delta = create (t -. delta)
47let neg t = create (-.t)
48let abs t = abs_float t
49
50let equal a b =
51 (* Longitudes wrap around, so normalize before comparing *)
52 normalize_180 a = normalize_180 b
53
54let compare a b = Float.compare (normalize_180 a) (normalize_180 b)
55let ( = ) = equal
56let ( < ) a b = compare a b < 0
57let ( > ) a b = compare a b > 0
58let ( <= ) a b = compare a b <= 0
59let ( >= ) a b = compare a b >= 0
60
61let to_string t = Printf.sprintf "%.6f" t
62
63let format ?(precision = 6) t =
64 Printf.sprintf "%.*f" precision t
65
66let to_dms_string t =
67 let h = match hemisphere t with `E -> "E" | `W -> "W" in
68 let d = abs_float (float_of_int (degree t)) |> int_of_float in
69 let m = minute (abs_float t) in
70 let s = second (abs_float t) in
71 Printf.sprintf "%03d°%02d'%05.2f\"%s" d m s h