(** High-level Unix API for GPX operations *) (** Result binding operators *) let (let*) = Result.bind (* Re-export core modules *) module Types = Gpx.Types module Parser = Gpx.Parser module Writer = Gpx.Writer module Validate = Gpx.Validate module IO = Gpx_io (* Re-export common types *) open Gpx.Types (** Convenience functions for common operations *) (** Read and parse GPX file *) let read = IO.read_file (** Read and parse GPX file with validation *) let read_validated = IO.read_file_validated (** Write GPX to file *) let write = IO.write_file (** Write GPX to file with validation *) let write_validated = IO.write_file_validated (** Write GPX to file with backup *) let write_with_backup = IO.write_file_with_backup (** Convert GPX to string *) let to_string = Writer.write_string (** Parse GPX from string *) let from_string = Parser.parse_string (** Quick validation check *) let is_valid = Validate.is_valid (** Get validation issues *) let validate = Validate.validate_gpx (** Create simple waypoint *) let make_waypoint ~lat ~lon ?name ?desc () = match (latitude lat, longitude lon) with | (Ok lat, Ok lon) -> let wpt = make_waypoint_data lat lon in Ok { wpt with name; desc } | (Error e, _) | (_, Error e) -> Error (Invalid_coordinate e) (** Create simple track from coordinate list *) let make_track_from_coords ~name coords = let make_trkpt (lat, lon) = match (latitude lat, longitude lon) with | (Ok lat, Ok lon) -> Ok (make_waypoint_data lat lon) | (Error e, _) | (_, Error e) -> Error (Invalid_coordinate e) in let rec convert_coords acc = function | [] -> Ok (List.rev acc) | coord :: rest -> match make_trkpt coord with | Ok trkpt -> convert_coords (trkpt :: acc) rest | Error e -> Error e in let* trkpts = convert_coords [] coords in let trkseg = { trkpts; extensions = [] } in Ok { name = Some name; cmt = None; desc = None; src = None; links = []; number = None; type_ = None; extensions = []; trksegs = [trkseg]; } (** Create simple route from coordinate list *) let make_route_from_coords ~name coords = let make_rtept (lat, lon) = match (latitude lat, longitude lon) with | (Ok lat, Ok lon) -> Ok (make_waypoint_data lat lon) | (Error e, _) | (_, Error e) -> Error (Invalid_coordinate e) in let rec convert_coords acc = function | [] -> Ok (List.rev acc) | coord :: rest -> match make_rtept coord with | Ok rtept -> convert_coords (rtept :: acc) rest | Error e -> Error e in let* rtepts = convert_coords [] coords in Ok { name = Some name; cmt = None; desc = None; src = None; links = []; number = None; type_ = None; extensions = []; rtepts; } (** Extract coordinates from waypoints *) let waypoint_coords wpt = (latitude_to_float wpt.lat, longitude_to_float wpt.lon) (** Extract coordinates from track *) let track_coords track = List.fold_left (fun acc trkseg -> List.fold_left (fun acc trkpt -> waypoint_coords trkpt :: acc ) acc trkseg.trkpts ) [] track.trksegs |> List.rev (** Extract coordinates from route *) let route_coords route = List.map waypoint_coords route.rtepts (** Count total points in GPX *) let count_points gpx = let waypoint_count = List.length gpx.waypoints in let route_count = List.fold_left (fun acc route -> acc + List.length route.rtepts ) 0 gpx.routes in let track_count = List.fold_left (fun acc track -> List.fold_left (fun acc trkseg -> acc + List.length trkseg.trkpts ) acc track.trksegs ) 0 gpx.tracks in waypoint_count + route_count + track_count (** Get GPX statistics *) type gpx_stats = { waypoint_count : int; route_count : int; track_count : int; total_points : int; has_elevation : bool; has_time : bool; } let get_stats gpx = let waypoint_count = List.length gpx.waypoints in let route_count = List.length gpx.routes in let track_count = List.length gpx.tracks in let total_points = count_points gpx in let has_elevation = List.exists (fun wpt -> wpt.ele <> None) gpx.waypoints || List.exists (fun route -> List.exists (fun rtept -> rtept.ele <> None) route.rtepts ) gpx.routes || List.exists (fun track -> List.exists (fun trkseg -> List.exists (fun trkpt -> trkpt.ele <> None) trkseg.trkpts ) track.trksegs ) gpx.tracks in let has_time = List.exists (fun wpt -> wpt.time <> None) gpx.waypoints || List.exists (fun route -> List.exists (fun rtept -> rtept.time <> None) route.rtepts ) gpx.routes || List.exists (fun track -> List.exists (fun trkseg -> List.exists (fun trkpt -> trkpt.time <> None) trkseg.trkpts ) track.trksegs ) gpx.tracks in { waypoint_count; route_count; track_count; total_points; has_elevation; has_time } (** Pretty print GPX statistics *) let print_stats gpx = let stats = get_stats gpx in Printf.printf "GPX Statistics:\n"; Printf.printf " Waypoints: %d\n" stats.waypoint_count; Printf.printf " Routes: %d\n" stats.route_count; Printf.printf " Tracks: %d\n" stats.track_count; Printf.printf " Total points: %d\n" stats.total_points; Printf.printf " Has elevation data: %s\n" (if stats.has_elevation then "yes" else "no"); Printf.printf " Has time data: %s\n" (if stats.has_time then "yes" else "no")