My agentic slop goes here. Not intended for anyone else!
1(** Geographic vector module *)
2
3type t = {
4 dx : float; (* km *)
5 dy : float; (* km *)
6}
7
8let deg_to_rad = Float.pi /. 180.0
9let rad_to_deg = 180.0 /. Float.pi
10
11let create_cartesian ~dx ~dy = { dx; dy }
12
13let create_polar ~heading ~distance =
14 (* Convert heading to mathematical angle (east = 0, counterclockwise) *)
15 let angle = (90.0 -. heading) *. deg_to_rad in
16 {
17 dx = distance *. cos angle;
18 dy = distance *. sin angle;
19 }
20
21let between p1 p2 =
22 (* Calculate vector between two coordinates *)
23 let dist = Coord.distance_haversine p1 p2 in
24 let bearing = Coord.bearing p1 p2 in
25 create_polar ~heading:bearing ~distance:dist
26
27let dx t = t.dx
28let dy t = t.dy
29
30let heading t =
31 (* Convert from mathematical angle to geographic heading *)
32 let angle = atan2 t.dy t.dx *. rad_to_deg in
33 mod_float (90.0 -. angle +. 360.0) 360.0
34
35let distance t =
36 sqrt (t.dx ** 2.0 +. t.dy ** 2.0)
37
38let add v1 v2 = {
39 dx = v1.dx +. v2.dx;
40 dy = v1.dy +. v2.dy;
41}
42
43let sub v1 v2 = {
44 dx = v1.dx -. v2.dx;
45 dy = v1.dy -. v2.dy;
46}
47
48let scale v factor = {
49 dx = v.dx *. factor;
50 dy = v.dy *. factor;
51}
52
53let neg v = {
54 dx = -.v.dx;
55 dy = -.v.dy;
56}
57
58let rotate v degrees =
59 let angle = degrees *. deg_to_rad in
60 let cos_a = cos angle in
61 let sin_a = sin angle in
62 {
63 dx = v.dx *. cos_a -. v.dy *. sin_a;
64 dy = v.dx *. sin_a +. v.dy *. cos_a;
65 }
66
67let apply coord v =
68 Coord.offset coord ~heading:(heading v) ~distance:(distance v)
69
70let to_string t =
71 Printf.sprintf "Vector(heading=%.2f°, distance=%.2fkm)" (heading t) (distance t)