aboutsummaryrefslogtreecommitdiff
path: root/src/svg
diff options
context:
space:
mode:
authorArne Dußin2021-01-27 14:01:50 +0100
committerArne Dußin2021-02-02 22:16:15 +0100
commitf92e9f6f07b1e3834c2ca58ce3510734819d08e4 (patch)
tree20e3d3afce342a56ae98f6c20491482ccd2b5c6b /src/svg
parentc60a6d07efb120724b308e29e8e70f27c87c952d (diff)
downloadgraf_karto-f92e9f6f07b1e3834c2ca58ce3510734819d08e4.tar.gz
graf_karto-f92e9f6f07b1e3834c2ca58ce3510734819d08e4.zip
Rework graf karto to fit the client/server structure
Diffstat (limited to 'src/svg')
-rw-r--r--src/svg/mod.rs178
-rw-r--r--src/svg/style.rs180
2 files changed, 0 insertions, 358 deletions
diff --git a/src/svg/mod.rs b/src/svg/mod.rs
deleted file mode 100644
index af066f1..0000000
--- a/src/svg/mod.rs
+++ /dev/null
@@ -1,178 +0,0 @@
-//! Module for drawing SVG files to the screen or maybe a texture etc.
-
-pub mod style;
-
-use crate::math::Vec2;
-use raylib::drawing::RaylibDraw;
-use std::fs::File;
-use std::io::{self, Read};
-use std::ops::Deref;
-use std::path::Path;
-use std::str::FromStr;
-use style::Style;
-use svgtypes::{Path as SVGPath, PathSegment};
-use xmltree::{Element, XMLNode};
-
-/// Find the first XML-Node with the given name. With depth, the maximum depth the
-/// algorithm will search to can be set. If it is set to `None`, the algorithm will search the
-/// entire sub-tree. Returns `None` if no such child can be found. Returns itself, in case the root
-/// node is already of the name given.
-pub fn find_first_node(root: Element, name: &str, depth: Option<usize>) -> Option<Element> {
- // The abort condition of this recursive function. If the element itself is of the required
- // name, return it.
- if root.name == name {
- return Some(root);
- }
- // Also abort, if the depth is reached.
- if depth == Some(0) {
- return None;
- }
-
- // Decrease the depth by one for all calls on the children, if it is set.
- let depth = match depth {
- Some(depth) => Some(depth - 1),
- None => None,
- };
-
- // Recursively look for the element in this node's children.
- for child in root.children {
- // We only care for the elements, not for comments, cdata etc.
- if let XMLNode::Element(element) = child {
- if let Some(element) = find_first_node(element, name, depth) {
- return Some(element);
- }
- }
- }
-
- None
-}
-
-/// Read an svg file from the given path. On success, return the first graphics data that is read
-/// from this file. This can be used to draw an SVG.
-pub fn read_svg_file<P: AsRef<Path>>(file: P) -> io::Result<Element> {
- let mut file = File::open(file)?;
- let mut data = String::new();
- file.read_to_string(&mut data)?;
-
- let root: Element = match Element::parse(data.as_bytes()) {
- Ok(root) => root,
- Err(err) => return Err(io::Error::new(io::ErrorKind::InvalidData, err)),
- };
-
- match find_first_node(root, "g", None) {
- Some(graphics) => Ok(graphics),
- None => Err(io::Error::new(
- io::ErrorKind::InvalidData,
- "No graphics element in the file",
- )),
- }
-}
-
-/// Trait that indicates a struct is capable of drawing SVG-elements.
-pub trait DrawSVG {
- /// Draw the elements given by `svg_data` and all its children to the implementor, with the
- /// specified scale and translated by `position_px`.
- fn draw_svg(&mut self, svg_data: &Element, pixels_per_m: f32, position_px: Vec2<f32>);
-}
-
-impl<D> DrawSVG for D
-where
- D: RaylibDraw,
-{
- fn draw_svg(&mut self, svg_data: &Element, pixels_per_m: f32, position_px: Vec2<f32>) {
- assert_eq!(&svg_data.name, "g");
-
- // Go through all the graphics children and draw them one by one
- for child in &svg_data.children {
- if let XMLNode::Element(child) = child {
- match child.name.as_str() {
- "path" => draw_path(self, child, pixels_per_m, position_px),
- other => warn!("Unsupported SVG-Element {}", other),
- }
- }
- }
- }
-}
-
-// Helper functions to draw specific parts of the SVG file --------------------
-
-fn draw_path(
- d: &mut impl RaylibDraw,
- path_data: &Element,
- pixels_per_m: f32,
- position_px: Vec2<f32>,
-) {
- let style = if let Some(style_data) = path_data.attributes.get("style") {
- match Style::from_str(style_data) {
- Ok(style) => style,
- Err(err) => {
- warn!("Could not parse path style: {}", err);
- warn!("Using default style instead");
- Style::default()
- }
- }
- } else {
- Style::default()
- };
-
- let move_data = match path_data.attributes.get("d") {
- Some(d) => d,
- None => {
- error!("Unable to draw path, no move data found");
- return;
- }
- };
-
- let mut path: SVGPath = match move_data.parse() {
- Ok(mv) => mv,
- Err(err) => {
- error!(
- "Unable to draw path, move data not correctly formatted: {}",
- err
- );
- return;
- }
- };
-
- path.conv_to_absolute();
-
- let mut current_pos: Vec2<f32> = Vec2::new(0., 0.);
- for segment in path.deref() {
- match segment {
- PathSegment::MoveTo { x, y, .. } => {
- current_pos.x = *x as f32;
- current_pos.y = *y as f32;
- }
- PathSegment::LineTo { x, y, .. } => {
- d.draw_line_ex(
- current_pos * pixels_per_m / 1000. + position_px,
- Vec2::new(*x as f32, *y as f32) * pixels_per_m / 1000. + position_px,
- pixels_per_m * style.stroke_width / 1000.,
- style.stroke,
- );
- current_pos.x = *x as f32;
- current_pos.y = *y as f32;
- }
- PathSegment::HorizontalLineTo { x, .. } => {
- d.draw_line_ex(
- current_pos * pixels_per_m / 1000. + position_px,
- Vec2::new(*x as f32, current_pos.y) * pixels_per_m / 1000. + position_px,
- pixels_per_m * style.stroke_width / 1000.,
- style.stroke,
- );
- current_pos.x = *x as f32;
- }
- PathSegment::VerticalLineTo { y, .. } => {
- d.draw_line_ex(
- current_pos * pixels_per_m / 1000. + position_px,
- Vec2::new(current_pos.x, *y as f32) * pixels_per_m / 1000. + position_px,
- pixels_per_m * style.stroke_width / 1000.,
- style.stroke,
- );
- current_pos.y = *y as f32;
- }
- PathSegment::ClosePath { .. } => return,
- other => warn!("Ignoring unsupported {:?}", other),
- }
- }
-}
diff --git a/src/svg/style.rs b/src/svg/style.rs
deleted file mode 100644
index 7a0110e..0000000
--- a/src/svg/style.rs
+++ /dev/null
@@ -1,180 +0,0 @@
-//! Style options for SVG components.
-//!
-//! For information on SVG styles, pleas see the SVG documentation.
-// TODO: There should be a lib available that can be integrated into the program
-
-use raylib::ffi::Color;
-use std::str::FromStr;
-
-/// Convert an html-style colour into a raylib Color-struct if possible. If there is an error in
-/// the formatting, it returns `None`.
-pub fn colour_from_html(html: &str) -> Option<Color> {
- /* The html-code must be exactly seven characters long, one for the hash and two per primary
- * colour.
- */
- if html.len() != 7 {
- return None;
- }
-
- let extract_hex = |string: &str, pos: usize| {
- u8::from_str_radix(
- string.get(pos..pos + 2).expect("Could not split string"),
- 16,
- )
- .ok()
- };
- let red: Option<u8> = extract_hex(html, 1);
- let green: Option<u8> = extract_hex(html, 3);
- let blue: Option<u8> = extract_hex(html, 5);
-
- if let (Some(r), Some(g), Some(b)) = (red, green, blue) {
- Some(Color { r, g, b, a: 255 })
- } else {
- None
- }
-}
-
-/// The style of the end of the stroke.
-/// See [stroke-line-cap property](https://www.w3.org/TR/SVG11/painting.html#StrokeLinecapProperty)
-/// in the SVG Documentation.
-#[allow(missing_docs)]
-pub enum StrokeLineCap {
- Butt,
- Round,
- Square,
-}
-
-/// The style of the joining corners of the stroke.
-/// See [stroke-line-join property](https://www.w3.org/TR/SVG11/painting.html#StrokeLinejoinProperty)
-/// in the SVG Documentation
-#[allow(missing_docs)]
-pub enum StrokeLineJoin {
- Miter,
- Round,
- Bevel,
-}
-
-/// The style of a path drawing instruction.
-#[allow(missing_docs)]
-pub struct Style {
- pub fill: Option<Color>,
- pub stroke: Color,
- pub stroke_width: f32,
- pub stroke_linecap: StrokeLineCap,
- pub stroke_linejoin: StrokeLineJoin,
- pub stroke_opacity: f32,
-}
-
-impl FromStr for StrokeLineCap {
- type Err = String;
-
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- match s {
- "butt" => Ok(Self::Butt),
- "round" => Ok(Self::Round),
- "square" => Ok(Self::Square),
- _ => Err("No such line-cap style".to_owned()),
- }
- }
-}
-
-impl Default for StrokeLineCap {
- fn default() -> Self {
- StrokeLineCap::Butt
- }
-}
-
-impl FromStr for StrokeLineJoin {
- type Err = String;
-
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- match s {
- "miter" => Ok(Self::Miter),
- "round" => Ok(Self::Round),
- "bevel" => Ok(Self::Bevel),
- _ => Err("No such line-join style".to_owned()),
- }
- }
-}
-
-impl Default for StrokeLineJoin {
- fn default() -> Self {
- StrokeLineJoin::Miter
- }
-}
-
-impl FromStr for Style {
- type Err = String;
-
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- // Split into CSS-attributes
- let attributes: Vec<&str> = s.split(';').collect();
- // Split the attributes into name and value pairs and parse them into a style struct
- let mut style = Style::default();
- for attribute in attributes {
- let attribute_parts: Vec<&str> = attribute.split(':').collect();
- if attribute_parts.len() != 2 {
- continue;
- }
-
- match attribute_parts[0].trim() {
- "fill" => {
- style.fill = match attribute_parts[1].trim() {
- "none" => None,
- colour => colour_from_html(colour),
- }
- }
- "stroke" => {
- style.stroke = match colour_from_html(attribute_parts[1].trim()) {
- Some(c) => c,
- None => {
- return Err(format!(
- "Could not parse colour from {}",
- attribute_parts[1].trim()
- ))
- }
- }
- }
- "stroke-width" => {
- style.stroke_width = match attribute_parts[1].trim().parse::<f32>() {
- Ok(width) => width,
- Err(err) => return Err(format!("Could not parse stroke-width: {}", err)),
- }
- }
- "stroke-linecap" => {
- style.stroke_linecap = StrokeLineCap::from_str(attribute_parts[1].trim())?
- }
- "stroke-linejoin" => {
- style.stroke_linejoin = StrokeLineJoin::from_str(attribute_parts[1].trim())?
- }
- "stroke-opacity" => {
- style.stroke_width = match attribute_parts[1].trim().parse::<f32>() {
- Ok(opacity) => opacity,
- Err(err) => return Err(format!("Could not parse stroke-opacity: {}", err)),
- }
- }
- attr => return Err(format!("Unknown attribute {}", attr)),
- }
- }
-
- Ok(style)
- }
-}
-
-impl Default for Style {
- fn default() -> Self {
- Self {
- fill: None,
- stroke: Color {
- r: 0,
- g: 0,
- b: 0,
- a: 255,
- },
- stroke_width: 1.,
- stroke_linecap: StrokeLineCap::default(),
- stroke_linejoin: StrokeLineJoin::default(),
- stroke_opacity: 1.,
- }
- }
-}