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
31impl 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") }
36}
37
38pub struct SvgGeometryCollectionForGeometryError;
39
40impl 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") }
45}
46
47impl fmt::Debug for SvgUnsupportedGeometryTypeError {
49 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
50 write!(f, "{{ file: {}, line: {} }}", file!(), line!()) }
52}
53
54pub struct InvalidSvgError;
55
56impl fmt::Display for InvalidSvgError {
58 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
59 write!(f, "The SVG input is invalid") }
61}
62
63impl fmt::Debug for InvalidSvgError {
65 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
66 write!(f, "{{ file: {}, line: {} }}", file!(), line!()) }
68}
69
70pub 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 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 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 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 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 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
279pub 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 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
420pub fn svg_d_path_to_geometry_collection(svg: &str) -> Result<GeometryCollection<f64>, SvgError> {
462 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 }; let mut last_point: Option<Coordinate<f64>> = None; let mut last_control_point: Option<Coord2> = None; 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 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 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 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 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 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
669pub 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 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#[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 }
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}