(** Longitude module *) type t = float let normalize_180 f = let x = mod_float (f +. 180.0) 360.0 in if x < 0.0 then x +. 360.0 -. 180.0 else x -. 180.0 let normalize_360 f = let x = mod_float f 360.0 in if x < 0.0 then x +. 360.0 else x let create f = normalize_180 f let unsafe_create f = f let of_dms ~degree ~minute ~second = let sign = if degree < 0 || minute < 0 || second < 0.0 then -1.0 else 1.0 in let d = abs degree in let m = abs minute in let s = abs_float second in let decimal = float_of_int d +. (float_of_int m /. 60.0) +. (s /. 3600.0) in create (sign *. decimal) let to_float t = t let to_range_180 t = normalize_180 t let to_range_360 t = normalize_360 t let degree t = int_of_float t let decimal_minute t = let d = abs_float t in (d -. floor d) *. 60.0 let minute t = int_of_float (decimal_minute t) let second t = let dm = decimal_minute t in (dm -. floor dm) *. 60.0 let hemisphere t = if t < 0.0 then `W else `E let add t delta = create (t +. delta) let sub t delta = create (t -. delta) let neg t = create (-.t) let abs t = abs_float t let equal a b = (* Longitudes wrap around, so normalize before comparing *) normalize_180 a = normalize_180 b let compare a b = Float.compare (normalize_180 a) (normalize_180 b) let ( = ) = equal let ( < ) a b = compare a b < 0 let ( > ) a b = compare a b > 0 let ( <= ) a b = compare a b <= 0 let ( >= ) a b = compare a b >= 0 let to_string t = Printf.sprintf "%.6f" t let format ?(precision = 6) t = Printf.sprintf "%.*f" precision t let to_dms_string t = let h = match hemisphere t with `E -> "E" | `W -> "W" in let d = abs_float (float_of_int (degree t)) |> int_of_float in let m = minute (abs_float t) in let s = second (abs_float t) in Printf.sprintf "%03d°%02d'%05.2f\"%s" d m s h