///|
/// GPX 1.1 数据模型。
///
/// 对应官方 schema 的复合类型:
/// `gpxType` / `metadataType` / `wptType` / `rteType` / `trkType` / `trksegType` /
/// `linkType` / `personType` / `emailType` / `copyrightType` / `boundsType`。
///
/// 规范来源:
///|
/// `fix` 属性的枚举值。
///
/// ⚠️ 大小写敏感:schema 里是小写的 `none` / `2d` / `3d` / `dgps` / `pps`,
/// 写成 `2D` 是非法的。
pub(all) enum FixType {
FixNone
Fix2d
Fix3d
FixDgps
FixPps
} derive(Eq, Debug)
///|
/// 从 schema 的字符串值解析。非法值返回 `None`。
pub fn FixType::from_string(text : String) -> FixType? {
match text {
"none" => Some(FixNone)
"2d" => Some(Fix2d)
"3d" => Some(Fix3d)
"dgps" => Some(FixDgps)
"pps" => Some(FixPps)
_ => None
}
}
///|
/// 转回 schema 的字符串值。
pub fn FixType::to_string(self : FixType) -> String {
match self {
FixNone => "none"
Fix2d => "2d"
Fix3d => "3d"
FixDgps => "dgps"
FixPps => "pps"
}
}
///|
/// `link` 元素。`href` 属性**必填**。
pub struct Link {
href : String
text : String?
/// schema 里字段名是 `type`,这里改名以避免与语言关键字混淆。
mime_type : String?
} derive(Eq, Debug)
///|
/// `email` 元素。schema 把它拆成 `id` 和 `domain` 两个**都必填**的属性
/// (GPX 1.0 里是一个完整的 `` 文本节点,1.1 改了)。
pub struct Email {
id : String
domain : String
} derive(Eq, Debug)
///|
/// `person` 元素,用于 `metadata/author`。
pub struct Person {
name : String?
email : Email?
link : Link?
} derive(Eq, Debug)
///|
/// `copyright` 元素。`author` 属性**必填**。
pub struct Copyright {
author : String
/// `xsd:gYear`,原样保留文本形式(可能是负年份或带时区)。
year : String?
license : String?
} derive(Eq, Debug)
///|
/// `bounds` 元素。四个属性**全部必填**,且都经过坐标范围校验。
pub struct Bounds {
min_lat : Latitude
min_lon : Longitude
max_lat : Latitude
max_lon : Longitude
} derive(Eq, Debug)
///|
/// 构造包围盒。四个坐标都必须已通过各自类型的范围校验。
pub fn Bounds::new(
min_lat : Latitude,
min_lon : Longitude,
max_lat : Latitude,
max_lon : Longitude,
) -> Bounds {
{ min_lat, min_lon, max_lat, max_lon, }
}
///|
/// `metadata` 元素(GPX 1.1 新增;1.0 里这些字段直接挂在根下)。
pub struct Metadata {
name : String?
desc : String?
author : Person?
copyright : Copyright?
links : Array[Link]
/// `xsd:dateTime`,原样保留文本形式。
time : String?
keywords : String?
bounds : Bounds?
/// `extensions` 的**原始内部 XML 文本**,用于无损往返。
extensions : String?
} derive(Eq, Debug)
///|
/// 航点 / 轨迹点(`wptType`)。
///
/// schema 规定子元素分三段且**顺序固定**:
/// 位置信息 → 描述信息 → 精度信息。
pub struct Waypoint {
lat : Latitude
lon : Longitude
// —— 位置信息 ——
ele : Double?
time : String?
magvar : Degrees?
geoid_height : Double?
// —— 描述信息 ——
name : String?
cmt : String?
desc : String?
src : String?
links : Array[Link]
sym : String?
wpt_type : String?
// —— 精度信息 ——
fix : FixType?
sat : Int?
hdop : Double?
vdop : Double?
pdop : Double?
age_of_dgps_data : Double?
dgps_id : DgpsStationId?
/// `extensions` 的**原始内部 XML 文本**,用于无损往返。
extensions : String?
} derive(Eq, Debug)
///|
/// 构造一个只有经纬度的最小航点,其余字段全为空。
///
/// 模型字段是只读的:包外**既不能写结构体字面量,也不能改字段**。
/// 所以要程序化生成 GPX(而不只是回写解析出来的数据),必须走构造函数。
/// 字段类型自带范围校验(`Latitude` 只能由 `from_double` / `from_string` 产出),
/// 因此这里不需要再检查一遍。
pub fn Waypoint::new(lat : Latitude, lon : Longitude) -> Waypoint {
{
lat,
lon,
ele: None,
time: None,
magvar: None,
geoid_height: None,
name: None,
cmt: None,
desc: None,
src: None,
links: [],
sym: None,
wpt_type: None,
fix: None,
sat: None,
hdop: None,
vdop: None,
pdop: None,
age_of_dgps_data: None,
dgps_id: None,
extensions: None,
}
}
///|
/// 返回设置了高程的副本,其余字段原样保留。
pub fn Waypoint::with_ele(self : Waypoint, ele : Double?) -> Waypoint {
{ ..self, ele, }
}
///|
/// 返回设置了时间的副本,其余字段原样保留。
pub fn Waypoint::with_time(self : Waypoint, time : String?) -> Waypoint {
{ ..self, time, }
}
///|
/// 返回设置了名称的副本,其余字段原样保留。
pub fn Waypoint::with_name(self : Waypoint, name : String?) -> Waypoint {
{ ..self, name, }
}
///|
/// `rte` 元素。
pub struct Route {
name : String?
cmt : String?
desc : String?
src : String?
links : Array[Link]
number : Int?
route_type : String?
extensions : String?
points : Array[Waypoint]
} derive(Eq, Debug)
///|
/// `trkseg` 元素。
pub struct TrackSegment {
points : Array[Waypoint]
extensions : String?
} derive(Eq, Debug)
///|
/// 构造一个轨迹段。
pub fn TrackSegment::new(points : Array[Waypoint]) -> TrackSegment {
{ points, extensions: None, }
}
///|
/// `trk` 元素。
pub struct Track {
name : String?
cmt : String?
desc : String?
src : String?
links : Array[Link]
number : Int?
track_type : String?
extensions : String?
segments : Array[TrackSegment]
} derive(Eq, Debug)
///|
/// 构造一条轨迹。
pub fn Track::new(segments : Array[TrackSegment]) -> Track {
{
name: None,
cmt: None,
desc: None,
src: None,
links: [],
number: None,
track_type: None,
extensions: None,
segments,
}
}
///|
/// GPX 文档根(`gpxType`)。
pub struct Gpx {
/// schema 规定固定为 `"1.1"`。
version : String
/// 创建该文档的软件名称或 URL,**必填**。
creator : String
metadata : Metadata?
waypoints : Array[Waypoint]
routes : Array[Route]
tracks : Array[Track]
extensions : String?
} derive(Eq, Debug)
///|
/// 构造一个空的 GPX 1.1 文档。`version` 按 schema 固定为 `"1.1"`。
pub fn Gpx::new(creator : String) -> Gpx {
{
version: "1.1",
creator,
metadata: None,
waypoints: [],
routes: [],
tracks: [],
extensions: None,
}
}