GPS Exchange Format library/CLI in OCaml
1(** High-level Unix API for GPX operations *) 2 3(** Result binding operators *) 4let (let*) = Result.bind 5 6(* Re-export IO module *) 7module IO = Gpx_io 8 9(* Re-export common types *) 10open Gpx 11 12(** Convenience functions for common operations *) 13 14(** Read and parse GPX file *) 15let read = IO.read_file 16 17(** Write GPX to file *) 18let write = IO.write_file 19 20(** Write GPX to file with backup *) 21let write_with_backup = IO.write_file_with_backup 22 23(** Convert GPX to string *) 24let to_string = write_string 25 26(** Parse GPX from string *) 27let from_string = parse_string 28 29(** Quick validation check *) 30let is_valid = is_valid 31 32(** Get validation issues *) 33let validate = validate_gpx 34 35(** Create simple waypoint *) 36let make_waypoint ~lat ~lon ?name ?desc () = 37 match (Coordinate.latitude lat, Coordinate.longitude lon) with 38 | (Ok lat, Ok lon) -> 39 let wpt = Waypoint.make lat lon in 40 let wpt = { wpt with name; desc } in 41 Ok wpt 42 | (Error e, _) | (_, Error e) -> Error (Gpx.Error.invalid_coordinate e) 43 44(** Create simple track from coordinate list *) 45let make_track_from_coords ~name coords = 46 let make_trkpt (lat, lon) = 47 match (Coordinate.latitude lat, Coordinate.longitude lon) with 48 | (Ok lat, Ok lon) -> Ok (Waypoint.make lat lon) 49 | (Error e, _) | (_, Error e) -> Error (Gpx.Error.invalid_coordinate e) 50 in 51 let rec convert_coords acc = function 52 | [] -> Ok (List.rev acc) 53 | coord :: rest -> 54 match make_trkpt coord with 55 | Ok trkpt -> convert_coords (trkpt :: acc) rest 56 | Error e -> Error e 57 in 58 let* _trkpts = convert_coords [] coords in 59 Ok (Track.make_from_coords ~name coords) 60 61(** Create simple route from coordinate list *) 62let make_route_from_coords ~name coords = 63 let make_rtept (lat, lon) = 64 match (Coordinate.latitude lat, Coordinate.longitude lon) with 65 | (Ok lat, Ok lon) -> Ok (Waypoint.make lat lon) 66 | (Error e, _) | (_, Error e) -> Error (Gpx.Error.invalid_coordinate e) 67 in 68 let rec convert_coords acc = function 69 | [] -> Ok (List.rev acc) 70 | coord :: rest -> 71 match make_rtept coord with 72 | Ok rtept -> convert_coords (rtept :: acc) rest 73 | Error e -> Error e 74 in 75 let* _rtepts = convert_coords [] coords in 76 Ok (Route.make_from_coords ~name coords) 77 78(** Extract coordinates from waypoints *) 79let waypoint_coords wpt = Waypoint.to_floats wpt 80 81(** Extract coordinates from track *) 82let track_coords track = Track.to_coords track 83 84(** Extract coordinates from route *) 85let route_coords route = Route.to_coords route 86 87(** Count total points in GPX *) 88let count_points gpx = 89 let waypoints = Doc.waypoints gpx in 90 let routes = Doc.routes gpx in 91 let tracks = Doc.tracks gpx in 92 List.length waypoints + 93 List.fold_left (fun acc r -> acc + List.length (Route.points r)) 0 routes + 94 List.fold_left (fun acc t -> acc + Track.point_count t) 0 tracks 95 96(** Get GPX statistics *) 97type gpx_stats = { 98 waypoint_count : int; 99 route_count : int; 100 track_count : int; 101 total_points : int; 102 has_elevation : bool; 103 has_time : bool; 104} 105 106let stats gpx = 107 let waypoints = Doc.waypoints gpx in 108 let routes = Doc.routes gpx in 109 let tracks = Doc.tracks gpx in 110 { 111 waypoint_count = List.length waypoints; 112 route_count = List.length routes; 113 track_count = List.length tracks; 114 total_points = count_points gpx; 115 has_elevation = List.exists (fun w -> Waypoint.elevation w <> None) waypoints; 116 has_time = List.exists (fun w -> Waypoint.time w <> None) waypoints; 117 } 118 119(** Pretty print GPX statistics *) 120let print_stats gpx = 121 let stats = stats gpx in 122 Printf.printf "GPX Statistics:\n"; 123 Printf.printf " Waypoints: %d\n" stats.waypoint_count; 124 Printf.printf " Routes: %d\n" stats.route_count; 125 Printf.printf " Tracks: %d\n" stats.track_count; 126 Printf.printf " Total points: %d\n" stats.total_points; 127 Printf.printf " Has elevation data: %s\n" (if stats.has_elevation then "yes" else "no"); 128 Printf.printf " Has time data: %s\n" (if stats.has_time then "yes" else "no")