-
Notifications
You must be signed in to change notification settings - Fork 22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add kml:Link, kml:Icon #28
Changes from 4 commits
371945e
6e83cff
4ec2c4e
0b86a26
8b0a6ad
5f70a96
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,8 +17,8 @@ use crate::types::geom_props::GeomProps; | |
use crate::types::{ | ||
self, coords_from_str, BalloonStyle, ColorMode, Coord, CoordType, Element, Geometry, Icon, | ||
IconStyle, Kml, KmlDocument, KmlVersion, LabelStyle, LineString, LineStyle, LinearRing, | ||
ListStyle, Location, MultiGeometry, Orientation, Pair, Placemark, Point, PolyStyle, Polygon, | ||
Scale, Style, StyleMap, Units, Vec2, | ||
LinkTypeIcon, LinkTypeLink, ListStyle, Location, MultiGeometry, Orientation, Pair, Placemark, | ||
Point, PolyStyle, Polygon, RefreshMode, Scale, Style, StyleMap, Units, Vec2, ViewRefreshMode, | ||
}; | ||
|
||
/// Main struct for reading KML documents | ||
|
@@ -158,7 +158,12 @@ where | |
elements.push(Kml::BalloonStyle(self.read_balloon_style(attrs)?)) | ||
} | ||
b"IconStyle" => elements.push(Kml::IconStyle(self.read_icon_style(attrs)?)), | ||
b"Icon" => elements.push(Kml::Icon(self.read_icon()?)), | ||
b"Link" => { | ||
elements.push(Kml::LinkTypeLink(self.read_link_type_link(attrs)?)) | ||
} | ||
b"Icon" => { | ||
elements.push(Kml::LinkTypeIcon(self.read_link_type_icon(attrs)?)) | ||
} | ||
b"LabelStyle" => { | ||
elements.push(Kml::LabelStyle(self.read_label_style(attrs)?)) | ||
} | ||
|
@@ -560,7 +565,7 @@ where | |
}); | ||
} | ||
} | ||
b"Icon" => icon_style.icon = self.read_icon()?, | ||
b"Icon" => icon_style.icon = self.read_basic_link_type_icon()?, | ||
b"color" => icon_style.color = self.read_str()?, | ||
b"colorMode" => { | ||
icon_style.color_mode = self.read_str()?.parse::<ColorMode>()? | ||
|
@@ -578,7 +583,7 @@ where | |
Ok(icon_style) | ||
} | ||
|
||
fn read_icon(&mut self) -> Result<Icon, Error> { | ||
fn read_basic_link_type_icon(&mut self) -> Result<Icon, Error> { | ||
let mut href = String::new(); | ||
loop { | ||
let mut e = self.reader.read_event(&mut self.buf)?; | ||
|
@@ -599,6 +604,102 @@ where | |
Ok(Icon { href }) | ||
} | ||
|
||
fn read_link_type_icon( | ||
&mut self, | ||
attrs: HashMap<String, String>, | ||
) -> Result<LinkTypeIcon, Error> { | ||
let mut icon = LinkTypeIcon { | ||
attrs, | ||
..Default::default() | ||
}; | ||
loop { | ||
let mut e = self.reader.read_event(&mut self.buf)?; | ||
match e { | ||
Event::Start(ref mut e) => match e.local_name() { | ||
b"href" => icon.href = Some(self.read_str()?), | ||
b"refreshMode" => { | ||
icon.refresh_mode = match self.read_str()?.as_str() { | ||
"onChange" => Some(RefreshMode::OnChange), | ||
"onInterval" => Some(RefreshMode::OnInterval), | ||
"onExpire" => Some(RefreshMode::OnExpire), | ||
_ => None, | ||
} | ||
} | ||
b"refreshInterval" => icon.refresh_interval = self.read_float()?, | ||
b"viewRefreshMode" => { | ||
icon.view_refresh_mode = match self.read_str()?.as_str() { | ||
"never" => Some(ViewRefreshMode::Never), | ||
"onRequest" => Some(ViewRefreshMode::OnRequest), | ||
"onStop" => Some(ViewRefreshMode::OnStop), | ||
"onRegion" => Some(ViewRefreshMode::OnRegion), | ||
_ => None, | ||
} | ||
} | ||
b"viewRefreshTime" => icon.view_refresh_time = self.read_float()?, | ||
b"viewBoundScale" => icon.view_bound_scale = self.read_float()?, | ||
b"viewFormat" => icon.view_format = Some(self.read_str()?), | ||
b"httpQuery" => icon.http_query = Some(self.read_str()?), | ||
_ => {} | ||
}, | ||
Event::End(ref mut e) => { | ||
if e.local_name() == b"Icon" { | ||
break; | ||
} | ||
} | ||
_ => break, | ||
} | ||
} | ||
Ok(icon) | ||
} | ||
|
||
fn read_link_type_link( | ||
&mut self, | ||
attrs: HashMap<String, String>, | ||
) -> Result<LinkTypeLink, Error> { | ||
let mut link = LinkTypeLink { | ||
attrs, | ||
..Default::default() | ||
}; | ||
loop { | ||
let mut e = self.reader.read_event(&mut self.buf)?; | ||
match e { | ||
Event::Start(ref mut e) => match e.local_name() { | ||
b"href" => link.href = Some(self.read_str()?), | ||
b"refreshMode" => { | ||
link.refresh_mode = match self.read_str()?.as_str() { | ||
"onChange" => Some(RefreshMode::OnChange), | ||
"onInterval" => Some(RefreshMode::OnInterval), | ||
"onExpire" => Some(RefreshMode::OnExpire), | ||
_ => None, | ||
} | ||
} | ||
b"refreshInterval" => link.refresh_interval = self.read_float()?, | ||
b"viewRefreshMode" => { | ||
link.view_refresh_mode = match self.read_str()?.as_str() { | ||
"never" => Some(ViewRefreshMode::Never), | ||
"onRequest" => Some(ViewRefreshMode::OnRequest), | ||
"onStop" => Some(ViewRefreshMode::OnStop), | ||
"onRegion" => Some(ViewRefreshMode::OnRegion), | ||
_ => None, | ||
} | ||
} | ||
b"viewRefreshTime" => link.view_refresh_time = self.read_float()?, | ||
b"viewBoundScale" => link.view_bound_scale = self.read_float()?, | ||
b"viewFormat" => link.view_format = Some(self.read_str()?), | ||
b"httpQuery" => link.http_query = Some(self.read_str()?), | ||
_ => {} | ||
}, | ||
Event::End(ref mut e) => { | ||
if e.local_name() == b"Link" { | ||
break; | ||
} | ||
} | ||
_ => break, | ||
} | ||
} | ||
Ok(link) | ||
} | ||
|
||
fn read_balloon_style( | ||
&mut self, | ||
attrs: HashMap<String, String>, | ||
|
@@ -930,6 +1031,64 @@ mod tests { | |
); | ||
} | ||
|
||
#[test] | ||
fn test_read_link_type_link() { | ||
let kml_str = r#"<Link id="Some ID"> | ||
<href>/path/to/local/resource</href> | ||
<refreshMode>onChange</refreshMode> | ||
<refreshInterval>4</refreshInterval> | ||
<viewRefreshMode>onStop</viewRefreshMode> | ||
<viewRefreshTime>4</viewRefreshTime> | ||
<viewBoundScale>1</viewBoundScale> | ||
<viewFormat></viewFormat> | ||
</Link>"#; | ||
|
||
let mut attrs = HashMap::new(); | ||
attrs.insert("id".to_string(), "Some ID".to_string()); | ||
|
||
let l: Kml = kml_str.parse().unwrap(); | ||
assert_eq!( | ||
l, | ||
Kml::LinkTypeLink(LinkTypeLink { | ||
href: Some("/path/to/local/resource".to_string()), | ||
refresh_mode: Some(types::RefreshMode::OnChange), | ||
view_refresh_mode: Some(types::ViewRefreshMode::OnStop), | ||
view_format: Some(String::new()), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In this test, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the test and behavior work as-is, since I would assume |
||
attrs, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we want to store the attributes? I see some other types do, but most ignore them. The spec only allows three here: As an aside, I could see how many attributes could be an issue with memory. Perhaps that's a separate issue to be solved in another PR. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think enough of the other types include |
||
..Default::default() | ||
}) | ||
); | ||
} | ||
|
||
#[test] | ||
fn test_read_link_type_icon() { | ||
let kml_str = r#"<Icon id="Some ID"> | ||
<href>/path/to/local/resource</href> | ||
<refreshMode>onChange</refreshMode> | ||
<refreshInterval>4</refreshInterval> | ||
<viewRefreshMode>onStop</viewRefreshMode> | ||
<viewRefreshTime>4</viewRefreshTime> | ||
<viewBoundScale>1</viewBoundScale> | ||
<viewFormat></viewFormat> | ||
</Icon>"#; | ||
|
||
let mut attrs = HashMap::new(); | ||
attrs.insert("id".to_string(), "Some ID".to_string()); | ||
|
||
let l: Kml = kml_str.parse().unwrap(); | ||
assert_eq!( | ||
l, | ||
Kml::LinkTypeIcon(LinkTypeIcon { | ||
href: Some("/path/to/local/resource".to_string()), | ||
refresh_mode: Some(types::RefreshMode::OnChange), | ||
view_refresh_mode: Some(types::ViewRefreshMode::OnStop), | ||
view_format: Some(String::new()), | ||
attrs, | ||
..Default::default() | ||
}) | ||
); | ||
} | ||
|
||
#[test] | ||
fn test_parse_scale() { | ||
let kml_str = r#"<Scale> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
use std::{ | ||
collections::HashMap, | ||
fmt::{Display, Formatter, Result}, | ||
}; | ||
|
||
/// `kml:Link`, [13.1](https://docs.opengeospatial.org/is/12-007r2/12-007r2.html#974) in the KML specification. | ||
#[derive(Clone, Debug, PartialEq)] | ||
pub struct Link { | ||
pub href: Option<String>, | ||
pub refresh_mode: Option<RefreshMode>, | ||
pub refresh_interval: f64, | ||
pub view_refresh_mode: Option<ViewRefreshMode>, | ||
pub view_refresh_time: f64, | ||
pub view_bound_scale: f64, | ||
pub view_format: Option<String>, | ||
pub http_query: Option<String>, | ||
pub attrs: HashMap<String, String>, | ||
} | ||
|
||
impl Default for Link { | ||
fn default() -> Self { | ||
Self { | ||
href: None, | ||
refresh_mode: None, | ||
refresh_interval: 4.0, | ||
view_refresh_mode: None, | ||
view_refresh_time: 4.0, | ||
view_bound_scale: 1.0, | ||
view_format: None, | ||
http_query: None, | ||
attrs: HashMap::new(), | ||
} | ||
} | ||
} | ||
|
||
/// `kml:Icon`, [13.1](https://docs.opengeospatial.org/is/12-007r2/12-007r2.html#974) in the KML specification. | ||
#[derive(Clone, Debug, PartialEq)] | ||
pub struct Icon { | ||
pub href: Option<String>, | ||
pub refresh_mode: Option<RefreshMode>, | ||
pub refresh_interval: f64, | ||
pub view_refresh_mode: Option<ViewRefreshMode>, | ||
pub view_refresh_time: f64, | ||
pub view_bound_scale: f64, | ||
pub view_format: Option<String>, | ||
pub http_query: Option<String>, | ||
pub attrs: HashMap<String, String>, | ||
} | ||
|
||
impl Default for Icon { | ||
fn default() -> Self { | ||
Self { | ||
href: None, | ||
refresh_mode: None, | ||
refresh_interval: 4.0, | ||
view_refresh_mode: None, | ||
view_refresh_time: 4.0, | ||
view_bound_scale: 1.0, | ||
view_format: None, | ||
http_query: None, | ||
attrs: HashMap::new(), | ||
} | ||
} | ||
} | ||
|
||
/// `kml:refreshModeEnumType`, [16.21](https://docs.opengeospatial.org/is/12-007r2/12-007r2.html#1239) in the KML specification. | ||
#[derive(Clone, Debug, PartialEq)] | ||
pub enum RefreshMode { | ||
OnChange, | ||
OnInterval, | ||
OnExpire, | ||
} | ||
|
||
impl Default for RefreshMode { | ||
fn default() -> RefreshMode { | ||
RefreshMode::OnChange | ||
} | ||
} | ||
|
||
impl Display for RefreshMode { | ||
fn fmt(&self, f: &mut Formatter<'_>) -> Result { | ||
match self { | ||
RefreshMode::OnChange => write!(f, "onChange"), | ||
RefreshMode::OnInterval => write!(f, "onInterval"), | ||
RefreshMode::OnExpire => write!(f, "onExpire"), | ||
} | ||
} | ||
} | ||
|
||
/// `kml:viewRefreshModeEnumType`, [16.27](https://docs.opengeospatial.org/is/12-007r2/12-007r2.html#1270) in the KML specification. | ||
#[derive(Clone, Debug, PartialEq)] | ||
pub enum ViewRefreshMode { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would be great to implement There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
Never, | ||
OnRequest, | ||
OnStop, | ||
OnRegion, | ||
} | ||
|
||
impl Default for ViewRefreshMode { | ||
fn default() -> ViewRefreshMode { | ||
ViewRefreshMode::Never | ||
} | ||
} | ||
|
||
impl Display for ViewRefreshMode { | ||
fn fmt(&self, f: &mut Formatter<'_>) -> Result { | ||
match self { | ||
ViewRefreshMode::Never => write!(f, "never"), | ||
ViewRefreshMode::OnRequest => write!(f, "onRequest"), | ||
ViewRefreshMode::OnStop => write!(f, "onStop"), | ||
ViewRefreshMode::OnRegion => write!(f, "onRegion"), | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -36,6 +36,10 @@ mod geometry; | |
|
||
pub use geometry::Geometry; | ||
|
||
mod link; | ||
|
||
pub use link::{Icon as LinkTypeIcon, Link as LinkTypeLink, RefreshMode, ViewRefreshMode}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not a fan of these aliases, but I couldn't think of anything better. Decided to alias There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think I'd prefer we only alias |
||
|
||
mod style; | ||
|
||
pub use style::{ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of including this here, could we implement
FromStr
forRefreshMode
as well as the other added enums? We've done this forAltitudeMode
andColorMode
as well and it keeps things a little cleanerThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.