geo_svg_io2/geo_svg_reader/
mod.rs

1extern crate geo_booleanop;
2extern crate geo_normalized2;
3extern crate geo_types;
4
5use flo_curves::bezier::{de_casteljau3, de_casteljau4};
6use flo_curves::{Coord2, Coordinate2D};
7use geo_types::{
8    Coordinate, Geometry, GeometryCollection, Line, LineString, MultiLineString, MultiPolygon,
9    Polygon, Rect,
10};
11use std::convert::From;
12use std::fmt;
13use svgtypes::{PathParser, PathSegment, PointsParser};
14use xml::reader::{EventReader, XmlEvent};
15
16pub enum SvgError {
17    ParseError(std::num::ParseFloatError),
18    SvgInvalidType(SvgUnsupportedGeometryTypeError),
19    SvgGeomCollectionForGeometry(SvgGeometryCollectionForGeometryError),
20    InvalidSvgError(InvalidSvgError),
21}
22
23impl From<std::num::ParseFloatError> for SvgError {
24    fn from(error: std::num::ParseFloatError) -> Self {
25        SvgError::ParseError(error)
26    }
27}
28
29pub struct SvgUnsupportedGeometryTypeError;
30
31// Implement std::fmt::Display for AppError
32impl fmt::Display for SvgUnsupportedGeometryTypeError {
33    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
34        write!(f, "The SVG could not be parsed to a valid Geometry type") // user-facing output
35    }
36}
37
38pub struct SvgGeometryCollectionForGeometryError;
39
40// Implement std::fmt::Display for AppError
41impl fmt::Display for SvgGeometryCollectionForGeometryError {
42    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
43        write!(f, "The SVG could only be parsed as a GEOMETRYCOLLECTION") // user-facing output
44    }
45}
46
47// Implement std::fmt::Debug for AppError
48impl fmt::Debug for SvgUnsupportedGeometryTypeError {
49    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
50        write!(f, "{{ file: {}, line: {} }}", file!(), line!()) // programmer-facing output
51    }
52}
53
54pub struct InvalidSvgError;
55
56// Implement std::fmt::Display for AppError
57impl fmt::Display for InvalidSvgError {
58    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
59        write!(f, "The SVG input is invalid") // user-facing output
60    }
61}
62
63// Implement std::fmt::Debug for AppError
64impl fmt::Debug for InvalidSvgError {
65    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
66        write!(f, "{{ file: {}, line: {} }}", file!(), line!()) // programmer-facing output
67    }
68}
69
70/// Returns a GeometryCollection parsed from the submitted SVG element
71///
72/// **Note** this function does not parse a full SVG string (e.g., `<svg xmlns="http://www.w3.org/2000/svg"><path d="M0 0L10 0L10 10L0 10Z"/></svg>`), it only parses the individual shape elements (e.g., `<path d="M0 0L10 0L10 10L0 10Z"/>`).  The following SVG elements are supported and produce the specified Geometry types:
73///
74/// * \<path\> &rarr; GeometryCollection
75/// * \<polygon\> &rarr; GeometryCollection with a single Polygon
76/// * \<polyline\> &rarr; GeometryCollection with a single LineString
77/// * \<rect\> &rarr; GeometryCollection with a single Polygon
78/// * \<line\> &rarr; GeometryCollection with a single Line
79///
80/// **Note** also that the current parsing of curves in a `<path>`is rather simple right now,
81/// it just finds 100 points along the curve.
82///
83/// # Examples
84///
85/// Parsing a `<path>` element:
86///
87/// ```rust
88/// use geo_types::{ Polygon, polygon };
89/// use geo_svg_io::geo_svg_reader::svg_to_geometry_collection;
90///
91/// let poly: Polygon<f64> = polygon!(
92///         exterior: [
93///             (x: 0.0_f64, y: 0.0),
94///             (x: 0.0, y: 60.0),
95///             (x: 60.0, y: 60.0),
96///             (x: 60.0, y: 0.0),
97///             (x: 0.0, y: 0.0),],
98///         interiors:[[
99///             (x: 10.0, y: 10.0),
100///             (x: 40.0, y: 1.0),
101///             (x: 40.0, y: 40.0),
102///             (x: 10.50, y: 40.0),
103///             (x: 10.0, y: 10.0),]
104///             ]
105///         )
106///         .into();
107/// let svg_string =
108///             String::from(r#"<path d="M0 0L0 60L60 60L60 0L0 0M10 10L40 1L40 40L10.5 40L10 10"/>"#);
109///
110/// let parsed_svg = svg_to_geometry_collection(&svg_string);
111/// assert_eq!(parsed_svg.is_ok(), true);
112///
113/// // Unwrap the GeometryCollection result
114/// let geom = parsed_svg.ok().unwrap();
115/// assert_eq!(1, geom.0.len());
116///
117/// // Read the geometry as a Polygon
118/// let pl = geom.0[0].clone().into_polygon();
119/// assert_eq!(true, pl.is_some());
120/// assert_eq!(poly, pl.unwrap());
121/// ```
122///
123/// Parsing a `<polygon>` element:
124///
125/// ```rust
126/// use geo_types::{ Polygon, polygon };
127/// use geo_svg_io::geo_svg_reader::svg_to_geometry_collection;
128///
129/// let poly: Polygon<f64> = polygon!(
130///         exterior: [
131///             (x: 0.0_f64, y: 0.0),
132///             (x: 0.0, y: 60.0),
133///             (x: 60.0, y: 60.0),
134///             (x: 60.0, y: 0.0),
135///             (x: 0.0, y: 0.0),],
136///         interiors:[]
137///         )
138///         .into();
139///
140/// let svg_string = String::from(r#"<polygon points="0, 0 60, 0 60, 60 0, 60 0, 0"/>"#);
141///
142/// let parsed_svg = svg_to_geometry_collection(&svg_string);
143/// assert_eq!(parsed_svg.is_ok(), true);
144///
145/// // Unwrap the GeometryCollection result
146/// let geom = parsed_svg.ok().unwrap();
147/// assert_eq!(1, geom.0.len());
148///
149/// // Read the geometry as a Polygon
150/// let pl = geom.0[0].clone().into_polygon();
151/// assert_eq!(true, pl.is_some());
152/// assert_eq!(poly, pl.unwrap());
153/// ```
154///
155pub fn svg_to_geometry_collection(svg: &str) -> Result<GeometryCollection<f64>, SvgError> {
156    let parser = EventReader::new(svg.as_bytes());
157    for e in parser {
158        if let Ok(XmlEvent::StartElement {
159            name, attributes, ..
160        }) = e
161        {
162            // An SVG path element
163            if name.local_name == "path" {
164                for attr in attributes {
165                    if attr.name.local_name == "d" {
166                        let res = svg_d_path_to_geometry_collection(&attr.value)?;
167                        return Ok(res);
168                    }
169                }
170            }
171            // An SVG polygon
172            else if name.local_name == "polygon" {
173                for attr in attributes {
174                    if attr.name.local_name == "points" {
175                        let res = svg_polygon_to_geometry(&attr.value)?;
176                        return Ok(res.into());
177                    }
178                }
179            }
180            // An SVG polyline
181            else if name.local_name == "polyline" {
182                for attr in attributes {
183                    if attr.name.local_name == "points" {
184                        let res = svg_polyline_to_geometry(&attr.value)?;
185                        return Ok(res.into());
186                    }
187                }
188            }
189            // An SVG rect
190            else if name.local_name == "rect" {
191                let mut x: Option<f64> = None;
192                let mut y: Option<f64> = None;
193                let mut width: Option<f64> = None;
194                let mut height: Option<f64> = None;
195
196                for attr in attributes {
197                    if attr.name.local_name == "x" {
198                        let x_val = attr.value.parse::<f64>()?;
199                        x = Some(x_val);
200                    } else if attr.name.local_name == "y" {
201                        let y_val = attr.value.parse::<f64>()?;
202                        y = Some(y_val);
203                    } else if attr.name.local_name == "width" {
204                        let width_val = attr.value.parse::<f64>()?;
205                        width = Some(width_val);
206                    } else if attr.name.local_name == "height" {
207                        let height_val = attr.value.parse::<f64>()?;
208                        height = Some(height_val);
209                    }
210                }
211
212                if x.is_none() {
213                    return Err(SvgError::InvalidSvgError(InvalidSvgError));
214                }
215                if y.is_none() {
216                    return Err(SvgError::InvalidSvgError(InvalidSvgError));
217                }
218                if width.is_none() {
219                    return Err(SvgError::InvalidSvgError(InvalidSvgError));
220                }
221                if height.is_none() {
222                    return Err(SvgError::InvalidSvgError(InvalidSvgError));
223                }
224                let rect =
225                    svg_rect_to_geometry(x.unwrap(), y.unwrap(), width.unwrap(), height.unwrap())?;
226
227                return Ok(rect.into());
228            }
229            // An SVG line
230            else if name.local_name == "line" {
231                let mut start_x: Option<f64> = None;
232                let mut start_y: Option<f64> = None;
233                let mut end_x: Option<f64> = None;
234                let mut end_y: Option<f64> = None;
235
236                for attr in attributes {
237                    if attr.name.local_name == "x1" {
238                        let start_x_val = attr.value.parse::<f64>()?;
239                        start_x = Some(start_x_val);
240                    } else if attr.name.local_name == "y1" {
241                        let start_y_val = attr.value.parse::<f64>()?;
242                        start_y = Some(start_y_val);
243                    } else if attr.name.local_name == "x2" {
244                        let end_x_val = attr.value.parse::<f64>()?;
245                        end_x = Some(end_x_val);
246                    } else if attr.name.local_name == "y2" {
247                        let end_y_val = attr.value.parse::<f64>()?;
248                        end_y = Some(end_y_val);
249                    }
250                }
251
252                if start_x.is_none() {
253                    return Err(SvgError::InvalidSvgError(InvalidSvgError));
254                }
255                if start_y.is_none() {
256                    return Err(SvgError::InvalidSvgError(InvalidSvgError));
257                }
258                if end_x.is_none() {
259                    return Err(SvgError::InvalidSvgError(InvalidSvgError));
260                }
261                if end_y.is_none() {
262                    return Err(SvgError::InvalidSvgError(InvalidSvgError));
263                }
264
265                return Ok(svg_line_to_geometry(
266                    &start_x.unwrap(),
267                    &start_y.unwrap(),
268                    &end_x.unwrap(),
269                    &end_y.unwrap(),
270                )
271                .into());
272            }
273        }
274    }
275
276    Err(SvgError::SvgInvalidType(SvgUnsupportedGeometryTypeError))
277}
278
279/// Returns a Geometry parsed from the submitted SVG element
280///
281/// **Note** this function does not parse a full SVG string (e.g., `<svg xmlns="http://www.w3.org/2000/svg"><path d="M0 0L10 0L10 10L0 10Z"/></svg>`), it only parses the individual shape elements (e.g., `<path d="M0 0L10 0L10 10L0 10Z"/>`).  The following SVG elements are supported and produce the specified Geometry types:
282///
283/// * \<path\> &rarr; Geometry with the autodetected Geometry type
284/// * \<polygon\> &rarr; Polygon
285/// * \<polyline\> &rarr; LineString
286/// * \<rect\> &rarr; Polygon
287/// * \<line\> &rarr; Line
288///
289/// **Note** also that the current parsing of curves in a `<path>`is rather simple right now,
290/// it just finds 100 points along the curve.
291///
292/// # Examples
293///
294/// Parsing a `<path>` element:
295///
296/// ```rust
297/// use geo_types::{ Polygon, polygon };
298/// use geo_svg_io::geo_svg_reader::svg_to_geometry;
299///
300/// let poly: Polygon<f64> = polygon!(
301///     exterior: [
302///         (x: 0.0_f64, y: 0.0),
303///         (x: 0.0, y: 60.0),
304///         (x: 60.0, y: 60.0),
305///         (x: 60.0, y: 0.0),
306///         (x: 0.0, y: 0.0),],
307///     interiors:[[
308///         (x: 10.0, y: 10.0),
309///         (x: 40.0, y: 1.0),
310///         (x: 40.0, y: 40.0),
311///         (x: 10.50, y: 40.0),
312///         (x: 10.0, y: 10.0),]
313///         ]
314///     );
315/// let svg_string =
316///     String::from(r#"<path d="M0 0L0 60L60 60L60 0L0 0M10 10L40 1L40 40L10.5 40L10 10"/>"#);
317///
318/// let parsed_svg = svg_to_geometry(&svg_string);
319/// assert!(parsed_svg.is_ok());
320/// let parsed_poly = parsed_svg.ok().unwrap().into_polygon();
321/// assert!(parsed_poly.is_some());
322/// assert_eq!(poly, parsed_poly.unwrap());
323/// ```
324///
325/// Parsing a `<polygon>` element:
326///
327/// ```rust
328/// use geo_types::{ Polygon, polygon };
329/// use geo_svg_io::geo_svg_reader::svg_to_geometry;
330///
331/// let poly: Polygon<f64> = polygon!(
332///     exterior: [
333///         (x: 0.0_f64, y: 0.0),
334///         (x: 0.0, y: 60.0),
335///         (x: 60.0, y: 60.0),
336///         (x: 60.0, y: 0.0),
337///         (x: 0.0, y: 0.0),],
338///     interiors:[]
339///     );
340/// let svg_string = String::from(r#"<polygon points="0, 0 60, 0 60, 60 0, 60 0, 0"/>"#);
341///
342/// let parsed_svg = svg_to_geometry(&svg_string);
343/// assert!(parsed_svg.is_ok());
344/// let parsed_poly = parsed_svg.ok().unwrap().into_polygon();
345/// assert!(parsed_poly.is_some());
346/// assert_eq!(poly, parsed_poly.unwrap());
347/// ```
348///
349pub fn svg_to_geometry(svg: &str) -> Result<Geometry<f64>, SvgError> {
350    let gc = svg_to_geometry_collection(svg)?;
351    if gc.0.len() == 1 {
352        return Ok(gc.0[0].clone());
353    }
354    Err(SvgError::SvgGeomCollectionForGeometry(
355        SvgGeometryCollectionForGeometryError,
356    ))
357}
358
359fn svg_polygon_to_geometry(point_string: &str) -> Result<Polygon<f64>, SvgError> {
360    let points = PointsParser::from(point_string);
361    let polygon = Polygon::new(
362        LineString(
363            points
364                .map(|(x, y)| Coordinate { x, y })
365                .collect::<Vec<Coordinate<f64>>>(),
366        ),
367        vec![],
368    );
369
370    if polygon.exterior().num_coords() == 0 {
371        return Err(SvgError::InvalidSvgError(InvalidSvgError));
372    }
373    Ok(polygon)
374}
375
376fn svg_polyline_to_geometry(point_string: &str) -> Result<LineString<f64>, SvgError> {
377    let points = PointsParser::from(point_string);
378    let linestring = LineString(
379        points
380            .map(|(x, y)| Coordinate { x, y })
381            .collect::<Vec<Coordinate<f64>>>(),
382    );
383
384    if linestring.num_coords() == 0 {
385        return Err(SvgError::InvalidSvgError(InvalidSvgError));
386    }
387    Ok(linestring)
388}
389
390fn svg_rect_to_geometry(x: f64, y: f64, width: f64, height: f64) -> Result<Polygon<f64>, SvgError> {
391    let max_x = x + width;
392    let max_y = y + height;
393    if x > max_x {
394        return Err(SvgError::InvalidSvgError(InvalidSvgError));
395    }
396    if y > max_y {
397        return Err(SvgError::InvalidSvgError(InvalidSvgError));
398    }
399
400    // geo_types::Rect is not part of the enum Geometry, so we cast it to Polygon upon return
401    Ok(Polygon::from(Rect::new(
402        Coordinate::<f64> { x, y },
403        Coordinate::<f64> { x: max_x, y: max_y },
404    )))
405}
406
407fn svg_line_to_geometry(start_x: &f64, start_y: &f64, end_x: &f64, end_y: &f64) -> Line<f64> {
408    Line::new(
409        Coordinate::<f64> {
410            x: *start_x,
411            y: *start_y,
412        },
413        Coordinate::<f64> {
414            x: *end_x,
415            y: *end_y,
416        },
417    )
418}
419
420/// Parses the `d`-string from an SVG `<path>` element into a GeometryCollection
421///
422/// **Note** that the current parsing of curves is rather simple right now, it just finds
423/// 100 points along the curve.
424///
425/// # Examples
426///
427/// ```rust
428/// use geo_svg_io::geo_svg_reader::svg_d_path_to_geometry_collection;
429/// use geo_types::polygon;
430///
431/// let poly = polygon!(
432///         exterior: [
433///             (x: 0.0, y: 0.0),
434///             (x: 0.0, y: 60.0),
435///             (x: 60.0, y: 60.0),
436///             (x: 60.0, y: 0.0),
437///             (x: 0.0, y: 0.0),],
438///         interiors:[[
439///             (x: 10.0, y: 10.0),
440///             (x: 40.0, y: 1.0),
441///             (x: 40.0, y: 40.0),
442///             (x: 10.50, y: 40.0),
443///             (x: 10.0, y: 10.0),]
444///             ]
445///         );
446///
447/// let svg_string = String::from("M0 0l0 60l60 0L60 0L0 0M10 10L40 1L40 40L10.5 40L10 10");
448/// let parsed_svg = svg_d_path_to_geometry_collection(&svg_string);
449/// assert_eq!(parsed_svg.is_ok(), true);
450///
451/// // Unwrap the GeometryCollection result
452/// let geom = parsed_svg.ok().unwrap();
453/// assert_eq!(1, geom.0.len());
454///
455/// // Read the geometry as a Polygon
456/// let pl = geom.0[0].clone().into_polygon();
457/// assert_eq!(true, pl.is_some());
458/// assert_eq!(pl.unwrap(), poly);
459/// ```
460///
461pub fn svg_d_path_to_geometry_collection(svg: &str) -> Result<GeometryCollection<f64>, SvgError> {
462    // We will collect the separate paths (from M to M) into segments for parsing
463    let mut path_segments = vec![] as Vec<Vec<Coordinate<f64>>>;
464    let mut segment_count = 0;
465    let mut first_segment = true;
466    let zero_coord = Coordinate { x: 0_f64, y: 0_f64 }; // Default values to be added to relative coords
467    let mut last_point: Option<Coordinate<f64>> = None; // Store last point for relative coordinates
468    let mut last_control_point: Option<Coord2> = None; // Store last control point for S and T coordinates
469    let p = PathParser::from(svg);
470    for token in p {
471        let t = token.unwrap();
472        match t {
473            PathSegment::MoveTo { abs, x, y } => {
474                path_segments.push(vec![] as Vec<Coordinate<f64>>);
475                if !first_segment {
476                    segment_count += 1;
477                } else {
478                    first_segment = false;
479                }
480                let coord = Coordinate {
481                    x: if !abs {
482                        x + last_point.unwrap_or(zero_coord).x
483                    } else {
484                        x
485                    },
486                    y: if !abs {
487                        y + last_point.unwrap_or(zero_coord).y
488                    } else {
489                        y
490                    },
491                };
492                last_point = Some(coord);
493                path_segments[segment_count].push(coord);
494            }
495            PathSegment::LineTo { abs, x, y } => {
496                let coord = Coordinate {
497                    x: if !abs {
498                        x + last_point.unwrap_or(zero_coord).x
499                    } else {
500                        x
501                    },
502                    y: if !abs {
503                        y + last_point.unwrap_or(zero_coord).y
504                    } else {
505                        y
506                    },
507                };
508                last_point = Some(coord);
509                path_segments[segment_count].push(coord);
510            }
511            PathSegment::HorizontalLineTo { abs, x } => {
512                let coord = Coordinate {
513                    x: if !abs {
514                        x + last_point.unwrap_or(zero_coord).x
515                    } else {
516                        x
517                    },
518                    y: last_point.unwrap_or(zero_coord).y,
519                };
520                last_point = Some(coord);
521                path_segments[segment_count].push(coord);
522            }
523            PathSegment::VerticalLineTo { abs, y } => {
524                let coord = Coordinate {
525                    x: last_point.unwrap_or(zero_coord).x,
526                    y: if !abs {
527                        y + last_point.unwrap_or(zero_coord).y
528                    } else {
529                        y
530                    },
531                };
532                last_point = Some(coord);
533                path_segments[segment_count].push(coord);
534            }
535            PathSegment::CurveTo {
536                x,
537                x1,
538                x2,
539                y,
540                y1,
541                y2,
542                abs,
543            } => {
544                let last = last_point.unwrap_or(zero_coord);
545                let start_point = calculate_svg_coord2(last.x, last.y, last, true);
546                let control_1 = calculate_svg_coord2(x1, y1, last, abs);
547                let control_2 = calculate_svg_coord2(x2, y2, last, abs);
548                last_control_point = Some(control_2);
549                let end_point = calculate_svg_coord2(x, y, last, abs);
550                let end = Coordinate {
551                    x: end_point.x(),
552                    y: end_point.y(),
553                };
554                last_point = Some(end);
555                // TODO: it is not great to just pick an arbitrary number of points along the curve
556                // update this to use a recursive function instead to create more points until
557                // they are collinear (enough)
558                for x in 1..100 {
559                    let arc_point = de_casteljau4(
560                        x as f64 / 100_f64,
561                        start_point,
562                        control_1,
563                        control_2,
564                        end_point,
565                    );
566                    path_segments[segment_count].push(Coordinate {
567                        x: arc_point.x(),
568                        y: arc_point.y(),
569                    });
570                }
571                path_segments[segment_count].push(end);
572            }
573            PathSegment::SmoothCurveTo { x2, x, y2, y, abs } => {
574                let last = last_point.unwrap_or(zero_coord);
575                let start_point = calculate_svg_coord2(last.x, last.y, last, true);
576                let control_1 = reflect_point(last, last_control_point.unwrap_or(Coord2(0., 0.)));
577                let control_2 = calculate_svg_coord2(x2, y2, last, abs);
578                last_control_point = Some(control_2);
579                let end_point = calculate_svg_coord2(x, y, last, abs);
580                let end = Coordinate {
581                    x: end_point.x(),
582                    y: end_point.y(),
583                };
584                last_point = Some(end);
585                // TODO: it is not great to just pick an arbitrary number of points along the curve
586                // update this to use a recursive function instead to create more points until
587                // they are collinear (enough)
588                for x in 1..100 {
589                    let arc_point = de_casteljau4(
590                        x as f64 / 100_f64,
591                        start_point,
592                        control_1,
593                        control_2,
594                        end_point,
595                    );
596                    path_segments[segment_count].push(Coordinate {
597                        x: arc_point.x(),
598                        y: arc_point.y(),
599                    });
600                }
601                path_segments[segment_count].push(end);
602            }
603            PathSegment::Quadratic { x1, x, y1, y, abs } => {
604                let last = last_point.unwrap_or(zero_coord);
605                let start_point = calculate_svg_coord2(last.x, last.y, last, true);
606                let control_1 = calculate_svg_coord2(x1, y1, last, abs);
607                last_control_point = Some(control_1);
608                let end_point = calculate_svg_coord2(x, y, last, abs);
609                let end = Coordinate {
610                    x: end_point.x(),
611                    y: end_point.y(),
612                };
613                last_point = Some(end);
614                // TODO: it is not great to just pick an arbitrary number of points along the curve
615                // update this to use a recursive function instead to create more points until
616                // they are collinear (enough)
617                for x in 1..100 {
618                    let arc_point =
619                        de_casteljau3(x as f64 / 100_f64, start_point, control_1, end_point);
620                    path_segments[segment_count].push(Coordinate {
621                        x: arc_point.x(),
622                        y: arc_point.y(),
623                    });
624                }
625                path_segments[segment_count].push(end);
626            }
627            PathSegment::SmoothQuadratic { x, y, abs } => {
628                let last = last_point.unwrap_or(zero_coord);
629                let start_point = calculate_svg_coord2(last.x, last.y, last, true);
630                let control_1 = reflect_point(last, last_control_point.unwrap_or(Coord2(0., 0.)));
631                last_control_point = Some(control_1);
632                let end_point = calculate_svg_coord2(x, y, last, abs);
633                let end = Coordinate {
634                    x: end_point.x(),
635                    y: end_point.y(),
636                };
637                last_point = Some(end);
638                // TODO: it is not great to just pick an arbitrary number of points along the curve
639                // update this to use a recursive function instead to create more points until
640                // they are collinear (enough)
641                for x in 1..100 {
642                    let arc_point =
643                        de_casteljau3(x as f64 / 100_f64, start_point, control_1, end_point);
644                    path_segments[segment_count].push(Coordinate {
645                        x: arc_point.x(),
646                        y: arc_point.y(),
647                    });
648                }
649                path_segments[segment_count].push(end);
650            }
651            // TODO: PathSegment::EllipticalArc
652            PathSegment::ClosePath { .. } => {
653                let coord = Coordinate {
654                    x: path_segments[segment_count][0].x,
655                    y: path_segments[segment_count][0].y,
656                };
657                last_point = Some(coord);
658                path_segments[segment_count].push(coord);
659            }
660            _ => last_point = None,
661        }
662    }
663    if path_segments.is_empty() {
664        return Err(SvgError::InvalidSvgError(InvalidSvgError));
665    }
666    Ok(parse_path_segments_to_geom(&path_segments))
667}
668
669/// Parses the `d`-string from an SVG `<path>` element into a single Geometry
670///
671/// **Note** that the current parsing of curves is rather simple right now, it just finds
672/// 100 points along the curve.
673///
674/// # Examples
675///
676/// ```rust
677/// use geo_svg_io::geo_svg_reader::svg_d_path_to_geometry;
678/// use geo_types::polygon;
679///
680/// let poly = polygon!(
681///         exterior: [
682///             (x: 0.0, y: 0.0),
683///             (x: 0.0, y: 60.0),
684///             (x: 60.0, y: 60.0),
685///             (x: 60.0, y: 0.0),
686///             (x: 0.0, y: 0.0),],
687///         interiors:[[
688///             (x: 10.0, y: 10.0),
689///             (x: 40.0, y: 1.0),
690///             (x: 40.0, y: 40.0),
691///             (x: 10.50, y: 40.0),
692///             (x: 10.0, y: 10.0),]
693///             ]
694///         );
695///
696/// let svg_string = String::from("M0 0l0 60l60 0L60 0L0 0M10 10L40 1L40 40L10.5 40L10 10");
697/// let parsed_svg = svg_d_path_to_geometry(&svg_string);
698/// assert!(parsed_svg.is_ok());
699/// let pl = parsed_svg.ok().unwrap().into_polygon();
700/// assert!(pl.is_some());
701/// assert_eq!(pl.unwrap(), poly);
702/// ```
703///
704pub fn svg_d_path_to_geometry(svg: &str) -> Result<Geometry<f64>, SvgError> {
705    let gc = svg_d_path_to_geometry_collection(svg)?;
706    if gc.0.len() == 1 {
707        return Ok(gc.0[0].clone());
708    }
709    Err(SvgError::SvgGeomCollectionForGeometry(
710        SvgGeometryCollectionForGeometryError,
711    ))
712}
713
714fn calculate_svg_coord2(x: f64, y: f64, last: Coordinate<f64>, abs: bool) -> Coord2 {
715    Coord2(
716        if abs { x } else { last.x + x },
717        if abs { y } else { last.y + y },
718    )
719}
720
721fn reflect_point(orig: Coordinate<f64>, pr: Coord2) -> Coord2 {
722    let x_step = pr.x() - orig.x;
723    let y_step = pr.y() - orig.y;
724
725    Coord2(orig.x - x_step, orig.y - y_step)
726}
727
728fn parse_path_segments_to_geom(paths: &Vec<Vec<Coordinate<f64>>>) -> GeometryCollection<f64> {
729    let mut lines = vec![] as Vec<Line<f64>>;
730    let mut line_strings = vec![] as Vec<LineString<f64>>;
731    let mut poly_line_strings = vec![] as Vec<LineString<f64>>;
732    let mut polygons: MultiPolygon<f64> = (vec![] as Vec<Polygon<f64>>).into();
733
734    for path in paths {
735        let length = path.len();
736        if length == 0 {
737            continue;
738        } else if length == 2 {
739            lines.push(Line::new(path[0], path[1]));
740        } else if !path.first().unwrap().eq(path.last().unwrap()) {
741            line_strings.push(path.clone().into());
742        } else {
743            poly_line_strings.push(path.clone().into());
744        }
745    }
746
747    if !poly_line_strings.is_empty() {
748        if poly_line_strings.len() == 1 {
749            polygons = Polygon::new(poly_line_strings[0].clone(), vec![]).into();
750        } else {
751            polygons = parse_polygon_rings_to_geom(&poly_line_strings);
752        }
753    }
754
755    let number_of_geom_types = !lines.is_empty() as i32
756        + !line_strings.is_empty() as i32
757        + !poly_line_strings.is_empty() as i32;
758
759    let mut geom_collection = vec![] as Vec<Geometry<f64>>;
760    if !lines.is_empty() {
761        let return_lines = map_lines_to_geometry(&lines);
762        if number_of_geom_types == 1 {
763            return GeometryCollection(vec![return_lines]);
764        } else {
765            geom_collection.push(return_lines);
766        }
767    } else if !line_strings.is_empty() {
768        let return_line_strings = map_line_strings_to_geometry(&line_strings);
769        if number_of_geom_types == 1 {
770            return GeometryCollection(vec![return_line_strings]);
771        } else {
772            geom_collection.push(return_line_strings);
773        }
774    } else if !polygons.0.is_empty() {
775        let return_polygons = map_polygons_to_geometry(polygons);
776        if number_of_geom_types == 1 {
777            return GeometryCollection(vec![return_polygons]);
778        } else {
779            geom_collection.push(return_polygons);
780        }
781    }
782
783    GeometryCollection(geom_collection)
784}
785
786fn parse_polygon_rings_to_geom(rings: &Vec<LineString<f64>>) -> MultiPolygon<f64> {
787    // Early return for empty vector
788    if rings.len() == 0 {
789        return (vec![] as Vec<Polygon<f64>>).into();
790    }
791
792    let mut ring_iter = rings.iter();
793    let mut result_poly = MultiPolygon(vec![Polygon::new(
794        ring_iter.next().unwrap().clone(),
795        vec![],
796    )]);
797
798    result_poly
799}
800
801fn map_lines_to_geometry(lines: &Vec<Line<f64>>) -> Geometry<f64> {
802    if lines.len() == 1 {
803        lines[0].into()
804    } else {
805        let multi_line: MultiLineString<f64> = lines
806            .iter()
807            .map(|x| LineString(vec![x.start, x.end]))
808            .collect();
809        multi_line.into()
810    }
811}
812
813fn map_line_strings_to_geometry(line_strings: &Vec<LineString<f64>>) -> Geometry<f64> {
814    if line_strings.len() == 1 {
815        line_strings[0].clone().into()
816    } else {
817        let multi_line: MultiLineString<f64> = MultiLineString(line_strings.to_vec());
818        multi_line.into()
819    }
820}
821
822fn map_polygons_to_geometry(polys: MultiPolygon<f64>) -> Geometry<f64> {
823    if polys.0.len() == 1 {
824        polys.0[0].clone().into()
825    } else {
826        polys.into()
827    }
828}
829
830/** Tests */
831
832#[cfg(test)]
833mod tests {
834    use super::*;
835    use crate::geo_svg_writer::ToSvg;
836    use geo_types::{line_string, polygon};
837
838    #[test]
839    fn can_convert_svg_path() {
840        let poly = polygon!(
841        exterior: [
842            (x: 0.0, y: 0.0),
843            (x: 0.0, y: 60.0),
844            (x: 60.0, y: 60.0),
845            (x: 60.0, y: 0.0),
846            (x: 0.0, y: 0.0),],
847        interiors:[[
848            (x: 10.0, y: 10.0),
849            (x: 40.0, y: 1.0),
850            (x: 40.0, y: 40.0),
851            (x: 10.50, y: 40.0),
852            (x: 10.0, y: 10.0),]
853            ]
854        );
855        let svg_string = String::from("M0 0l0 60l60 0L60 0L0 0M10 10L40 1L40 40L10.5 40L10 10");
856        let parsed_svg = svg_d_path_to_geometry_collection(&svg_string);
857        assert_eq!(parsed_svg.is_ok(), true);
858        let geom = parsed_svg.ok().unwrap();
859        assert_eq!(1, geom.0.len());
860        let pl = geom.0[0].clone().into_polygon();
861        assert_eq!(true, pl.is_some());
862        assert_eq!(pl.unwrap(), poly);
863    }
864
865    #[test]
866    fn can_convert_svg_path_test() {
867        let poly: Polygon<f64> = polygon!(
868        exterior: [
869            (x: 0.0_f64, y: 0.0),
870            (x: 0.0, y: 60.0),
871            (x: 60.0, y: 60.0),
872            (x: 60.0, y: 0.0),
873            (x: 0.0, y: 0.0),],
874        interiors:[[
875            (x: 10.0, y: 10.0),
876            (x: 40.0, y: 1.0),
877            (x: 40.0, y: 40.0),
878            (x: 10.50, y: 40.0),
879            (x: 10.0, y: 10.0),]
880            ]
881        )
882        .into();
883        let svg_string =
884            String::from(r#"<path d="M0 0L0 60L60 60L60 0L0 0M10 10L40 1L40 40L10.5 40L10 10"/>"#);
885        let parsed_svg = svg_to_geometry_collection(&svg_string);
886        assert_eq!(parsed_svg.is_ok(), true);
887        let geom = parsed_svg.ok().unwrap();
888        assert_eq!(1, geom.0.len());
889        let pl = geom.0[0].clone().into_polygon();
890        assert_eq!(true, pl.is_some());
891        assert_eq!(poly, pl.unwrap());
892    }
893
894    #[test]
895    fn can_convert_svg_h_v_path_test() {
896        let poly: Polygon<f64> = polygon!(
897        exterior: [
898            (x: 0.0_f64, y: 0.0),
899            (x: 0.0, y: 60.0),
900            (x: 60.0, y: 60.0),
901            (x: 60.0, y: 0.0),
902            (x: 0.0, y: 0.0),],
903        interiors:[[
904            (x: 10.0, y: 10.0),
905            (x: 40.0, y: 1.0),
906            (x: 40.0, y: 40.0),
907            (x: 10.50, y: 40.0),
908            (x: 10.0, y: 10.0),]
909            ]
910        )
911        .into();
912        let svg_string =
913            String::from(r#"<path d="M0 0v60h60v-60h-60M10 10L40 1L40 40L10.5 40L10 10"/>"#);
914        let parsed_svg = svg_to_geometry_collection(&svg_string);
915        assert_eq!(parsed_svg.is_ok(), true);
916        let geom = parsed_svg.ok().unwrap();
917        assert_eq!(1, geom.0.len());
918        let pl = geom.0[0].clone().into_polygon();
919        assert_eq!(true, pl.is_some());
920        assert_eq!(poly, pl.unwrap());
921    }
922
923    #[test]
924    fn can_convert_svg_c_s_path_test() {
925        let solution = String::from(
926            r#"<path d="M0 0L0.00895 0.89401L0.0356 1.7760799999999999L0.07964999999999998 2.6462699999999995L0.14079999999999998 3.5046399999999998L0.21875000000000003 4.35125L0.3132 5.186159999999999L0.42385000000000006 6.00943L0.5504 6.8211200000000005L0.6925499999999999 7.621289999999999L0.8500000000000001 8.41L1.02245 9.18731L1.2095999999999998 9.95328L1.4111500000000001 10.70797L1.6268000000000002 11.451440000000002L1.8562499999999997 12.18375L2.0992 12.90496L2.3553500000000005 13.61513L2.6244 14.314320000000002L2.90605 15.002590000000001L3.2 15.680000000000001L3.5059499999999995 16.34661L3.8236 17.002480000000002L4.15265 17.64767L4.492799999999999 18.282239999999998L4.84375 18.90625L5.2052000000000005 19.51976L5.576850000000001 20.122830000000004L5.9584 20.715519999999998L6.349549999999999 21.297889999999995L6.749999999999999 21.869999999999997L7.15945 22.43191L7.5776 22.98368L8.00415 23.525369999999995L8.4388 24.05704L8.88125 24.578750000000003L9.331199999999999 25.090559999999996L9.788350000000001 25.592530000000004L10.2524 26.084719999999997L10.723050000000002 26.567190000000004L11.200000000000001 27.04L11.68295 27.503210000000003L12.1716 27.956880000000005L12.66565 28.401070000000004L13.164800000000001 28.835840000000005L13.668750000000003 29.261250000000004L14.177200000000003 29.677360000000004L14.689849999999996 30.084229999999998L15.206399999999997 30.481919999999995L15.726550000000001 30.870490000000004L16.25 31.25L16.776449999999997 31.620509999999996L17.305600000000002 31.98208L17.83715 32.334770000000006L18.370800000000003 32.67864L18.906250000000004 33.013749999999995L19.443200000000004 33.34016L19.98135 33.65792999999999L20.520399999999995 33.967119999999994L21.060049999999997 34.26779L21.599999999999998 34.56L22.139950000000002 34.84381L22.6796 35.11928L23.21865 35.38647L23.756800000000002 35.64544L24.293750000000003 35.896249999999995L24.829200000000004 36.138960000000004L25.36285 36.373630000000006L25.8944 36.60032L26.42355 36.81909L26.95 37.03L27.47345 37.233109999999996L27.993599999999994 37.42847999999999L28.510149999999996 37.61617L29.022800000000007 37.796240000000004L29.53125 37.96875L30.035199999999996 38.13376L30.534350000000007 38.29133L31.028400000000005 38.441520000000004L31.517049999999998 38.58439L32 38.72L32.47695 38.84841L32.947599999999994 38.969680000000004L33.41164999999999 39.08387L33.8688 39.19104L34.31875 39.29125L34.7612 39.38456L35.19584999999999 39.47103L35.622400000000006 39.550720000000005L36.040549999999996 39.623689999999996L36.449999999999996 39.69L36.850449999999995 39.74971L37.241600000000005 39.80288L37.62315000000001 39.84957L37.99479999999999 39.88984L38.356249999999996 39.923750000000005L38.70719999999999 39.95136L39.04734999999999 39.97273L39.376400000000004 39.98792L39.69405 39.99699L40 40L40.29702 40.00596L40.588159999999995 40.023680000000006L40.87353999999999 40.052919999999986L41.153279999999995 40.093439999999994L41.427499999999995 40.14499999999999L41.696319999999986 40.207359999999994L41.95985999999999 40.28027999999999L42.21824000000001 40.363520000000015L42.47158 40.45684L42.72 40.56000000000001L42.963620000000006 40.672760000000004L43.20256 40.79488L43.43693999999999 40.92611999999999L43.66688 41.06624L43.8925 41.215L44.11392 41.37216L44.33126 41.537479999999995L44.54464000000001 41.71072L44.754180000000005 41.89164000000001L44.96 42.08L45.162220000000005 42.275560000000006L45.360960000000006 42.478080000000006L45.55634 42.68732L45.74848 42.90304L45.9375 43.125L46.12352 43.35296L46.30666 43.58668L46.48704 43.825919999999996L46.66477999999999 44.07043999999999L46.83999999999999 44.31999999999999L47.01281999999999 44.57436L47.18335999999999 44.83327999999999L47.35173999999999 45.09651999999999L47.51807999999999 45.363839999999996L47.682500000000005 45.635L47.845119999999994 45.909760000000006L48.006060000000005 46.18788L48.165440000000004 46.469120000000004L48.32338 46.753240000000005L48.480000000000004 47.040000000000006L48.63542000000001 47.32916L48.78976000000001 47.62048000000001L48.94314000000001 47.91372000000001L49.09568000000001 48.20864L49.2475 48.505L49.398720000000004 48.80256000000001L49.549459999999996 49.10108000000001L49.69984 49.400319999999994L49.84998 49.70004L50 50L50.15002 50.29996L50.300160000000005 50.59968L50.45054 50.89892L50.60128 51.19744L50.7525 51.495000000000005L50.90432 51.791360000000005L51.05686 52.08628L51.21024 52.37951999999999L51.364580000000004 52.67084L51.519999999999996 52.96L51.67662 53.24676L51.834559999999996 53.53088L51.993939999999995 53.81211999999999L52.15488 54.09024L52.3175 54.364999999999995L52.48192 54.636160000000004L52.64826000000001 54.90348L52.81664000000001 55.16672L52.98718000000001 55.42564L53.160000000000004 55.68000000000001L53.33521999999999 55.929559999999995L53.51295999999999 56.17408L53.69334 56.41332L53.87648 56.64704L54.0625 56.875L54.25152 57.09696L54.44366 57.31268000000001L54.63904000000001 57.52192L54.83778000000001 57.72444L55.04 57.92L55.245819999999995 58.10836L55.45536 58.28928L55.66873999999999 58.46252L55.88608 58.62783999999999L56.1075 58.785L56.33312 58.93376000000001L56.56306000000001 59.07388000000001L56.79744 59.20512L57.036379999999994 59.327239999999996L57.28 59.44L57.528420000000004 59.54316L57.781760000000006 59.63648L58.04014000000001 59.719719999999995L58.30368 59.792640000000006L58.5725 59.855000000000004L58.84672 59.90655999999999L59.12645999999999 59.94708L59.41184 59.976319999999994L59.70298 59.99404L60 60L60 0L0 0M10 10L20 10L20 20L10 20L10 10"/>"#,
927        );
928        let svg_string = String::from(
929            r#"<path d="M0 0C0 30 30 40 40 40S50 60 60 60L60 0ZM10 10L20 10L20 20L10 20L10 10" />"#,
930        );
931        let parsed_svg = svg_to_geometry_collection(&svg_string);
932        assert_eq!(true, parsed_svg.is_ok());
933        let svg = parsed_svg.ok().unwrap().to_svg();
934        assert_eq!(solution, svg);
935    }
936
937    #[test]
938    fn can_convert_svg_q_t_path_test() {
939        let solution = String::from(
940            r#"<path d="M0 0L0.598 0.796L1.192 1.584L1.7819999999999998 2.364L2.368 3.136L2.95 3.9L3.5279999999999996 4.655999999999999L4.102 5.404L4.672000000000001 6.144000000000001L5.2379999999999995 6.8759999999999994L5.800000000000001 7.6L6.3580000000000005 8.316L6.911999999999999 9.024000000000001L7.462 9.724L8.008000000000001 10.416L8.549999999999999 11.1L9.088000000000001 11.776L9.622 12.444L10 12.914716981132074L10 10L20 10L20 20L15.858156028368795 20L16.2 20.4L16.678 20.956L17.152 21.503999999999998L17.622 22.044L18.088 22.576L18.55 23.1L19.007999999999996 23.616L19.462 24.124000000000002L19.912 24.624L20.358000000000004 25.116L20.8 25.6L21.238 26.076L21.672 26.544000000000004L22.102 27.003999999999998L22.528000000000002 27.456000000000003L22.950000000000003 27.9L23.368000000000006 28.336000000000006L23.781999999999996 28.763999999999996L24.191999999999997 29.183999999999997L24.598000000000003 29.596000000000004L25 30L25.397999999999996 30.395999999999997L25.792 30.784L26.182000000000002 31.164L26.568 31.536L26.950000000000003 31.9L27.328000000000003 32.256L27.701999999999998 32.604L28.071999999999996 32.944L28.438 33.275999999999996L28.799999999999997 33.6L29.158 33.916L29.512000000000004 34.224000000000004L29.862 34.524L30.208 34.816L30.55 35.1L30.888 35.376000000000005L31.222 35.644L31.552 35.904L31.878 36.156L32.2 36.400000000000006L32.518 36.635999999999996L32.831999999999994 36.864L33.141999999999996 37.084L33.44800000000001 37.296L33.75 37.5L34.047999999999995 37.696L34.342000000000006 37.884L34.632000000000005 38.064L34.918 38.236000000000004L35.2 38.4L35.478 38.556000000000004L35.751999999999995 38.704L36.02199999999999 38.843999999999994L36.288000000000004 38.976L36.550000000000004 39.1L36.808 39.216L37.062 39.324L37.312000000000005 39.42400000000001L37.558 39.516L37.8 39.6L38.038 39.675999999999995L38.272000000000006 39.744L38.502 39.804L38.727999999999994 39.855999999999995L38.95 39.9L39.168 39.936L39.38199999999999 39.964L39.592000000000006 39.984L39.797999999999995 39.996L40 40L40.199999999999996 40.002L40.4 40.008L40.599999999999994 40.017999999999994L40.8 40.032L41 40.05L41.199999999999996 40.071999999999996L41.39999999999999 40.09799999999999L41.60000000000001 40.128000000000014L41.8 40.162L42 40.2L42.2 40.242000000000004L42.4 40.288000000000004L42.599999999999994 40.337999999999994L42.8 40.391999999999996L43 40.45L43.2 40.512L43.4 40.577999999999996L43.6 40.648L43.80000000000001 40.72200000000001L44 40.8L44.2 40.882000000000005L44.400000000000006 40.968L44.599999999999994 41.058L44.8 41.152L45 41.25L45.2 41.352000000000004L45.400000000000006 41.458L45.599999999999994 41.568L45.8 41.681999999999995L46 41.8L46.199999999999996 41.922L46.39999999999999 42.047999999999995L46.599999999999994 42.178L46.8 42.312L47 42.45L47.199999999999996 42.592L47.400000000000006 42.738L47.599999999999994 42.888000000000005L47.800000000000004 43.042L48 43.2L48.2 43.362L48.400000000000006 43.528000000000006L48.60000000000001 43.69800000000001L48.80000000000001 43.872L49 44.05L49.2 44.232L49.400000000000006 44.418000000000006L49.599999999999994 44.608L49.8 44.80199999999999L50 45L50.2 45.202L50.400000000000006 45.408L50.599999999999994 45.617999999999995L50.8 45.83200000000001L51 46.05L51.199999999999996 46.272000000000006L51.400000000000006 46.498000000000005L51.599999999999994 46.727999999999994L51.8 46.962L52 47.2L52.2 47.44200000000001L52.400000000000006 47.688L52.6 47.938L52.8 48.192L53 48.45L53.199999999999996 48.712L53.400000000000006 48.97800000000001L53.6 49.248L53.80000000000001 49.52199999999999L54 49.8L54.2 50.081999999999994L54.4 50.368L54.599999999999994 50.658L54.8 50.952L55 51.25L55.2 51.55200000000001L55.400000000000006 51.858000000000004L55.6 52.168L55.800000000000004 52.482000000000006L56 52.800000000000004L56.199999999999996 53.122L56.4 53.448L56.599999999999994 53.778000000000006L56.8 54.111999999999995L57 54.449999999999996L57.2 54.792L57.400000000000006 55.138000000000005L57.6 55.48799999999999L57.8 55.842L58 56.2L58.2 56.562000000000005L58.400000000000006 56.928L58.60000000000001 57.298L58.800000000000004 57.672L59 58.05L59.199999999999996 58.431999999999995L59.39999999999999 58.818L59.6 59.208L59.8 59.602L60 60L60 0L0 0"/>
941<path d="M10 12.914716981132074L10 20L15.858156028368795 20L15.717999999999998 19.836L15.232 19.264000000000003L14.742 18.684L14.248000000000001 18.096L13.75 17.5L13.248 16.896L12.742 16.284000000000002L12.232 15.664000000000001L11.718 15.036000000000001L11.200000000000001 14.4L10.678 13.756L10.152000000000001 13.104L10 12.914716981132074"/>"#,
942        );
943        let svg_string = String::from(
944            r#"<path d="M0 0Q30 40 40 40T60 60L60 0ZM10 10L20 10L20 20L10 20L10 10" />"#,
945        );
946        let parsed_svg = svg_to_geometry_collection(&svg_string);
947        assert_eq!(true, parsed_svg.is_ok());
948        let svg = parsed_svg.ok().unwrap().to_svg();
949        assert_eq!(solution, svg);
950    }
951
952    #[test]
953    fn can_convert_svg_polygon_test() {
954        let poly: Polygon<f64> = polygon!(
955        exterior: [
956            (x: 0.0_f64, y: 0.0),
957            (x: 0.0, y: 60.0),
958            (x: 60.0, y: 60.0),
959            (x: 60.0, y: 0.0),
960            (x: 0.0, y: 0.0),],
961        interiors:[]
962        )
963        .into();
964        let svg_string = String::from(r#"<polygon points="0, 0 60, 0 60, 60 0, 60 0, 0"/>"#);
965        let parsed_svg = svg_to_geometry_collection(&svg_string);
966        assert_eq!(parsed_svg.is_ok(), true);
967        let geom = parsed_svg.ok().unwrap();
968        assert_eq!(1, geom.0.len());
969        let pl = geom.0[0].clone().into_polygon();
970        assert_eq!(true, pl.is_some());
971        assert_eq!(poly, pl.unwrap());
972    }
973
974    #[test]
975    fn can_convert_svg_polyline_test() {
976        let line: LineString<f64> = line_string![
977            (x: 0.0_f64, y: 0.0),
978            (x: 0.0, y: 60.0),
979            (x: 60.0, y: 60.0),
980            (x: 60.0, y: 0.0),]
981        .into();
982        let svg_string = String::from(r#"<polyline points="0, 0 0, 60 60, 60 60, 0"/>"#);
983        let parsed_svg = svg_to_geometry_collection(&svg_string);
984        assert_eq!(parsed_svg.is_ok(), true);
985        let geom = parsed_svg.ok().unwrap();
986        assert_eq!(1, geom.0.len());
987        let pl = geom.0[0].clone().into_line_string();
988        assert_eq!(true, pl.is_some());
989        assert_eq!(line, pl.unwrap());
990    }
991
992    #[test]
993    fn can_convert_svg_rect_test() {
994        let poly: Polygon<f64> = polygon!(
995        exterior: [
996            (x: 0.0_f64, y: 0.0),
997            (x: 0.0, y: 60.0),
998            (x: 60.0, y: 60.0),
999            (x: 60.0, y: 0.0),
1000            (x: 0.0, y: 0.0),],
1001        interiors:[]
1002        )
1003        .into();
1004        let svg_string = String::from(r#"<rect x="0" y="0" width="60" height="60"/>"#);
1005        let parsed_svg = svg_to_geometry_collection(&svg_string);
1006        assert_eq!(parsed_svg.is_ok(), true);
1007        let geom = parsed_svg.ok().unwrap();
1008        assert_eq!(1, geom.0.len());
1009        let pl = geom.0[0].clone().into_polygon();
1010        assert_eq!(true, pl.is_some());
1011        assert_eq!(poly, pl.unwrap());
1012    }
1013
1014    #[test]
1015    fn can_convert_svg_path_to_single_geom() {
1016        let poly: Polygon<f64> = polygon!(
1017        exterior: [
1018            (x: 0.0_f64, y: 0.0),
1019            (x: 0.0, y: 60.0),
1020            (x: 60.0, y: 60.0),
1021            (x: 60.0, y: 0.0),
1022            (x: 0.0, y: 0.0),],
1023        interiors:[[
1024            (x: 10.0, y: 10.0),
1025            (x: 40.0, y: 1.0),
1026            (x: 40.0, y: 40.0),
1027            (x: 10.50, y: 40.0),
1028            (x: 10.0, y: 10.0),]
1029            ]
1030        );
1031        let svg_string =
1032            String::from(r#"<path d="M0 0L0 60L60 60L60 0L0 0M10 10L40 1L40 40L10.5 40L10 10"/>"#);
1033
1034        let parsed_svg = svg_to_geometry(&svg_string);
1035        assert!(parsed_svg.is_ok());
1036        let parsed_poly = parsed_svg.ok().unwrap().into_polygon();
1037        assert!(parsed_poly.is_some());
1038        //assert_eq!(poly, parsed_poly.unwrap());
1039        //let concave_hull = parsed_poly.unwrap().concave_hull(2.0);
1040        //assert!(!concave_hull.is_empty());
1041    }
1042
1043    #[test]
1044    fn can_convert_svg_polygon_to_single_geom() {
1045        let poly: Polygon<f64> = polygon!(
1046        exterior: [
1047            (x: 0.0_f64, y: 0.0),
1048            (x: 0.0, y: 60.0),
1049            (x: 60.0, y: 60.0),
1050            (x: 60.0, y: 0.0),
1051            (x: 0.0, y: 0.0),],
1052        interiors:[]
1053        );
1054        let svg_string = String::from(r#"<polygon points="0, 0 60, 0 60, 60 0, 60 0, 0"/>"#);
1055
1056        let parsed_svg = svg_to_geometry(&svg_string);
1057        assert!(parsed_svg.is_ok());
1058        let parsed_poly = parsed_svg.ok().unwrap().into_polygon();
1059        assert!(parsed_poly.is_some());
1060        assert_eq!(poly, parsed_poly.unwrap());
1061    }
1062}