2 releases
0.1.1 | Apr 22, 2020 |
---|---|
0.1.0 | Apr 15, 2020 |
#164 in Geospatial
80KB
1.5K
SLoC
rust-geo-svg
Functionality to convert between SVG and geo-types.
SVG to Geometry
This package provides a functions to read a string containing an SVG element or d
string and parse it to a geometry.
svg_to_geometry(svg: &str)
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:
- <path> → Geometry with the autodetected Geometry type
- <polygon> → Polygon
- <polyline> → LineString
- <rect> → Polygon
- <line> → Line
Examples
use geo_types::{ Polygon, polygon };
use geo_svg_io::geo_svg_reader::svg_to_geometry;
let poly: Polygon<f64> = polygon!(
exterior: [
(x: 0.0_f64, y: 0.0),
(x: 0.0, y: 60.0),
(x: 60.0, y: 60.0),
(x: 60.0, y: 0.0),
(x: 0.0, y: 0.0),],
interiors:[[
(x: 10.0, y: 10.0),
(x: 40.0, y: 1.0),
(x: 40.0, y: 40.0),
(x: 10.50, y: 40.0),
(x: 10.0, y: 10.0),]
]
);
let svg_string =
String::from(r#"<path d="M0 0L0 60L60 60L60 0L0 0M10 10L40 1L40 40L10.5 40L10 10"/>"#);
let parsed_svg = svg_to_geometry(&svg_string);
assert!(parsed_svg.is_ok());
let parsed_poly = parsed_svg.ok().unwrap().into_polygon();
assert!(parsed_poly.is_some());
assert_eq!(poly, parsed_poly.unwrap());
use geo_types::{ Polygon, polygon };
use geo_svg_io::geo_svg_reader::svg_to_geometry;
let poly: Polygon<f64> = polygon!(
exterior: [
(x: 0.0_f64, y: 0.0),
(x: 0.0, y: 60.0),
(x: 60.0, y: 60.0),
(x: 60.0, y: 0.0),
(x: 0.0, y: 0.0),],
interiors:[]
);
let svg_string = String::from(r#"<polygon points="0, 0 60, 0 60, 60 0, 60 0, 0"/>"#);
let parsed_svg = svg_to_geometry(&svg_string);
assert!(parsed_svg.is_ok());
let parsed_poly = parsed_svg.ok().unwrap().into_polygon();
assert!(parsed_poly.is_some());
assert_eq!(poly, parsed_poly.unwrap());
svg_to_geometry_collection(svg: &str)
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:
- <path> → GeometryCollection
- <polygon> → GeometryCollection with a single Polygon
- <polyline> → GeometryCollection with a single LineString
- <rect> → GeometryCollection with a single Polygon
- <line> → GeometryCollection with a single Line
Examples
use geo_types::{ Polygon, polygon };
use geo_svg_io::geo_svg_reader::svg_to_geometry_collection;
let poly: Polygon<f64> = polygon!(
exterior: [
(x: 0.0_f64, y: 0.0),
(x: 0.0, y: 60.0),
(x: 60.0, y: 60.0),
(x: 60.0, y: 0.0),
(x: 0.0, y: 0.0),],
interiors:[[
(x: 10.0, y: 10.0),
(x: 40.0, y: 1.0),
(x: 40.0, y: 40.0),
(x: 10.50, y: 40.0),
(x: 10.0, y: 10.0),]
]
)
.into();
let svg_string =
String::from(r#"<path d="M0 0L0 60L60 60L60 0L0 0M10 10L40 1L40 40L10.5 40L10 10"/>"#);
let parsed_svg = svg_to_geometry_collection(&svg_string);
assert!(parsed_svg.is_ok());
// Unwrap the GeometryCollection result
let geom = parsed_svg.ok().unwrap();
assert_eq!(1, geom.0.len());
// Read the geometry as a Polygon
let pl = geom.0[0].clone().into_polygon();
assert_eq!(true, pl.is_some());
assert_eq!(poly, pl.unwrap());
use geo_types::{ Polygon, polygon };
use geo_svg_io::geo_svg_reader::svg_to_geometry;
let poly: Polygon<f64> = polygon!(
exterior: [
(x: 0.0_f64, y: 0.0),
(x: 0.0, y: 60.0),
(x: 60.0, y: 60.0),
(x: 60.0, y: 0.0),
(x: 0.0, y: 0.0),],
interiors:[]
)
.into();
let svg_string = String::from(r#"<polygon points="0, 0 60, 0 60, 60 0, 60 0, 0"/>"#);
let parsed_svg = svg_to_geometry_collection(&svg_string);
assert!(parsed_svg.is_ok());
// Unwrap the GeometryCollection result
let geom = parsed_svg.ok().unwrap();
assert_eq!(1, geom.0.len());
// Read the geometry as a Polygon
let pl = geom.0[0].clone().into_polygon();
assert_eq!(true, pl.is_some());
assert_eq!(poly, pl.unwrap());
svg_d_path_to_geometry(svg: &str)
A <path>
element d
string can be parsed directly into a Geometry by the svg_d_path_to_geometry(svg: &str)
function. The output will always be a GeometryCollection.
Examples
use geo_svg_io::geo_svg_reader::svg_d_path_to_geometry_collection;
use geo_types::polygon;
let poly = polygon!(
exterior: [
(x: 0.0, y: 0.0),
(x: 0.0, y: 60.0),
(x: 60.0, y: 60.0),
(x: 60.0, y: 0.0),
(x: 0.0, y: 0.0),],
interiors:[[
(x: 10.0, y: 10.0),
(x: 40.0, y: 1.0),
(x: 40.0, y: 40.0),
(x: 10.50, y: 40.0),
(x: 10.0, y: 10.0),]
]
);
let svg_string = String::from("M0 0l0 60l60 0L60 0L0 0M10 10L40 1L40 40L10.5 40L10 10");
let parsed_svg = svg_d_path_to_geometry(&svg_string);
assert!(parsed_svg.is_ok());
let pl = parsed_svg.ok().unwrap().into_polygon();
assert!(pl.is_some());
assert_eq!(pl.unwrap(), poly);
svg_d_path_to_geometry_collection(svg: &str)
A <path>
element d
string can be parsed directly into a GeometryCollection by the svg_d_path_to_geometry_collection(svg: &str)
function. The output will always be a GeometryCollection.
Examples
use geo_svg_io::geo_svg_reader::svg_d_path_to_geometry_collection;
use geo_types::polygon;
let poly = polygon!(
exterior: [
(x: 0.0, y: 0.0),
(x: 0.0, y: 60.0),
(x: 60.0, y: 60.0),
(x: 60.0, y: 0.0),
(x: 0.0, y: 0.0),],
interiors:[[
(x: 10.0, y: 10.0),
(x: 40.0, y: 1.0),
(x: 40.0, y: 40.0),
(x: 10.50, y: 40.0),
(x: 10.0, y: 10.0),]
]
);
let svg_string = String::from("M0 0l0 60l60 0L60 0L0 0M10 10L40 1L40 40L10.5 40L10 10");
let parsed_svg = svg_d_path_to_geometry_collection(&svg_string);
assert!(parsed_svg.is_ok());
// Unwrap the GeometryCollection result
let geom = parsed_svg.ok().unwrap();
assert_eq!(1, geom.0.len());
// Read the geometry as a Polygon
let pl = geom.0[0].clone().into_polygon();
assert_eq!(true, pl.is_some());
assert_eq!(pl.unwrap(), poly);
Error handling
Both function return a Result which will either contain the parsed Geometry or an Error of the SvgError
Enum. An error may result from passing an unsupported SVG element type, from an improperly formed SVG element, or from an inability to parse a float
from the supplied string.
Geometry to SVG
This package provides two traits for converting a Geometry to SVG. Note that the parsing of curves in <path>
d
-strings is simplistic. It plots 100 points along the curve.
TODO update this functionality to use a recursive function instead to create points until they are collinear (enough).
ToSvg
Using to_svg()
from any Geometry type with produce an SVG element of the simplest type possible:
- Polygon → <path>
- LineString → <polyline>
- Line → <line>
- Triangle → <polygon> with three points
- Rect → <rect> with
x
,y
,width
, andheight
Complex Geometry types will return multiple SVG elements separated by newline
s:
- GeometryCollection →
newline
separated SVG elements corresponding to the individual Geometries it contains - MultiPolygon →
newline
separated elements - MultiLineString →
newline
separated elements
Example
use geo_types::{ MultiPolygon, polygon };
use geo_svg_io::geo_svg_writer::ToSvg;
let poly1 = polygon![
(x: 1.0, y: 1.0),
(x: 4.0, y: 1.0),
(x: 4.0, y: 4.0),
(x: 1.0, y: 4.0),
(x: 1.0, y: 1.0),
];
let poly2 = polygon!(
exterior: [
(x: 0.0, y: 0.0),
(x: 6.0, y: 0.0),
(x: 6.0, y: 6.0),
(x: 0.0, y: 6.0),
(x: 0.0, y: 0.0),],
interiors:[[
(x: 1.0, y: 1.0),
(x: 4.0, y: 1.0),
(x: 4.0, y: 4.0),
(x: 1.50, y: 4.0),
(x: 1.0, y: 1.0),]
]
);
let mp = MultiPolygon(vec![poly1, poly2]);
let wkt_out = mp.to_svg();
let expected = String::from(
r#"<path d="M1 1L4 1L4 4L1 4L1 1"/>
<path d="M0 0L6 0L6 6L0 6L0 0M1 1L4 1L4 4L1.5 4L1 1"/>"#,
);
assert_eq!(wkt_out, expected);
ToSvgString
Using to_svg_string()
from any Geometry type will produce an SVG d
string for all the points of that geometry, which can be used in an SVG path element
Examples
use geo_types::{polygon, MultiPolygon};
use geo_svg_io::geo_svg_writer::ToSvgString;
let poly1 = polygon![
(x: 1.0, y: 1.0),
(x: 4.0, y: 1.0),
(x: 4.0, y: 4.0),
(x: 1.0, y: 4.0),
(x: 1.0, y: 1.0),
];
let poly2 = polygon!(
exterior: [
(x: 0.0, y: 0.0),
(x: 6.0, y: 0.0),
(x: 6.0, y: 6.0),
(x: 0.0, y: 6.0),
(x: 0.0, y: 0.0),],
interiors:[[
(x: 1.0, y: 1.0),
(x: 4.0, y: 1.0),
(x: 4.0, y: 4.0),
(x: 1.50, y: 4.0),
(x: 1.0, y: 1.0),]
]
);
let mp = MultiPolygon(vec![poly1, poly2]);
let wkt_out = mp.to_svg_string();
let expected = String::from(
"M1 1L4 1L4 4L1 4L1 1M0 0L6 0L6 6L0 6L0 0M1 1L4 1L4 4L1.5 4L1 1"
);
assert_eq!(wkt_out, expected);
Similar projects
For a similar project that provides higher level functionality to build SVG's from Rust geo-types, see https://github.com/lelongg/geo-svg
Dependencies
~4.5MB
~79K SLoC