Skip to content

Instantly share code, notes, and snippets.

@AtkinsSJ
Created April 6, 2013 18:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AtkinsSJ/5327208 to your computer and use it in GitHub Desktop.
Save AtkinsSJ/5327208 to your computer and use it in GitHub Desktop.
This is a class I've written to grab data from svg files made in Inkscape. (Saved as Inkscape svg, not plain svg) Create an SvgParser, call fromFile() with a file handle to the svg file, and you'll be able to access layers by what you named then in Inkscape, using getLayer(name), then access paths from the Layer with getPath(id), or points with …
package uk.co.samatkins.racing;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.XmlReader;
import com.badlogic.gdx.utils.XmlReader.Element;
import com.badlogic.gdx.math.Vector2;
public class SvgParser {
private HashMap<String, Layer> layers;
public SvgParser() {
layers = new HashMap<String, Layer>();
}
public void fromFile(FileHandle file) throws IOException {
XmlReader reader = new XmlReader();
XmlReader.Element xml;
xml = reader.parse(file);
Array<Element> gs = xml.getChildrenByName("g");
for (Element g : gs ) {
if (g.getAttribute("inkscape:groupmode").equals("layer")) {
Layer l = new Layer(transformToVector(g.getAttribute("transform", "")));
for (int i=0; i<g.getChildCount(); i++) {
Element el = g.getChild(i);
switch (el.getName()) {
case "path":
l.addPath(el.getAttribute("id"), this.svgPathToVertices(el.getAttribute("d")));
break;
case "text":
l.addPoint(el.getAttribute("id"),
new Vector2(Float.parseFloat(el.getAttribute("x")),
Float.parseFloat(el.getAttribute("y"))));
break;
}
}
this.addLayer(g.getAttribute("inkscape:label"), l);
}
}
}
/**
* Takes a path's data, and returns an array of vectors for its vertices.
* @param pathString The 'd' attribute from the svg 'path' element
* @return
*/
private Vector2[] svgPathToVertices(String pathString) {
ArrayList<Vector2> vertexList = new ArrayList<Vector2>();
boolean relativeCoords = false;
// get the path string
String[] pathParts = pathString.split(" ");
for (String s: pathParts) {
if (s.charAt(0) == 'm') {
relativeCoords = true;
} else if (s.charAt(0) == 'M') {
relativeCoords = false;
} else if (s.charAt(0) == 'l') {
relativeCoords = true;
} else if (s.charAt(0) == 'L') {
relativeCoords = false;
} else if (Character.isDigit(s.charAt(0)) || s.charAt(0) == '-') {
String[] coords = s.split(",");
if (vertexList.size() > 0 && relativeCoords) {
Vector2 last = vertexList.get(vertexList.size()-1);
vertexList.add( new Vector2( Float.parseFloat(coords[0]) + last.x, Float.parseFloat(coords[1]) + last.y ) );
} else {
vertexList.add( new Vector2( Float.parseFloat(coords[0]), Float.parseFloat(coords[1]) ) );
}
}
}
Vector2[] v = new Vector2[vertexList.size()];
return vertexList.toArray(v);
}
private void addLayer(String id, Layer layer) {
this.layers.put(id, layer);
}
public Layer getLayer(String id) {
return this.layers.get(id);
}
private Vector2 transformToVector(String transform) {
if (transform.startsWith("translate")) {
String[] parts = transform.substring(10, transform.length()-1).split(",");
return new Vector2(Float.parseFloat(parts[0]), Float.parseFloat(parts[1]));
}
return Vector2.Zero;
}
public class Layer {
private HashMap<String, Vector2[]> paths;
private HashMap<String, Vector2> points;
private Vector2 position;
public Layer(Vector2 offset) {
paths = new HashMap<String, Vector2[]>();
points = new HashMap<String, Vector2>();
position = offset;
}
/**
* Adds the given path to this layer.
* If this layer has a translation, the path is normalised.
* @param id
* @param path
*/
public void addPath(String id, Vector2[] path) {
for (int i=0; i<path.length; i++) {
path[i] = path[i].add(position);
}
this.paths.put(id, path);
}
public Vector2[] getPath(String id) {
return this.paths.get(id);
}
/**
* Adds the given point to this layer.
* If this layer has a translation, the point is normalised.
* @param id
* @param point
*/
public void addPoint(String id, Vector2 point) {
this.points.put(id, point.add(position));
}
public Vector2 getPoint(String id) {
return this.points.get(id);
}
}
}
Display the source blob
Display the rendered blob
Raw
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
width="1052.3622"
height="744.09448"
id="svg2"
inkscape:version="0.47 r22583"
sodipodi:docname="track1.svg">
<metadata
id="metadata2824">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1680"
inkscape:window-height="988"
id="namedview2822"
showgrid="true"
inkscape:zoom="0.89702957"
inkscape:cx="314.8279"
inkscape:cy="239.81161"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="layer3">
<inkscape:grid
type="xygrid"
id="grid2883"
empspacing="1"
visible="false"
enabled="true"
snapvisiblegridlinesonly="true" />
</sodipodi:namedview>
<defs
id="defs4">
<inkscape:path-effect
effect="skeletal"
id="path-effect3449"
is_visible="true"
pattern="M 0,0 0,10 10,5 z"
copytype="single_stretched"
prop_scale="1"
scale_y_rel="false"
spacing="0"
normal_offset="0"
tang_offset="0"
prop_units="false"
vertical_pattern="false"
fuse_tolerance="0" />
<inkscape:path-effect
effect="skeletal"
id="path-effect3445"
is_visible="true"
pattern="M 0,5 10,10 10,0 z"
copytype="single_stretched"
prop_scale="1"
scale_y_rel="false"
spacing="0"
normal_offset="0"
tang_offset="0"
prop_units="false"
vertical_pattern="false"
fuse_tolerance="0" />
<inkscape:path-effect
effect="skeletal"
id="path-effect3441"
is_visible="true"
pattern="M 0,5 C 0,2.24 2.24,0 5,0 7.76,0 10,2.24 10,5 10,7.76 7.76,10 5,10 2.24,10 0,7.76 0,5 z"
copytype="single_stretched"
prop_scale="1"
scale_y_rel="false"
spacing="0"
normal_offset="0"
tang_offset="0"
prop_units="false"
vertical_pattern="false"
fuse_tolerance="0" />
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="35.673294 : 12.262693 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="983.77443 : 345.58504 : 1"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
id="perspective2826" />
<inkscape:perspective
id="perspective2844"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective2866"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
</defs>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="collisions"
transform="translate(0,-308.2677)">
<path
style="fill:none;stroke:#000000;stroke-width:1.24027729px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="inside"
d="M 330,972.36218 733.943,966.17172 910,680.45742 l 20,-168.09524 -140,-130 -320,0 -300,170 0,180 160,240 z"
sodipodi:nodetypes="ccccccccc" />
<path
style="fill:none;stroke:#000000;stroke-width:1.95931172px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="outside"
d="m 390,312.36218 -390,170 L 3.3814897,742.8551 270,1052.3622 l 560,0 220,-364.07663 0,-225.92339 -220,-150 -440,0 z"
sodipodi:nodetypes="ccccccccc" />
</g>
<g
inkscape:groupmode="layer"
id="layer3"
inkscape:label="features">
<text
xml:space="preserve"
style="font-size:40px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
x="698.20313"
y="713.6062"
id="start"
inkscape:label="#start"><tspan
sodipodi:role="line"
id="tspan2916"
x="698.20313"
y="713.6062">Start</tspan></text>
</g>
</svg>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment