Skip to main content

lc_gpx_utils/kml/
model.rs

1#[derive(Debug, Clone, PartialEq)]
2pub struct Style {
3    /// the id, used as the `style_id` field in Placemark  
4    pub id: String,
5    pub icon_style_scale: f64,
6    /// look at <https://kml4earth.appspot.com/icons.html>for instance
7    pub icon_url: String,
8    pub line_style_width: f64,
9}
10
11/// a Point
12/// to have the point on the earth ground, set altitude to 0.0 and altitude_mode to [AltitudeMode::ErelativeToGround]
13#[derive(Debug, Clone, PartialEq)]
14pub struct Point {
15    pub longitude: f64,
16    pub latitude: f64,
17    pub altitude: f64,
18    pub altitude_mode: AltitudeMode,
19}
20
21/// a kml line string.
22#[derive(Debug, Clone, PartialEq)]
23pub struct LineString {
24    pub extrude: u32,
25    pub tessellate: u32,
26    /// the altitude_mode of the points is ignored, altitude_mode of self is used instead
27    pub altitude_mode: AltitudeMode,
28    pub points: Vec<Point>,
29}
30
31/// @todo kml has other modes, for diving under sea, not implemented yet
32#[derive(Debug, Clone, PartialEq)]
33pub enum AltitudeMode {
34    ErelativeToGround,
35    /// 0 is the sea level
36    Eabsolute,
37}
38
39/// a kml place marker, This is what you see in google earth, in the left tab
40#[derive(Debug, Clone, PartialEq)]
41pub struct Placemark {
42    pub name: String,
43    /// description. @todo : support CDATA, so you can have html code in the description
44    pub description: String,
45    /// a reference to the style, without the leading # as in the generated kml file
46    pub style_id: Option<String>,
47    /// a place marker has only one geo_element
48    pub geo_element: GeoElement,
49    pub visible: bool,
50}
51
52/// a kml folder, only contains placemarks or sub-folders
53#[derive(Debug, Clone, PartialEq)]
54pub struct Folder {
55    pub name: String,
56    pub description: String,
57    pub elements: Vec<Element>,
58}
59
60/// a geoelement is the sum type for what is in a placemark
61#[derive(Debug, Clone, PartialEq)]
62pub enum GeoElement {
63    EPoint(Point),
64    ELineString(LineString),
65}
66
67/// a kml element, in this simple model, is either a folder or a placemark,
68/// as you see in google earth or map in the left tab
69#[derive(Debug, Clone, PartialEq)]
70pub enum Element {
71    EFolder(Folder),
72    EPlacemark(Placemark),
73}
74
75/// a kml document, this is the root of the xml tree.
76#[derive(Debug, Clone, PartialEq)]
77pub struct Document {
78    pub name: String,
79    pub description: String,
80    pub styles: Vec<Style>,
81    pub elements: Vec<Element>,
82}
83
84impl From<Placemark> for Element {
85    fn from(e: Placemark) -> Self {
86        Element::EPlacemark(e)
87    }
88}
89
90impl From<Point> for GeoElement {
91    fn from(p: Point) -> Self {
92        GeoElement::EPoint(p)
93    }
94}
95
96impl Placemark {
97    pub fn new_point_on_ground(
98        name: String,
99        description: String,
100        style_id: Option<String>,
101        longitude: f64,
102        latitude: f64,
103    ) -> Self {
104        let geo_element: GeoElement = Point {
105            longitude,
106            latitude,
107            altitude: 0f64,
108            altitude_mode: AltitudeMode::ErelativeToGround,
109        }
110        .into();
111        Placemark {
112            name,
113            description,
114            geo_element,
115            style_id,
116            visible: true,
117        }
118    }
119}
120
121impl From<Folder> for Element {
122    fn from(e: Folder) -> Self {
123        Element::EFolder(e)
124    }
125}
126
127impl Placemark {
128    pub fn new_line(
129        name: String,
130        description: String,
131        style_id: Option<String>,
132        points: Vec<(f64, f64)>,
133    ) -> Self {
134        let points = points
135            .iter()
136            .map(|(longitude, latitude)| Point {
137                longitude: *longitude,
138                latitude: *latitude,
139                altitude: 0f64,
140                altitude_mode: AltitudeMode::ErelativeToGround,
141            })
142            .collect::<Vec<_>>();
143        let geo_element: GeoElement = LineString {
144            extrude: 1,
145            tessellate: 1,
146            altitude_mode: AltitudeMode::ErelativeToGround,
147            points,
148        }
149        .into();
150        Placemark {
151            name,
152            description,
153            style_id,
154            geo_element,
155            visible: true,
156        }
157    }
158}
159
160impl From<LineString> for GeoElement {
161    fn from(ls: LineString) -> Self {
162        GeoElement::ELineString(ls)
163    }
164}