svg fixes, font work, issue 350, issue 130, copying to android

This commit is contained in:
benfry
2011-05-15 17:02:53 +00:00
parent b975d8ab94
commit 14aa9f7e4a
12 changed files with 950 additions and 370 deletions
@@ -1183,11 +1183,11 @@ public class PGraphics extends PImage implements PConstants {
protected void bezierVertexCheck() {
if (shape == 0 || shape != POLYGON) {
throw new RuntimeException("beginShape() or beginShape(POLYGON) " +
"must be used before bezierVertex()");
"must be used before bezierVertex() or quadVertex()");
}
if (vertexCount == 0) {
throw new RuntimeException("vertex() must be used at least once" +
"before bezierVertex()");
"before bezierVertex() or quadVertex()");
}
}
@@ -1252,6 +1252,33 @@ public class PGraphics extends PImage implements PConstants {
}
public void quadVertex(float cx, float cy,
float x3, float y3) {
bezierVertexCheck();
float[] prev = vertices[vertexCount-1];
float x1 = prev[X];
float y1 = prev[Y];
bezierVertex(x1 + ((cx-x1)*2/3.0f), y1 + ((cy-y1)*2/3.0f),
x3 + ((cx-x3)*2/3.0f), y3 + ((cy-y3)*2/3.0f),
x3, y3);
}
public void quadVertex(float cx, float cy, float cz,
float x3, float y3, float z3) {
bezierVertexCheck();
float[] prev = vertices[vertexCount-1];
float x1 = prev[X];
float y1 = prev[Y];
float z1 = prev[Z];
bezierVertex(x1 + ((cx-x1)*2/3.0f), y1 + ((cy-y1)*2/3.0f), z1 + ((cz-z1)*2/3.0f),
x3 + ((cx-x3)*2/3.0f), y3 + ((cy-y3)*2/3.0f), z3 + ((cz-z3)*2/3.0f),
x3, y3, z3);
}
/**
* Perform initialization specific to curveVertex(), and handle standard
* error modes. Can be overridden by subclasses that need the flexibility.
@@ -484,6 +484,25 @@ public class PGraphicsAndroid2D extends PGraphics {
//////////////////////////////////////////////////////////////
// QUADRATIC BEZIER VERTICES
public void quadVertex(float ctrlX, float ctrlY,
float endX, float endY) {
bezierVertexCheck();
path.quadTo(ctrlX, ctrlY, endX, endY);
}
public void quadVertex(float x2, float y2, float z2,
float x4, float y4, float z4) {
showDepthWarningXYZ("quadVertex");
}
//////////////////////////////////////////////////////////////
// CURVE VERTICES
+40 -5
View File
@@ -122,8 +122,9 @@ public class PShape implements PConstants {
static public final int VERTEX = 0;
static public final int BEZIER_VERTEX = 1;
static public final int CURVE_VERTEX = 2;
static public final int BREAK = 3;
static public final int QUAD_BEZIER_VERTEX = 2;
static public final int CURVE_VERTEX = 3;
static public final int BREAK = 4;
/** Array of VERTEX, BEZIER_VERTEX, and CURVE_VERTEX calls. */
protected int vertexCodeCount;
protected int[] vertexCodes;
@@ -583,13 +584,32 @@ public class PShape implements PConstants {
case VERTEX:
g.vertex(vertices[index][X], vertices[index][Y]);
// cx = vertices[index][X];
// cy = vertices[index][Y];
index++;
break;
case QUAD_BEZIER_VERTEX:
g.quadVertex(vertices[index+0][X], vertices[index+0][Y],
vertices[index+1][X], vertices[index+1][Y]);
// float x1 = vertices[index+0][X];
// float y1 = vertices[index+0][Y];
// float x2 = vertices[index+1][X];
// float y2 = vertices[index+1][Y];
// g.bezierVertex(x1 + ((cx-x1)*2/3.0f), y1 + ((cy-y1)*2/3.0f),
// x2 + ((cx-x2)*2/3.0f), y2 + ((cy-y2)*2/3.0f),
// x2, y2);
// cx = vertices[index+1][X];
// cy = vertices[index+1][Y];
index += 2;
break;
case BEZIER_VERTEX:
g.bezierVertex(vertices[index+0][X], vertices[index+0][Y],
vertices[index+1][X], vertices[index+1][Y],
vertices[index+2][X], vertices[index+2][Y]);
// cx = vertices[index+2][X];
// cy = vertices[index+2][Y];
index += 3;
break;
@@ -607,9 +627,19 @@ public class PShape implements PConstants {
case VERTEX:
g.vertex(vertices[index][X], vertices[index][Y], vertices[index][Z]);
// cx = vertices[index][X];
// cy = vertices[index][Y];
// cz = vertices[index][Z];
index++;
break;
case QUAD_BEZIER_VERTEX:
g.quadVertex(vertices[index+0][X], vertices[index+0][Y], vertices[index+0][Z],
vertices[index+1][X], vertices[index+1][Y], vertices[index+0][Z]);
index += 2;
break;
case BEZIER_VERTEX:
g.bezierVertex(vertices[index+0][X], vertices[index+0][Y], vertices[index+0][Z],
vertices[index+1][X], vertices[index+1][Y], vertices[index+1][Z],
@@ -634,6 +664,10 @@ public class PShape implements PConstants {
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
public PShape getParent() {
return parent;
}
public int getChildCount() {
return childCount;
}
@@ -707,6 +741,7 @@ public class PShape implements PConstants {
}
// adds child who exactly at position idx in the array of children.
public void addChild(PShape who, int idx) {
if (idx < childCount) {
if (childCount == children.length) {
@@ -731,7 +766,7 @@ public class PShape implements PConstants {
/**
* Remove the shape with index idx.
* Remove the child shape with index idx.
*/
public void removeChild(int idx) {
if (idx < childCount) {
@@ -753,7 +788,7 @@ public class PShape implements PConstants {
/**
* Add a shape to the name lookup table.
*/
protected void addName(String nom, PShape shape) {
public void addName(String nom, PShape shape) {
if (parent != null) {
parent.addName(nom, shape);
} else {
@@ -768,7 +803,7 @@ public class PShape implements PConstants {
/**
* Returns the index of child who.
*/
protected int getChildIdx(PShape who) {
public int getChildIndex(PShape who) {
for (int i = 0; i < childCount; i++) {
if (children[i] == who) {
return i;
@@ -796,7 +796,7 @@ public class PShape3D extends PShape implements PConstants {
/**
* Add a shape to the name lookup table.
*/
protected void addName(String nom, PShape shape) {
public void addName(String nom, PShape shape) {
if (nameTable == null) {
nameTable = new HashMap<String,PShape>();
}
@@ -894,7 +894,7 @@ public class PShape3D extends PShape implements PConstants {
child = gchildren[0];
p = child.parent;
if (p != null) {
idx = p.getChildIdx(child);
idx = p.getChildIndex(child);
if (idx < 0) idx = 0;
} else {
p = this;
@@ -908,7 +908,7 @@ public class PShape3D extends PShape implements PConstants {
child = gchildren[i];
p = child.parent;
if (p != null) {
idx = p.getChildIdx(child);
idx = p.getChildIndex(child);
if (-1 < idx) {
p.removeChild(idx);
}
+230 -142
View File
@@ -3,7 +3,7 @@
/*
Part of the Processing project - http://processing.org
Copyright (c) 2006-10 Ben Fry and Casey Reas
Copyright (c) 2006-11 Ben Fry and Casey Reas
Copyright (c) 2004-06 Michael Chang
This library is free software; you can redistribute it and/or
@@ -165,7 +165,7 @@ public class PShapeSVG extends PShape {
* Initializes a new SVG Object from the given XMLElement.
*/
public PShapeSVG(XMLElement svg) {
this(null, svg);
this(null, svg, true);
if (!svg.getName().equals("svg")) {
throw new RuntimeException("root is not <svg>, it's <" + svg.getName() + ">");
@@ -202,12 +202,12 @@ public class PShapeSVG extends PShape {
}
//root = new Group(null, svg);
parseChildren(svg); // ?
// parseChildren(svg); // ?
}
public PShapeSVG(PShapeSVG parent, XMLElement properties) {
// Need to set this so that findChild() works.
public PShapeSVG(PShapeSVG parent, XMLElement properties, boolean parseKids) {
// Need to set this so that findChild() works.
// Otherwise 'parent' is null until addChild() is called later.
this.parent = parent;
@@ -277,8 +277,10 @@ public class PShapeSVG extends PShape {
matrix = parseTransform(transformStr);
}
parseColors(properties);
parseChildren(properties);
if (parseKids) {
parseColors(properties);
parseChildren(properties);
}
}
@@ -296,6 +298,7 @@ public class PShapeSVG extends PShape {
addChild(kid);
}
}
children = (PShape[]) PApplet.subset(children, 0, childCount);
}
@@ -304,53 +307,54 @@ public class PShapeSVG extends PShape {
* Override this method to add parsing for more SVG elements.
*/
protected PShape parseChild(XMLElement elem) {
// System.err.println("parsing child in pshape " + elem.getName());
String name = elem.getName();
PShapeSVG shape = null;
if (name.equals("g")) {
//return new BaseObject(this, elem);
shape = new PShapeSVG(this, elem);
shape = new PShapeSVG(this, elem, true);
} else if (name.equals("defs")) {
// generally this will contain gradient info, so may
// as well just throw it into a group element for parsing
//return new BaseObject(this, elem);
shape = new PShapeSVG(this, elem);
shape = new PShapeSVG(this, elem, true);
} else if (name.equals("line")) {
//return new Line(this, elem);
//return new BaseObject(this, elem, LINE);
shape = new PShapeSVG(this, elem);
shape = new PShapeSVG(this, elem, true);
shape.parseLine();
} else if (name.equals("circle")) {
//return new BaseObject(this, elem, ELLIPSE);
shape = new PShapeSVG(this, elem);
shape = new PShapeSVG(this, elem, true);
shape.parseEllipse(true);
} else if (name.equals("ellipse")) {
//return new BaseObject(this, elem, ELLIPSE);
shape = new PShapeSVG(this, elem);
shape = new PShapeSVG(this, elem, true);
shape.parseEllipse(false);
} else if (name.equals("rect")) {
//return new BaseObject(this, elem, RECT);
shape = new PShapeSVG(this, elem);
shape = new PShapeSVG(this, elem, true);
shape.parseRect();
} else if (name.equals("polygon")) {
//return new BaseObject(this, elem, POLYGON);
shape = new PShapeSVG(this, elem);
shape = new PShapeSVG(this, elem, true);
shape.parsePoly(true);
} else if (name.equals("polyline")) {
//return new BaseObject(this, elem, POLYGON);
shape = new PShapeSVG(this, elem);
shape = new PShapeSVG(this, elem, true);
shape.parsePoly(false);
} else if (name.equals("path")) {
//return new BaseObject(this, elem, PATH);
shape = new PShapeSVG(this, elem);
shape = new PShapeSVG(this, elem, true);
shape.parsePath();
} else if (name.equals("radialGradient")) {
@@ -359,9 +363,22 @@ public class PShapeSVG extends PShape {
} else if (name.equals("linearGradient")) {
return new LinearGradient(this, elem);
} else if (name.equals("text") || name.equals("font")) {
} else if (name.equals("font")) {
return new Font(this, elem);
// } else if (name.equals("font-face")) {
// return new FontFace(this, elem);
// } else if (name.equals("glyph") || name.equals("missing-glyph")) {
// return new FontGlyph(this, elem);
} else if (name.equals("metadata")) {
// fontforge just stuffs this in as a comment
return null;
} else if (name.equals("text")) { // || name.equals("font")) {
PGraphics.showWarning("Text and fonts in SVG files " +
"are not currently supported, " +
"are not currently supported, " +
"convert text to outlines instead.");
} else if (name.equals("filter")) {
@@ -375,12 +392,13 @@ public class PShapeSVG extends PShape {
} else if (name.equals("stop")) {
// stop tag is handled by gradient parser, so don't warn about it
} else if (name.equals("sodipodi:namedview")) {
// these are always in Inkscape files, the warnings get tedious
// these are always in Inkscape files, the warnings get tedious
} else {
PGraphics.showWarning("Ignoring <" + name + "> tag.");
PGraphics.showWarning("Ignoring <" + name + "> tag.");
// new Exception().printStackTrace();
}
return shape;
}
@@ -464,7 +482,9 @@ public class PShapeSVG extends PShape {
primitive = 0;
String pathData = element.getString("d");
if (pathData == null) return;
if (pathData == null || PApplet.trim(pathData).length() == 0) {
return;
}
char[] pathDataChars = pathData.toCharArray();
StringBuffer pathBuffer = new StringBuffer();
@@ -482,6 +502,7 @@ public class PShapeSVG extends PShape {
c == 'S' || c == 's' ||
c == 'Q' || c == 'q' || // quadratic beziers
c == 'T' || c == 't' ||
// c == 'A' || c == 'a' || // elliptical arc
c == 'Z' || c == 'z' || // closepath
c == ',') {
separate = true;
@@ -493,7 +514,7 @@ public class PShapeSVG extends PShape {
separate = false;
}
if (c == '-' && !lastSeparate) {
// allow for 'e' notation in numbers, e.g. 2.10e-9
// allow for 'e' notation in numbers, e.g. 2.10e-9
// http://dev.processing.org/bugs/show_bug.cgi?id=1408
if (i == 0 || pathDataChars[i-1] != 'e') {
pathBuffer.append("|");
@@ -509,20 +530,23 @@ public class PShapeSVG extends PShape {
}
// use whitespace constant to get rid of extra spaces and CR or LF
String[] pathDataKeys =
String[] pathTokens =
PApplet.splitTokens(pathBuffer.toString(), "|" + WHITESPACE);
vertices = new float[pathDataKeys.length][2];
vertexCodes = new int[pathDataKeys.length];
vertices = new float[pathTokens.length][2];
vertexCodes = new int[pathTokens.length];
float cx = 0;
float cy = 0;
int i = 0;
char implicitCommand = '\0';
// char prevCommand = '\0';
boolean prevCurve = false;
float ctrlX, ctrlY;
while (i < pathDataKeys.length) {
char c = pathDataKeys[i].charAt(0);
if(((c >= '0' && c <= '9') || (c == '-')) && implicitCommand != '\0') {
while (i < pathTokens.length) {
char c = pathTokens[i].charAt(0);
if (((c >= '0' && c <= '9') || (c == '-')) && implicitCommand != '\0') {
c = implicitCommand;
i--;
} else {
@@ -531,191 +555,241 @@ public class PShapeSVG extends PShape {
switch (c) {
case 'M': // M - move to (absolute)
cx = PApplet.parseFloat(pathDataKeys[i + 1]);
cy = PApplet.parseFloat(pathDataKeys[i + 2]);
cx = PApplet.parseFloat(pathTokens[i + 1]);
cy = PApplet.parseFloat(pathTokens[i + 2]);
parsePathMoveto(cx, cy);
implicitCommand = 'L';
i += 3;
break;
case 'm': // m - move to (relative)
cx = cx + PApplet.parseFloat(pathDataKeys[i + 1]);
cy = cy + PApplet.parseFloat(pathDataKeys[i + 2]);
cx = cx + PApplet.parseFloat(pathTokens[i + 1]);
cy = cy + PApplet.parseFloat(pathTokens[i + 2]);
parsePathMoveto(cx, cy);
implicitCommand = 'l';
i += 3;
break;
case 'L':
cx = PApplet.parseFloat(pathDataKeys[i + 1]);
cy = PApplet.parseFloat(pathDataKeys[i + 2]);
cx = PApplet.parseFloat(pathTokens[i + 1]);
cy = PApplet.parseFloat(pathTokens[i + 2]);
parsePathLineto(cx, cy);
i += 3;
break;
case 'l':
cx = cx + PApplet.parseFloat(pathDataKeys[i + 1]);
cy = cy + PApplet.parseFloat(pathDataKeys[i + 2]);
cx = cx + PApplet.parseFloat(pathTokens[i + 1]);
cy = cy + PApplet.parseFloat(pathTokens[i + 2]);
parsePathLineto(cx, cy);
i += 3;
break;
// horizontal lineto absolute
case 'H':
cx = PApplet.parseFloat(pathDataKeys[i + 1]);
cx = PApplet.parseFloat(pathTokens[i + 1]);
parsePathLineto(cx, cy);
i += 2;
break;
// horizontal lineto relative
case 'h':
cx = cx + PApplet.parseFloat(pathDataKeys[i + 1]);
cx = cx + PApplet.parseFloat(pathTokens[i + 1]);
parsePathLineto(cx, cy);
i += 2;
break;
case 'V':
cy = PApplet.parseFloat(pathDataKeys[i + 1]);
cy = PApplet.parseFloat(pathTokens[i + 1]);
parsePathLineto(cx, cy);
i += 2;
break;
case 'v':
cy = cy + PApplet.parseFloat(pathDataKeys[i + 1]);
cy = cy + PApplet.parseFloat(pathTokens[i + 1]);
parsePathLineto(cx, cy);
i += 2;
break;
// C - curve to (absolute)
case 'C': {
float ctrlX1 = PApplet.parseFloat(pathDataKeys[i + 1]);
float ctrlY1 = PApplet.parseFloat(pathDataKeys[i + 2]);
float ctrlX2 = PApplet.parseFloat(pathDataKeys[i + 3]);
float ctrlY2 = PApplet.parseFloat(pathDataKeys[i + 4]);
float endX = PApplet.parseFloat(pathDataKeys[i + 5]);
float endY = PApplet.parseFloat(pathDataKeys[i + 6]);
float ctrlX1 = PApplet.parseFloat(pathTokens[i + 1]);
float ctrlY1 = PApplet.parseFloat(pathTokens[i + 2]);
float ctrlX2 = PApplet.parseFloat(pathTokens[i + 3]);
float ctrlY2 = PApplet.parseFloat(pathTokens[i + 4]);
float endX = PApplet.parseFloat(pathTokens[i + 5]);
float endY = PApplet.parseFloat(pathTokens[i + 6]);
parsePathCurveto(ctrlX1, ctrlY1, ctrlX2, ctrlY2, endX, endY);
cx = endX;
cy = endY;
i += 7;
prevCurve = true;
}
break;
break;
// c - curve to (relative)
case 'c': {
float ctrlX1 = cx + PApplet.parseFloat(pathDataKeys[i + 1]);
float ctrlY1 = cy + PApplet.parseFloat(pathDataKeys[i + 2]);
float ctrlX2 = cx + PApplet.parseFloat(pathDataKeys[i + 3]);
float ctrlY2 = cy + PApplet.parseFloat(pathDataKeys[i + 4]);
float endX = cx + PApplet.parseFloat(pathDataKeys[i + 5]);
float endY = cy + PApplet.parseFloat(pathDataKeys[i + 6]);
float ctrlX1 = cx + PApplet.parseFloat(pathTokens[i + 1]);
float ctrlY1 = cy + PApplet.parseFloat(pathTokens[i + 2]);
float ctrlX2 = cx + PApplet.parseFloat(pathTokens[i + 3]);
float ctrlY2 = cy + PApplet.parseFloat(pathTokens[i + 4]);
float endX = cx + PApplet.parseFloat(pathTokens[i + 5]);
float endY = cy + PApplet.parseFloat(pathTokens[i + 6]);
parsePathCurveto(ctrlX1, ctrlY1, ctrlX2, ctrlY2, endX, endY);
cx = endX;
cy = endY;
i += 7;
prevCurve = true;
}
break;
break;
// S - curve to shorthand (absolute)
// S - curve to shorthand (absolute)
// Draws a cubic Bézier curve from the current point to (x,y). The first
// control point is assumed to be the reflection of the second control
// point on the previous command relative to the current point.
// (x2,y2) is the second control point (i.e., the control point
// at the end of the curve). S (uppercase) indicates that absolute
// coordinates will follow; s (lowercase) indicates that relative
// coordinates will follow. Multiple sets of coordinates may be specified
// to draw a polybézier. At the end of the command, the new current point
// becomes the final (x,y) coordinate pair used in the polybézier.
case 'S': {
float ppx = vertices[vertexCount-2][X];
float ppy = vertices[vertexCount-2][Y];
float px = vertices[vertexCount-1][X];
float py = vertices[vertexCount-1][Y];
float ctrlX1 = px + (px - ppx);
float ctrlY1 = py + (py - ppy);
float ctrlX2 = PApplet.parseFloat(pathDataKeys[i + 1]);
float ctrlY2 = PApplet.parseFloat(pathDataKeys[i + 2]);
float endX = PApplet.parseFloat(pathDataKeys[i + 3]);
float endY = PApplet.parseFloat(pathDataKeys[i + 4]);
parsePathCurveto(ctrlX1, ctrlY1, ctrlX2, ctrlY2, endX, endY);
// (If there is no previous command or if the previous command was not
// an C, c, S or s, assume the first control point is coincident with
// the current point.)
if (!prevCurve) {
ctrlX = cx;
ctrlY = cy;
} else {
float ppx = vertices[vertexCount-2][X];
float ppy = vertices[vertexCount-2][Y];
float px = vertices[vertexCount-1][X];
float py = vertices[vertexCount-1][Y];
ctrlX = px + (px - ppx);
ctrlY = py + (py - ppy);
}
float ctrlX2 = PApplet.parseFloat(pathTokens[i + 1]);
float ctrlY2 = PApplet.parseFloat(pathTokens[i + 2]);
float endX = PApplet.parseFloat(pathTokens[i + 3]);
float endY = PApplet.parseFloat(pathTokens[i + 4]);
parsePathCurveto(ctrlX, ctrlY, ctrlX2, ctrlY2, endX, endY);
cx = endX;
cy = endY;
i += 5;
prevCurve = true;
}
break;
break;
// s - curve to shorthand (relative)
case 's': {
float ppx = vertices[vertexCount-2][X];
float ppy = vertices[vertexCount-2][Y];
float px = vertices[vertexCount-1][X];
float py = vertices[vertexCount-1][Y];
float ctrlX1 = px + (px - ppx);
float ctrlY1 = py + (py - ppy);
float ctrlX2 = cx + PApplet.parseFloat(pathDataKeys[i + 1]);
float ctrlY2 = cy + PApplet.parseFloat(pathDataKeys[i + 2]);
float endX = cx + PApplet.parseFloat(pathDataKeys[i + 3]);
float endY = cy + PApplet.parseFloat(pathDataKeys[i + 4]);
parsePathCurveto(ctrlX1, ctrlY1, ctrlX2, ctrlY2, endX, endY);
if (!prevCurve) {
ctrlX = cx;
ctrlY = cy;
} else {
float ppx = vertices[vertexCount-2][X];
float ppy = vertices[vertexCount-2][Y];
float px = vertices[vertexCount-1][X];
float py = vertices[vertexCount-1][Y];
ctrlX = px + (px - ppx);
ctrlY = py + (py - ppy);
}
float ctrlX2 = cx + PApplet.parseFloat(pathTokens[i + 1]);
float ctrlY2 = cy + PApplet.parseFloat(pathTokens[i + 2]);
float endX = cx + PApplet.parseFloat(pathTokens[i + 3]);
float endY = cy + PApplet.parseFloat(pathTokens[i + 4]);
parsePathCurveto(ctrlX, ctrlY, ctrlX2, ctrlY2, endX, endY);
cx = endX;
cy = endY;
i += 5;
prevCurve = true;
}
break;
break;
// Q - quadratic curve to (absolute)
// Q - quadratic curve to (absolute)
// Draws a quadratic Bézier curve from the current point to (x,y) using
// (x1,y1) as the control point. Q (uppercase) indicates that absolute
// coordinates will follow; q (lowercase) indicates that relative
// coordinates will follow. Multiple sets of coordinates may be specified
// to draw a polybézier. At the end of the command, the new current point
// becomes the final (x,y) coordinate pair used in the polybézier.
case 'Q': {
float ctrlX = PApplet.parseFloat(pathDataKeys[i + 1]);
float ctrlY = PApplet.parseFloat(pathDataKeys[i + 2]);
float endX = PApplet.parseFloat(pathDataKeys[i + 3]);
float endY = PApplet.parseFloat(pathDataKeys[i + 4]);
parsePathQuadto(cx, cy, ctrlX, ctrlY, endX, endY);
ctrlX = PApplet.parseFloat(pathTokens[i + 1]);
ctrlY = PApplet.parseFloat(pathTokens[i + 2]);
float endX = PApplet.parseFloat(pathTokens[i + 3]);
float endY = PApplet.parseFloat(pathTokens[i + 4]);
//parsePathQuadto(cx, cy, ctrlX, ctrlY, endX, endY);
parsePathQuadto(ctrlX, ctrlY, endX, endY);
cx = endX;
cy = endY;
i += 5;
prevCurve = true;
}
break;
break;
// q - quadratic curve to (relative)
// q - quadratic curve to (relative)
case 'q': {
float ctrlX = cx + PApplet.parseFloat(pathDataKeys[i + 1]);
float ctrlY = cy + PApplet.parseFloat(pathDataKeys[i + 2]);
float endX = cx + PApplet.parseFloat(pathDataKeys[i + 3]);
float endY = cy + PApplet.parseFloat(pathDataKeys[i + 4]);
parsePathQuadto(cx, cy, ctrlX, ctrlY, endX, endY);
ctrlX = cx + PApplet.parseFloat(pathTokens[i + 1]);
ctrlY = cy + PApplet.parseFloat(pathTokens[i + 2]);
float endX = cx + PApplet.parseFloat(pathTokens[i + 3]);
float endY = cy + PApplet.parseFloat(pathTokens[i + 4]);
//parsePathQuadto(cx, cy, ctrlX, ctrlY, endX, endY);
parsePathQuadto(ctrlX, ctrlY, endX, endY);
cx = endX;
cy = endY;
i += 5;
prevCurve = true;
}
break;
break;
// T - quadratic curve to shorthand (absolute)
// The control point is assumed to be the reflection of the
// control point on the previous command relative to the
// current point. (If there is no previous command or if the
// previous command was not a Q, q, T or t, assume the control
// point is coincident with the current point.)
// T - quadratic curveto shorthand (absolute)
// The control point is assumed to be the reflection of the control
// point on the previous command relative to the current point.
case 'T': {
float ppx = vertices[vertexCount-2][X];
float ppy = vertices[vertexCount-2][Y];
float px = vertices[vertexCount-1][X];
float py = vertices[vertexCount-1][Y];
float ctrlX = px + (px - ppx);
float ctrlY = py + (py - ppy);
float endX = PApplet.parseFloat(pathDataKeys[i + 1]);
float endY = PApplet.parseFloat(pathDataKeys[i + 2]);
parsePathQuadto(cx, cy, ctrlX, ctrlY, endX, endY);
// If there is no previous command or if the previous command was
// not a Q, q, T or t, assume the control point is coincident
// with the current point.
if (!prevCurve) {
ctrlX = cx;
ctrlY = cy;
} else {
float ppx = vertices[vertexCount-2][X];
float ppy = vertices[vertexCount-2][Y];
float px = vertices[vertexCount-1][X];
float py = vertices[vertexCount-1][Y];
ctrlX = px + (px - ppx);
ctrlY = py + (py - ppy);
}
float endX = PApplet.parseFloat(pathTokens[i + 1]);
float endY = PApplet.parseFloat(pathTokens[i + 2]);
//parsePathQuadto(cx, cy, ctrlX, ctrlY, endX, endY);
parsePathQuadto(ctrlX, ctrlY, endX, endY);
cx = endX;
cy = endY;
i += 3;
prevCurve = true;
}
break;
// t - quadratic curve to shorthand (relative)
// t - quadratic curveto shorthand (relative)
case 't': {
float ppx = vertices[vertexCount-2][X];
float ppy = vertices[vertexCount-2][Y];
float px = vertices[vertexCount-1][X];
float py = vertices[vertexCount-1][Y];
float ctrlX = px + (px - ppx);
float ctrlY = py + (py - ppy);
float endX = cx + PApplet.parseFloat(pathDataKeys[i + 1]);
float endY = cy + PApplet.parseFloat(pathDataKeys[i + 2]);
parsePathQuadto(cx, cy, ctrlX, ctrlY, endX, endY);
if (!prevCurve) {
ctrlX = cx;
ctrlY = cy;
} else {
float ppx = vertices[vertexCount-2][X];
float ppy = vertices[vertexCount-2][Y];
float px = vertices[vertexCount-1][X];
float py = vertices[vertexCount-1][Y];
ctrlX = px + (px - ppx);
ctrlY = py + (py - ppy);
}
float endX = cx + PApplet.parseFloat(pathTokens[i + 1]);
float endY = cy + PApplet.parseFloat(pathTokens[i + 2]);
//parsePathQuadto(cx, cy, ctrlX, ctrlY, endX, endY);
parsePathQuadto(ctrlX, ctrlY, endX, endY);
cx = endX;
cy = endY;
i += 3;
prevCurve = true;
}
break;
@@ -727,18 +801,19 @@ public class PShapeSVG extends PShape {
default:
String parsed =
PApplet.join(PApplet.subset(pathDataKeys, 0, i), ",");
PApplet.join(PApplet.subset(pathTokens, 0, i), ",");
String unparsed =
PApplet.join(PApplet.subset(pathDataKeys, i), ",");
PApplet.join(PApplet.subset(pathTokens, i), ",");
System.err.println("parsed: " + parsed);
System.err.println("unparsed: " + unparsed);
if (pathDataKeys[i].equals("a") || pathDataKeys[i].equals("A")) {
if (pathTokens[i].equals("a") || pathTokens[i].equals("A")) {
String msg = "Sorry, elliptical arc support for SVG files " +
"is not yet implemented (See bug #996 for details)";
"is not yet implemented (See issue #130 for updates)";
throw new RuntimeException(msg);
}
throw new RuntimeException("shape command not handled: " + pathDataKeys[i]);
throw new RuntimeException("shape command not handled: " + pathTokens[i]);
}
// prevCommand = c;
}
}
@@ -797,13 +872,26 @@ public class PShapeSVG extends PShape {
parsePathVertex(x3, y3);
}
private void parsePathQuadto(float x1, float y1,
float cx, float cy,
// private void parsePathQuadto(float x1, float y1,
// float cx, float cy,
// float x2, float y2) {
// //System.out.println("quadto: " + x1 + "," + y1 + " " + cx + "," + cy + " " + x2 + "," + y2);
//// parsePathCode(BEZIER_VERTEX);
// parsePathCode(QUAD_BEZIER_VERTEX);
// // x1/y1 already covered by last moveto, lineto, or curveto
//
// parsePathVertex(x1 + ((cx-x1)*2/3.0f), y1 + ((cy-y1)*2/3.0f));
// parsePathVertex(x2 + ((cx-x2)*2/3.0f), y2 + ((cy-y2)*2/3.0f));
// parsePathVertex(x2, y2);
// }
private void parsePathQuadto(float cx, float cy,
float x2, float y2) {
parsePathCode(BEZIER_VERTEX);
//System.out.println("quadto: " + x1 + "," + y1 + " " + cx + "," + cy + " " + x2 + "," + y2);
// parsePathCode(BEZIER_VERTEX);
parsePathCode(QUAD_BEZIER_VERTEX);
// x1/y1 already covered by last moveto, lineto, or curveto
parsePathVertex(x1 + ((cx-x1)*2/3.0f), y1 + ((cy-y1)*2/3.0f));
parsePathVertex(x2 + ((cx-x2)*2/3.0f), y2 + ((cy-y2)*2/3.0f));
parsePathVertex(cx, cy);
parsePathVertex(x2, y2);
}
@@ -894,7 +982,7 @@ public class PShapeSVG extends PShape {
String strokeText = properties.getString("stroke");
setColor(strokeText, false);
}
if (properties.hasAttribute("stroke-opacity")) {
String strokeOpacityText = properties.getString("stroke-opacity");
setStrokeOpacity(strokeOpacityText);
@@ -926,8 +1014,8 @@ public class PShapeSVG extends PShape {
if (properties.hasAttribute("fill-opacity")) {
String fillOpacityText = properties.getString("fill-opacity");
setFillOpacity(fillOpacityText);
}
}
if (properties.hasAttribute("style")) {
String styleText = properties.getString("style");
String[] styleTokens = PApplet.splitTokens(styleText, ";");
@@ -970,19 +1058,19 @@ public class PShapeSVG extends PShape {
}
}
void setOpacity(String opacityText) {
opacity = PApplet.parseFloat(opacityText);
strokeColor = ((int) (opacity * 255)) << 24 | strokeColor & 0xFFFFFF;
fillColor = ((int) (opacity * 255)) << 24 | fillColor & 0xFFFFFF;
}
void setStrokeWeight(String lineweight) {
strokeWeight = parseUnitSize(lineweight);
}
void setStrokeOpacity(String opacityText) {
strokeOpacity = PApplet.parseFloat(opacityText);
strokeColor = ((int) (strokeOpacity * 255)) << 24 | strokeColor & 0xFFFFFF;
@@ -1004,7 +1092,7 @@ public class PShapeSVG extends PShape {
}
}
void setStrokeCap(String linecap) {
if (linecap.equals("inherit")) {
// do nothing, will inherit automatically
@@ -1019,13 +1107,13 @@ public class PShapeSVG extends PShape {
strokeCap = PConstants.PROJECT;
}
}
void setFillOpacity(String opacityText) {
fillOpacity = PApplet.parseFloat(opacityText);
fillColor = ((int) (fillOpacity * 255)) << 24 | fillColor & 0xFFFFFF;
}
void setColor(String colorText, boolean isFill) {
int opacityMask = fillColor & 0xFF000000;
@@ -1079,7 +1167,7 @@ public class PShapeSVG extends PShape {
}
}
static protected int parseRGB(String what) {
int leftParen = what.indexOf('(') + 1;
int rightParen = what.indexOf(')');
@@ -1101,7 +1189,7 @@ public class PShapeSVG extends PShape {
/**
* Used in place of element.getFloatAttribute(a) because we can
* Used in place of element.getFloatAttribute(a) because we can
* have a unit suffix (length or coordinate).
* @param element what to parse
* @param attribute name of the attribute to get
@@ -1157,7 +1245,7 @@ public class PShapeSVG extends PShape {
int count;
public Gradient(PShapeSVG parent, XMLElement properties) {
super(parent, properties);
super(parent, properties, true);
XMLElement elements[] = properties.getChildren();
offset = new float[elements.length];