Skip to main content

gpx/
types.rs

1//! generic types for GPX
2
3pub use crate::parser::time::Time;
4use geo_types::{Geometry, LineString, MultiLineString, Point, Rect};
5#[cfg(feature = "use-serde")]
6use serde::{Deserialize, Serialize};
7
8/// Allowable GPX versions. Currently, only GPX 1.0 and GPX 1.1 are accepted.
9#[derive(Clone, Copy, Debug, PartialEq)]
10#[cfg_attr(feature = "use-serde", derive(Serialize, Deserialize))]
11#[derive(Default)]
12pub enum GpxVersion {
13    #[default]
14    Unknown,
15    Gpx10,
16    Gpx11,
17}
18
19impl std::fmt::Display for GpxVersion {
20    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21        write!(f, "{:?}", self)
22    }
23}
24
25/// Gpx is the root element in the XML file.
26#[derive(Clone, Default, Debug, PartialEq)]
27#[cfg_attr(feature = "use-serde", derive(Serialize, Deserialize))]
28pub struct Gpx {
29    /// Version of the Gpx file.
30    pub version: GpxVersion,
31
32    /// Creator name or URL of the software that created GPX document
33    pub creator: Option<String>,
34
35    /// Metadata about the file.
36    pub metadata: Option<Metadata>,
37
38    /// A list of waypoints.
39    pub waypoints: Vec<Waypoint>,
40
41    /// A list of tracks.
42    pub tracks: Vec<Track>,
43
44    /// A list of routes with a list of point-by-point directions
45    pub routes: Vec<Route>,
46}
47
48/// Information about the copyright holder and any license governing use of this file.
49///
50/// By linking to an appropriate license, you may place your data into the
51/// public domain or grant additional usage rights.
52#[derive(Clone, Default, Debug, PartialEq)]
53#[cfg_attr(feature = "use-serde", derive(Serialize, Deserialize))]
54pub struct GpxCopyright {
55    pub author: Option<String>,
56    pub year: Option<i32>,
57    pub license: Option<String>,
58}
59
60/// Metadata is information about the GPX file, author, and copyright restrictions.
61///
62/// Providing rich, meaningful information about your GPX files allows others to
63/// search for and use your GPS data.
64#[derive(Clone, Default, Debug, PartialEq)]
65#[cfg_attr(feature = "use-serde", derive(Serialize, Deserialize))]
66pub struct Metadata {
67    /// The name of the GPX file.
68    pub name: Option<String>,
69
70    /// A description of the contents of the GPX file.
71    pub description: Option<String>,
72
73    /// The person or organization who created the GPX file.
74    pub author: Option<Person>,
75
76    /// URLs associated with the location described in the file.
77    pub links: Vec<Link>,
78
79    /// The creation date of the file.
80    pub time: Option<Time>,
81
82    /// Keywords associated with the file. Search engines or databases can use
83    /// this information to classify the data.
84    pub keywords: Option<String>,
85
86    /// Information about the copyright holder and any license governing use of this file.
87    pub copyright: Option<GpxCopyright>,
88
89    /// Bounds for the tracks in the GPX.
90    pub bounds: Option<Rect<f64>>,
91    /*extensions: GpxExtensionsType,*/
92}
93
94/// Route represents an ordered list of waypoints representing a series of turn points leading to a destination.
95#[derive(Clone, Default, Debug, PartialEq)]
96#[cfg_attr(feature = "use-serde", derive(Serialize, Deserialize))]
97pub struct Route {
98    /// GPS name of route.
99    pub name: Option<String>,
100
101    /// GPS comment for route.
102    pub comment: Option<String>,
103
104    /// User description of route.
105    pub description: Option<String>,
106
107    /// Source of data. Included to give user some idea of reliability
108    /// and accuracy of data.
109    pub source: Option<String>,
110
111    /// Links to external information about the route.
112    pub links: Vec<Link>,
113
114    /// GPS route number.
115    pub number: Option<u32>,
116
117    /// Type (classification) of route.
118    pub type_: Option<String>,
119
120    /// Each Waypoint holds the coordinates, elevation, timestamp, and metadata
121    /// for a single point in a track.
122    pub points: Vec<Waypoint>,
123}
124
125impl Route {
126    /// Gives the linestring of the segment's points, the sequence of points that
127    /// comprises the track segment.
128    pub fn linestring(&self) -> LineString<f64> {
129        self.points.iter().map(|wpt| wpt.point()).collect()
130    }
131
132    /// Creates a new Route with default values.
133    ///
134    /// ```
135    /// extern crate gpx;
136    /// extern crate geo_types;
137    ///
138    /// use gpx::{Route, Waypoint};
139    /// use geo_types::Point;
140    ///
141    /// fn main() {
142    ///     let mut route: Route = Route::new();
143    ///
144    ///     let point = Waypoint::new(Point::new(-121.97, 37.24));
145    ///     route.points.push(point);
146    /// }
147    ///
148    pub fn new() -> Route {
149        Default::default()
150    }
151}
152
153impl From<Route> for Geometry<f64> {
154    fn from(route: Route) -> Geometry<f64> {
155        Geometry::LineString(route.linestring())
156    }
157}
158
159/// Track represents an ordered list of points describing a path.
160#[derive(Clone, Default, Debug, PartialEq)]
161#[cfg_attr(feature = "use-serde", derive(Serialize, Deserialize))]
162pub struct Track {
163    /// GPS name of track.
164    pub name: Option<String>,
165
166    /// GPS comment for track.
167    pub comment: Option<String>,
168
169    /// User description of track.
170    pub description: Option<String>,
171
172    /// Source of data. Included to give user some idea of reliability
173    /// and accuracy of data.
174    pub source: Option<String>,
175
176    /// Links to external information about the track.
177    pub links: Vec<Link>,
178
179    /// Type (classification) of track.
180    pub type_: Option<String>,
181
182    /// GPS number of track
183    pub number: Option<u32>,
184
185    /// A Track Segment holds a list of Track Points which are logically
186    /// connected in order. To represent a single GPS track where GPS reception
187    /// was lost, or the GPS receiver was turned off, start a new Track Segment
188    /// for each continuous span of track data.
189    pub segments: Vec<TrackSegment>,
190    /* extensions */
191    /* trkSeg */
192}
193
194impl Track {
195    /// Gives the multi-linestring that this track represents, which is multiple
196    /// linestrings.
197    pub fn multilinestring(&self) -> MultiLineString<f64> {
198        self.segments.iter().map(|seg| seg.linestring()).collect()
199    }
200
201    /// Creates a new Track with default values.
202    ///
203    /// ```
204    /// use gpx::{Track, TrackSegment};
205    ///
206    /// let mut track: Track = Track::new();
207    ///
208    /// let segment = TrackSegment::new();
209    /// track.segments.push(segment);
210    pub fn new() -> Track {
211        Default::default()
212    }
213}
214
215impl From<Track> for Geometry<f64> {
216    fn from(track: Track) -> Geometry<f64> {
217        Geometry::MultiLineString(track.multilinestring())
218    }
219}
220
221/// TrackSegment represents a list of track points.
222///
223/// This TrackSegment holds a list of Track Points which are logically
224/// connected in order. To represent a single GPS track where GPS reception
225/// was lost, or the GPS receiver was turned off, start a new Track Segment
226/// for each continuous span of track data.
227#[derive(Clone, Default, Debug, PartialEq)]
228#[cfg_attr(feature = "use-serde", derive(Serialize, Deserialize))]
229pub struct TrackSegment {
230    /// Each Waypoint holds the coordinates, elevation, timestamp, and metadata
231    /// for a single point in a track.
232    pub points: Vec<Waypoint>,
233    /* extensions */
234}
235
236impl TrackSegment {
237    /// Gives the linestring of the segment's points, the sequence of points that
238    /// comprises the track segment.
239    pub fn linestring(&self) -> LineString<f64> {
240        self.points.iter().map(|wpt| wpt.point()).collect()
241    }
242
243    /// Creates a new TrackSegment with default values.
244    ///
245    /// ```
246    /// extern crate gpx;
247    /// extern crate geo_types;
248    ///
249    /// use gpx::{TrackSegment, Waypoint};
250    /// use geo_types::Point;
251    ///
252    /// fn main() {
253    ///     let mut trkseg: TrackSegment = TrackSegment::new();
254    ///
255    ///     let point = Waypoint::new(Point::new(-121.97, 37.24));
256    ///     trkseg.points.push(point);
257    /// }
258    pub fn new() -> TrackSegment {
259        Default::default()
260    }
261}
262
263impl From<TrackSegment> for Geometry<f64> {
264    fn from(track_segment: TrackSegment) -> Geometry<f64> {
265        Geometry::LineString(track_segment.linestring())
266    }
267}
268
269// A Version of geo_types::Point that has the Default trait implemented, which
270// allows us to initialise the GpxPoint with default values compactly
271// in the Waypoint::new function below
272#[derive(Clone, Debug, PartialEq)]
273#[cfg_attr(feature = "use-serde", derive(Serialize, Deserialize))]
274struct GpxPoint(Point<f64>);
275
276impl Default for GpxPoint {
277    fn default() -> GpxPoint {
278        GpxPoint(Point::new(0 as f64, 0 as f64))
279    }
280}
281
282/// Waypoint represents a waypoint, point of interest, or named feature on a
283/// map.
284#[derive(Clone, Default, Debug, PartialEq)]
285#[cfg_attr(feature = "use-serde", derive(Serialize, Deserialize))]
286pub struct Waypoint {
287    /// The geographical point.
288    point: GpxPoint,
289
290    /// Elevation (in meters) of the point.
291    pub elevation: Option<f64>,
292
293    /// Speed (in meters per second) (only in GPX 1.0)
294    pub speed: Option<f64>,
295
296    /// Creation/modification timestamp for element. Date and time in are in
297    /// Univeral Coordinated Time (UTC), not local time! Conforms to ISO 8601
298    /// specification for date/time representation. Fractional seconds are
299    /// allowed for millisecond timing in tracklogs.
300    pub time: Option<Time>,
301
302    /// The GPS name of the waypoint. This field will be transferred to and
303    /// from the GPS. GPX does not place restrictions on the length of this
304    /// field or the characters contained in it. It is up to the receiving
305    /// application to validate the field before sending it to the GPS.
306    pub name: Option<String>,
307
308    /// GPS waypoint comment. Sent to GPS as comment.
309    pub comment: Option<String>,
310
311    /// A text description of the element. Holds additional information about
312    /// the element intended for the user, not the GPS.
313    pub description: Option<String>,
314
315    /// Source of data. Included to give user some idea of reliability and
316    /// accuracy of data. "Garmin eTrex", "USGS quad Boston North", e.g.
317    pub source: Option<String>,
318
319    /// Links to additional information about the waypoint.
320    pub links: Vec<Link>,
321
322    /// Text of GPS symbol name. For interchange with other programs, use the
323    /// exact spelling of the symbol as displayed on the GPS. If the GPS
324    /// abbreviates words, spell them out.
325    pub symbol: Option<String>,
326
327    /// Type (classification) of the waypoint.
328    pub type_: Option<String>,
329
330    // <magvar> degreesType </magvar> [0..1] ?
331    /// Height of geoid in meters above WGS 84. This correspond to the sea level.
332    pub geoidheight: Option<f64>,
333
334    /// Type of GPS fix. `none` means GPS had no fix. To signify "the fix info
335    /// is unknown", leave out `fix` entirely. Value comes from the list
336    /// `{'none'|'2d'|'3d'|'dgps'|'pps'}`, where `pps` means that the military
337    /// signal was used.
338    pub fix: Option<Fix>,
339
340    /// Number of satellites used to calculate the GPX fix.
341    pub sat: Option<u64>,
342
343    /// Horizontal dilution of precision.
344    pub hdop: Option<f64>,
345
346    /// Vertical dilution of precision.
347    pub vdop: Option<f64>,
348
349    /// Positional dilution of precision.
350    pub pdop: Option<f64>,
351
352    #[deprecated = "Prior to gpx 0.9.0 version crate used incorrect field to parse and emit DGPS age. Use `dgps_age` instead. See https://github.com/georust/gpx/issues/21"]
353    pub age: Option<f64>,
354
355    /// Number of seconds since last DGPS update, from the <ageofdgpsdata> element.
356    pub dgps_age: Option<f64>,
357
358    /// ID of DGPS station used in differential correction, in the range [0, 1023].
359    pub dgpsid: Option<u16>,
360    // <extensions> extensionsType </extensions> [0..1] ?
361}
362
363impl Waypoint {
364    /// Gives the geographical point of the waypoint.
365    ///
366    /// ```
367    /// extern crate geo_types;
368    /// extern crate gpx;
369    ///
370    /// use gpx::Waypoint;
371    /// use geo_types::Point;
372    ///
373    /// fn main() {
374    ///     // Kind of useless, but it shows the point.
375    ///     let wpt = Waypoint::new(Point::new(-121.97, 37.24));
376    ///     let point = wpt.point();
377    ///
378    ///     println!("waypoint latitude: {}, longitude: {}", point.x(), point.y());
379    /// }
380    /// ```
381    pub fn point(&self) -> Point<f64> {
382        self.point.0 //.0 to extract the geo_types::Point from the tuple struct GpxPoint
383    }
384
385    /// Creates a new Waypoint from a given geographical point.
386    ///
387    /// ```
388    /// extern crate geo_types;
389    /// extern crate gpx;
390    ///
391    /// use gpx::Waypoint;
392    /// use geo_types::Point;
393    ///
394    /// fn main() {
395    ///     let point = Point::new(-121.97, 37.24);
396    ///
397    ///     let mut wpt = Waypoint::new(point);
398    ///     wpt.elevation = Some(553.21);
399    /// }
400    /// ```
401    pub fn new(point: Point<f64>) -> Waypoint {
402        Waypoint {
403            point: GpxPoint(point),
404            ..Default::default()
405        }
406    }
407}
408
409impl From<Waypoint> for Geometry<f64> {
410    fn from(waypoint: Waypoint) -> Geometry<f64> {
411        Geometry::Point(waypoint.point())
412    }
413}
414
415/// Person represents a person or organization.
416#[derive(Clone, Default, Debug, PartialEq)]
417#[cfg_attr(feature = "use-serde", derive(Serialize, Deserialize))]
418pub struct Person {
419    /// Name of person or organization.
420    pub name: Option<String>,
421
422    /// Email address.
423    pub email: Option<String>,
424
425    /// Link to Web site or other external information about person.
426    pub link: Option<Link>,
427}
428
429/// Link represents a link to an external resource.
430///
431/// An external resource could be a web page, digital photo,
432/// video clip, etc., with additional information.
433#[derive(Clone, Default, Debug, PartialEq)]
434#[cfg_attr(feature = "use-serde", derive(Serialize, Deserialize))]
435pub struct Link {
436    /// URL of hyperlink.
437    pub href: String,
438
439    /// Text of hyperlink.
440    pub text: Option<String>,
441
442    /// Mime type of content (image/jpeg)
443    pub type_: Option<String>,
444}
445
446/// Type of the GPS fix.
447#[derive(Clone, Debug, PartialEq)]
448#[cfg_attr(feature = "use-serde", derive(Serialize, Deserialize))]
449pub enum Fix {
450    /// The GPS had no fix. To signify "the fix info is unknown", leave out the Fix entirely.
451    None,
452    /// 2D fix gives only longitude and latitude. It needs a minimum of 3 satellites.
453    TwoDimensional,
454    /// 3D fix gives longitude, latitude and altitude. It needs a minimum of 4 satellites.
455    ThreeDimensional,
456    /// Differential Global Positioning System.
457    DGPS,
458    /// Military signal.
459    PPS,
460    /// Other values that are not in the specification.
461    Other(String),
462}