mirror of
https://github.com/processing/processing4.git
synced 2026-02-03 05:39:18 +01:00
merge svg changes
This commit is contained in:
@@ -68,7 +68,7 @@ public class PShape implements PConstants {
|
||||
protected int family;
|
||||
|
||||
/** ELLIPSE, LINE, QUAD; TRIANGLE_FAN, QUAD_STRIP; etc. */
|
||||
protected int kind;
|
||||
protected int primitive;
|
||||
|
||||
protected PMatrix matrix;
|
||||
|
||||
@@ -80,7 +80,17 @@ public class PShape implements PConstants {
|
||||
//protected float y;
|
||||
//protected float width;
|
||||
//protected float height;
|
||||
/**
|
||||
* The width of the PShape document.
|
||||
* @webref
|
||||
* @brief Shape document width
|
||||
*/
|
||||
public float width;
|
||||
/**
|
||||
* The width of the PShape document.
|
||||
* @webref
|
||||
* @brief Shape document height
|
||||
*/
|
||||
public float height;
|
||||
public float depth;
|
||||
|
||||
@@ -114,7 +124,7 @@ public class PShape implements PConstants {
|
||||
static public final int BEZIER_VERTEX = 1;
|
||||
static public final int CURVE_VERTEX = 2;
|
||||
static public final int BREAK = 3;
|
||||
/** Array of VERTEX, BEZIER_VERTEX, and CURVE_VERTEXT calls. */
|
||||
/** Array of VERTEX, BEZIER_VERTEX, and CURVE_VERTEX calls. */
|
||||
protected int vertexCodeCount;
|
||||
protected int[] vertexCodes;
|
||||
/** True if this is a closed path. */
|
||||
@@ -178,21 +188,39 @@ public class PShape implements PConstants {
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a boolean value "true" if the image is set to be visible, "false" if not. This is modified with the <b>setVisible()</b> parameter.
|
||||
* <br><br>The visibility of a shape is usually controlled by whatever program created the SVG file.
|
||||
* For instance, this parameter is controlled by showing or hiding the shape in the layers palette in Adobe Illustrator.
|
||||
*
|
||||
* @webref
|
||||
* @brief Returns a boolean value "true" if the image is set to be visible, "false" if not
|
||||
*/
|
||||
public boolean isVisible() {
|
||||
return visible;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the shape to be visible or invisible. This is determined by the value of the <b>visible</b> parameter.
|
||||
* <br><br>The visibility of a shape is usually controlled by whatever program created the SVG file.
|
||||
* For instance, this parameter is controlled by showing or hiding the shape in the layers palette in Adobe Illustrator.
|
||||
* @param visible "false" makes the shape invisible and "true" makes it visible
|
||||
* @webref
|
||||
* @brief Sets the shape to be visible or invisible
|
||||
*/
|
||||
public void setVisible(boolean visible) {
|
||||
this.visible = visible;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Disables the shape's style data and uses Processing's current styles. Styles include attributes such as colors, stroke weight, and stroke joints.
|
||||
* =advanced
|
||||
* Overrides this shape's style information and uses PGraphics styles and
|
||||
* colors. Identical to ignoreStyles(true). Also disables styles for all
|
||||
* child shapes.
|
||||
* @webref
|
||||
* @brief Disables the shape's style data and uses Processing styles
|
||||
*/
|
||||
public void disableStyle() {
|
||||
style = false;
|
||||
@@ -204,7 +232,9 @@ public class PShape implements PConstants {
|
||||
|
||||
|
||||
/**
|
||||
* Re-enables style information (fill and stroke) set in the shape.
|
||||
* Enables the shape's style data and ignores Processing's current styles. Styles include attributes such as colors, stroke weight, and stroke joints.
|
||||
* @webref
|
||||
* @brief Enables the shape's style data and ignores the Processing styles
|
||||
*/
|
||||
public void enableStyle() {
|
||||
style = true;
|
||||
@@ -398,10 +428,10 @@ public class PShape implements PConstants {
|
||||
|
||||
|
||||
protected void drawPrimitive(PGraphics g) {
|
||||
if (kind == POINT) {
|
||||
if (primitive == POINT) {
|
||||
g.point(params[0], params[1]);
|
||||
|
||||
} else if (kind == LINE) {
|
||||
} else if (primitive == LINE) {
|
||||
if (params.length == 4) { // 2D
|
||||
g.line(params[0], params[1],
|
||||
params[2], params[3]);
|
||||
@@ -410,18 +440,18 @@ public class PShape implements PConstants {
|
||||
params[3], params[4], params[5]);
|
||||
}
|
||||
|
||||
} else if (kind == TRIANGLE) {
|
||||
} else if (primitive == TRIANGLE) {
|
||||
g.triangle(params[0], params[1],
|
||||
params[2], params[3],
|
||||
params[4], params[5]);
|
||||
|
||||
} else if (kind == QUAD) {
|
||||
} else if (primitive == QUAD) {
|
||||
g.quad(params[0], params[1],
|
||||
params[2], params[3],
|
||||
params[4], params[5],
|
||||
params[6], params[7]);
|
||||
|
||||
} else if (kind == RECT) {
|
||||
} else if (primitive == RECT) {
|
||||
if (image != null) {
|
||||
g.imageMode(CORNER);
|
||||
g.image(image, params[0], params[1], params[2], params[3]);
|
||||
@@ -430,29 +460,29 @@ public class PShape implements PConstants {
|
||||
g.rect(params[0], params[1], params[2], params[3]);
|
||||
}
|
||||
|
||||
} else if (kind == ELLIPSE) {
|
||||
} else if (primitive == ELLIPSE) {
|
||||
g.ellipseMode(CORNER);
|
||||
g.ellipse(params[0], params[1], params[2], params[3]);
|
||||
|
||||
} else if (kind == ARC) {
|
||||
} else if (primitive == ARC) {
|
||||
g.ellipseMode(CORNER);
|
||||
g.arc(params[0], params[1], params[2], params[3], params[4], params[5]);
|
||||
|
||||
} else if (kind == BOX) {
|
||||
} else if (primitive == BOX) {
|
||||
if (params.length == 1) {
|
||||
g.box(params[0]);
|
||||
} else {
|
||||
g.box(params[0], params[1], params[2]);
|
||||
}
|
||||
|
||||
} else if (kind == SPHERE) {
|
||||
} else if (primitive == SPHERE) {
|
||||
g.sphere(params[0]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void drawGeometry(PGraphics g) {
|
||||
g.beginShape(kind);
|
||||
g.beginShape(primitive);
|
||||
if (style) {
|
||||
for (int i = 0; i < vertexCount; i++) {
|
||||
g.vertex(vertices[i]);
|
||||
@@ -608,12 +638,21 @@ public class PShape implements PConstants {
|
||||
return childCount;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param index the layer position of the shape to get
|
||||
*/
|
||||
public PShape getChild(int index) {
|
||||
return children[index];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extracts a child shape from a parent shape. Specify the name of the shape with the <b>target</b> parameter.
|
||||
* The shape is returned as a <b>PShape</b> object, or <b>null</b> is returned if there is an error.
|
||||
* @param target the name of the shape to get
|
||||
* @webref
|
||||
* @brief Returns a child element of a shape as a PShape object
|
||||
*/
|
||||
public PShape getChild(String target) {
|
||||
if (name != null && name.equals(target)) {
|
||||
return this;
|
||||
@@ -632,7 +671,7 @@ public class PShape implements PConstants {
|
||||
|
||||
/**
|
||||
* Same as getChild(name), except that it first walks all the way up the
|
||||
* hierarchy to the farthest parent, so that children can be found anywhere.
|
||||
* hierarchy to the eldest grandparent, so that children can be found anywhere.
|
||||
*/
|
||||
public PShape findChild(String target) {
|
||||
if (parent == null) {
|
||||
@@ -684,6 +723,114 @@ public class PShape implements PConstants {
|
||||
// }
|
||||
|
||||
|
||||
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
|
||||
|
||||
/** The shape type, one of GROUP, PRIMITIVE, PATH, or GEOMETRY. */
|
||||
public int getFamily() {
|
||||
return family;
|
||||
}
|
||||
|
||||
|
||||
public int getPrimitive() {
|
||||
return primitive;
|
||||
}
|
||||
|
||||
|
||||
public float[] getParams() {
|
||||
return getParams(null);
|
||||
}
|
||||
|
||||
|
||||
public float[] getParams(float[] target) {
|
||||
if (target == null || target.length != params.length) {
|
||||
target = new float[params.length];
|
||||
}
|
||||
PApplet.arrayCopy(params, target);
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
public float getParam(int index) {
|
||||
return params[index];
|
||||
}
|
||||
|
||||
|
||||
public int getVertexCount() {
|
||||
return vertexCount;
|
||||
}
|
||||
|
||||
|
||||
public float[] getVertex(int index) {
|
||||
if (index < 0 || index >= vertexCount) {
|
||||
String msg = "No vertex " + index + " for this shape, " +
|
||||
"only vertices 0 through " + (vertexCount-1) + ".";
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
return vertices[index];
|
||||
}
|
||||
|
||||
|
||||
public float getVertexX(int index) {
|
||||
return vertices[index][X];
|
||||
}
|
||||
|
||||
|
||||
public float getVertexY(int index) {
|
||||
return vertices[index][Y];
|
||||
}
|
||||
|
||||
|
||||
public float getVertexZ(int index) {
|
||||
return vertices[index][Z];
|
||||
}
|
||||
|
||||
|
||||
public int[] getVertexCodes() {
|
||||
if (vertexCodes.length != vertexCodeCount) {
|
||||
vertexCodes = PApplet.subset(vertexCodes, 0, vertexCodeCount);
|
||||
}
|
||||
return vertexCodes;
|
||||
}
|
||||
|
||||
|
||||
public int getVertexCodeCount() {
|
||||
return vertexCodeCount;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* One of VERTEX, BEZIER_VERTEX, CURVE_VERTEX, or BREAK.
|
||||
*/
|
||||
public int getVertexCode(int index) {
|
||||
return vertexCodes[index];
|
||||
}
|
||||
|
||||
|
||||
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
|
||||
|
||||
// http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
|
||||
public boolean contains(float x, float y) {
|
||||
if (family == PATH) {
|
||||
boolean c = false;
|
||||
for (int i = 0, j = vertexCount-1; i < vertexCount; j = i++) {
|
||||
if (((vertices[i][Y] > y) != (vertices[j][Y] > y)) &&
|
||||
(x <
|
||||
(vertices[j][X]-vertices[i][X]) *
|
||||
(y-vertices[i][Y]) /
|
||||
(vertices[j][1]-vertices[i][Y]) +
|
||||
vertices[i][X])) {
|
||||
c = !c;
|
||||
}
|
||||
}
|
||||
return c;
|
||||
} else {
|
||||
throw new IllegalArgumentException("The contains() method is only implemented for paths.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
|
||||
|
||||
@@ -692,58 +839,119 @@ public class PShape implements PConstants {
|
||||
// if matrix is null when one is called,
|
||||
// it is created and set to identity
|
||||
|
||||
|
||||
public void translate(float tx, float ty) {
|
||||
checkMatrix(2);
|
||||
matrix.translate(tx, ty);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specifies an amount to displace the shape. The <b>x</b> parameter specifies left/right translation, the <b>y</b> parameter specifies up/down translation, and the <b>z</b> parameter specifies translations toward/away from the screen. Subsequent calls to the method accumulates the effect. For example, calling <b>translate(50, 0)</b> and then <b>translate(20, 0)</b> is the same as <b>translate(70, 0)</b>. This transformation is applied directly to the shape, it's not refreshed each time <b>draw()</b> is run.
|
||||
* <br><br>Using this method with the <b>z</b> parameter requires using the P3D or OPENGL parameter in combination with size.
|
||||
* @webref
|
||||
* @param tx left/right translation
|
||||
* @param ty up/down translation
|
||||
* @param tz forward/back translation
|
||||
* @brief Displaces the shape
|
||||
*/
|
||||
public void translate(float tx, float ty, float tz) {
|
||||
checkMatrix(3);
|
||||
matrix.translate(tx, ty, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Rotates a shape around the x-axis the amount specified by the <b>angle</b> parameter. Angles should be specified in radians (values from 0 to TWO_PI) or converted to radians with the <b>radians()</b> method.
|
||||
* <br><br>Shapes are always rotated around the upper-left corner of their bounding box. Positive numbers rotate objects in a clockwise direction.
|
||||
* Subsequent calls to the method accumulates the effect. For example, calling <b>rotateX(HALF_PI)</b> and then <b>rotateX(HALF_PI)</b> is the same as <b>rotateX(PI)</b>.
|
||||
* This transformation is applied directly to the shape, it's not refreshed each time <b>draw()</b> is run.
|
||||
* <br><br>This method requires a 3D renderer. You need to pass P3D or OPENGL as a third parameter into the <b>size()</b> method as shown in the example above.
|
||||
* @param angle angle of rotation specified in radians
|
||||
* @webref
|
||||
* @brief Rotates the shape around the x-axis
|
||||
*/
|
||||
public void rotateX(float angle) {
|
||||
rotate(angle, 1, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Rotates a shape around the y-axis the amount specified by the <b>angle</b> parameter. Angles should be specified in radians (values from 0 to TWO_PI) or converted to radians with the <b>radians()</b> method.
|
||||
* <br><br>Shapes are always rotated around the upper-left corner of their bounding box. Positive numbers rotate objects in a clockwise direction.
|
||||
* Subsequent calls to the method accumulates the effect. For example, calling <b>rotateY(HALF_PI)</b> and then <b>rotateY(HALF_PI)</b> is the same as <b>rotateY(PI)</b>.
|
||||
* This transformation is applied directly to the shape, it's not refreshed each time <b>draw()</b> is run.
|
||||
* <br><br>This method requires a 3D renderer. You need to pass P3D or OPENGL as a third parameter into the <b>size()</b> method as shown in the example above.
|
||||
* @param angle angle of rotation specified in radians
|
||||
* @webref
|
||||
* @brief Rotates the shape around the y-axis
|
||||
*/
|
||||
public void rotateY(float angle) {
|
||||
rotate(angle, 0, 1, 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Rotates a shape around the z-axis the amount specified by the <b>angle</b> parameter. Angles should be specified in radians (values from 0 to TWO_PI) or converted to radians with the <b>radians()</b> method.
|
||||
* <br><br>Shapes are always rotated around the upper-left corner of their bounding box. Positive numbers rotate objects in a clockwise direction.
|
||||
* Subsequent calls to the method accumulates the effect. For example, calling <b>rotateZ(HALF_PI)</b> and then <b>rotateZ(HALF_PI)</b> is the same as <b>rotateZ(PI)</b>.
|
||||
* This transformation is applied directly to the shape, it's not refreshed each time <b>draw()</b> is run.
|
||||
* <br><br>This method requires a 3D renderer. You need to pass P3D or OPENGL as a third parameter into the <b>size()</b> method as shown in the example above.
|
||||
* @param angle angle of rotation specified in radians
|
||||
* @webref
|
||||
* @brief Rotates the shape around the z-axis
|
||||
*/
|
||||
public void rotateZ(float angle) {
|
||||
rotate(angle, 0, 0, 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Rotates a shape the amount specified by the <b>angle</b> parameter. Angles should be specified in radians (values from 0 to TWO_PI) or converted to radians with the <b>radians()</b> method.
|
||||
* <br><br>Shapes are always rotated around the upper-left corner of their bounding box. Positive numbers rotate objects in a clockwise direction.
|
||||
* Transformations apply to everything that happens after and subsequent calls to the method accumulates the effect.
|
||||
* For example, calling <b>rotate(HALF_PI)</b> and then <b>rotate(HALF_PI)</b> is the same as <b>rotate(PI)</b>.
|
||||
* This transformation is applied directly to the shape, it's not refreshed each time <b>draw()</b> is run.
|
||||
* @param angle angle of rotation specified in radians
|
||||
* @webref
|
||||
* @brief Rotates the shape
|
||||
*/
|
||||
public void rotate(float angle) {
|
||||
rotate(angle, 0, 0, 1);
|
||||
checkMatrix(2); // at least 2...
|
||||
matrix.rotate(angle);
|
||||
}
|
||||
|
||||
|
||||
public void rotate(float angle, float v0, float v1, float v2) {
|
||||
checkMatrix(3);
|
||||
matrix.rotate(angle, v0, v1, v2);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param s percentage to scale the object
|
||||
*/
|
||||
public void scale(float s) {
|
||||
checkMatrix(2); // at least 2...
|
||||
matrix.scale(s);
|
||||
}
|
||||
|
||||
|
||||
public void scale(float sx, float sy) {
|
||||
public void scale(float x, float y) {
|
||||
checkMatrix(2);
|
||||
matrix.scale(sx, sy);
|
||||
matrix.scale(x, y);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Increases or decreases the size of a shape by expanding and contracting vertices. Shapes always scale from the relative origin of their bounding box.
|
||||
* Scale values are specified as decimal percentages. For example, the method call <b>scale(2.0)</b> increases the dimension of a shape by 200%.
|
||||
* Subsequent calls to the method multiply the effect. For example, calling <b>scale(2.0)</b> and then <b>scale(1.5)</b> is the same as <b>scale(3.0)</b>.
|
||||
* This transformation is applied directly to the shape, it's not refreshed each time <b>draw()</b> is run.
|
||||
* <br><br>Using this fuction with the <b>z</b> parameter requires passing P3D or OPENGL into the size() parameter.
|
||||
* @param x percentage to scale the object in the x-axis
|
||||
* @param y percentage to scale the object in the y-axis
|
||||
* @param z percentage to scale the object in the z-axis
|
||||
* @webref
|
||||
* @brief Increases and decreases the size of a shape
|
||||
*/
|
||||
public void scale(float x, float y, float z) {
|
||||
checkMatrix(3);
|
||||
matrix.scale(x, y, z);
|
||||
|
||||
@@ -341,7 +341,8 @@ public class PShape3D extends PShape implements PConstants {
|
||||
return numVertices;
|
||||
}
|
||||
|
||||
public PVector getVertex(int idx) {
|
||||
// public PVector getVertex(int idx) {
|
||||
public float[] getVertex(int idx) {
|
||||
if (updateElement != VERTICES) {
|
||||
throw new RuntimeException("PShape3D: update mode is not set to VERTICES");
|
||||
}
|
||||
@@ -350,10 +351,11 @@ public class PShape3D extends PShape implements PConstants {
|
||||
float y = vertexArray[3 * idx + 1];
|
||||
float z = vertexArray[3 * idx + 2];
|
||||
|
||||
PVector res = new PVector(x, y, z);
|
||||
return res;
|
||||
// PVector res = new PVector(x, y, z);
|
||||
// return res;
|
||||
return new float[] { x, y, z };
|
||||
}
|
||||
|
||||
|
||||
|
||||
public float[] getVertexArray() {
|
||||
if (updateElement != VERTICES) {
|
||||
@@ -371,7 +373,7 @@ public class PShape3D extends PShape implements PConstants {
|
||||
PApplet.arrayCopy(vertexArray, firstUpd * 3, data, firstData * 3, length * 3);
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public ArrayList<PVector> getVertexArrayList() {
|
||||
if (updateElement != VERTICES) {
|
||||
@@ -381,7 +383,10 @@ public class PShape3D extends PShape implements PConstants {
|
||||
ArrayList<PVector> res;
|
||||
res = new ArrayList<PVector>();
|
||||
|
||||
for (int i = 0; i < numVertices; i++) res.add(getVertex(i));
|
||||
for (int i = 0; i < numVertices; i++) {
|
||||
float[] v = getVertex(i);
|
||||
res.add(new PVector(v[0], v[1], v[2]));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -207,7 +207,9 @@ public class PShapeSVG extends PShape {
|
||||
|
||||
|
||||
public PShapeSVG(PShapeSVG parent, XMLElement properties) {
|
||||
//super(GROUP);
|
||||
// Need to set this so that findChild() works.
|
||||
// Otherwise 'parent' is null until addChild() is called later.
|
||||
this.parent = parent;
|
||||
|
||||
if (parent == null) {
|
||||
// set values to their defaults according to the SVG spec
|
||||
@@ -257,10 +259,10 @@ public class PShapeSVG extends PShape {
|
||||
|
||||
element = properties;
|
||||
name = properties.getStringAttribute("id");
|
||||
// @#$(* adobe illustrator
|
||||
// @#$(* adobe illustrator mangles names of objects when re-saving
|
||||
if (name != null) {
|
||||
while (true) {
|
||||
String[] m = PApplet.match(name, "_x(.*)_");
|
||||
String[] m = PApplet.match(name, "_x([A-Za-z0-9]{2})_");
|
||||
if (m == null) break;
|
||||
char repair = (char) PApplet.unhex(m[1]);
|
||||
name = name.replace(m[0], "" + repair);
|
||||
@@ -354,8 +356,9 @@ public class PShapeSVG extends PShape {
|
||||
} else if (name.equals("linearGradient")) {
|
||||
return new LinearGradient(this, elem);
|
||||
|
||||
} else if (name.equals("text")) {
|
||||
PGraphics.showWarning("Text in SVG files is not currently supported, " +
|
||||
} else if (name.equals("text") || name.equals("font")) {
|
||||
PGraphics.showWarning("Text and fonts in SVG files " +
|
||||
"are not currently supported, " +
|
||||
"convert text to outlines instead.");
|
||||
|
||||
} else if (name.equals("filter")) {
|
||||
@@ -364,9 +367,15 @@ public class PShapeSVG extends PShape {
|
||||
} else if (name.equals("mask")) {
|
||||
PGraphics.showWarning("Masks are not supported.");
|
||||
|
||||
} else if (name.equals("pattern")) {
|
||||
PGraphics.showWarning("Patterns are not supported.");
|
||||
|
||||
} 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
|
||||
|
||||
|
||||
} else {
|
||||
PGraphics.showWarning("Ignoring <" + name + "> tag.");
|
||||
}
|
||||
@@ -375,18 +384,14 @@ public class PShapeSVG extends PShape {
|
||||
|
||||
|
||||
protected void parseLine() {
|
||||
kind = LINE;
|
||||
primitive = LINE;
|
||||
family = PRIMITIVE;
|
||||
params = new float[] {
|
||||
element.getFloatAttribute("x1"),
|
||||
element.getFloatAttribute("y1"),
|
||||
element.getFloatAttribute("x2"),
|
||||
element.getFloatAttribute("y2"),
|
||||
getFloatWithUnit(element, "x1"),
|
||||
getFloatWithUnit(element, "y1"),
|
||||
getFloatWithUnit(element, "x2"),
|
||||
getFloatWithUnit(element, "y2")
|
||||
};
|
||||
// x = params[0];
|
||||
// y = params[1];
|
||||
// width = params[2];
|
||||
// height = params[3];
|
||||
}
|
||||
|
||||
|
||||
@@ -395,19 +400,19 @@ public class PShapeSVG extends PShape {
|
||||
* @param circle true if this is a circle and not an ellipse
|
||||
*/
|
||||
protected void parseEllipse(boolean circle) {
|
||||
kind = ELLIPSE;
|
||||
primitive = ELLIPSE;
|
||||
family = PRIMITIVE;
|
||||
params = new float[4];
|
||||
|
||||
params[0] = element.getFloatAttribute("cx");
|
||||
params[1] = element.getFloatAttribute("cy");
|
||||
params[0] = getFloatWithUnit(element, "cx");
|
||||
params[1] = getFloatWithUnit(element, "cy");
|
||||
|
||||
float rx, ry;
|
||||
if (circle) {
|
||||
rx = ry = element.getFloatAttribute("r");
|
||||
rx = ry = getFloatWithUnit(element, "r");
|
||||
} else {
|
||||
rx = element.getFloatAttribute("rx");
|
||||
ry = element.getFloatAttribute("ry");
|
||||
rx = getFloatWithUnit(element, "rx");
|
||||
ry = getFloatWithUnit(element, "ry");
|
||||
}
|
||||
params[0] -= rx;
|
||||
params[1] -= ry;
|
||||
@@ -418,13 +423,13 @@ public class PShapeSVG extends PShape {
|
||||
|
||||
|
||||
protected void parseRect() {
|
||||
kind = RECT;
|
||||
primitive = RECT;
|
||||
family = PRIMITIVE;
|
||||
params = new float[] {
|
||||
element.getFloatAttribute("x"),
|
||||
element.getFloatAttribute("y"),
|
||||
element.getFloatAttribute("width"),
|
||||
element.getFloatAttribute("height"),
|
||||
getFloatWithUnit(element, "x"),
|
||||
getFloatWithUnit(element, "y"),
|
||||
getFloatWithUnit(element, "width"),
|
||||
getFloatWithUnit(element, "height")
|
||||
};
|
||||
}
|
||||
|
||||
@@ -453,7 +458,7 @@ public class PShapeSVG extends PShape {
|
||||
|
||||
protected void parsePath() {
|
||||
family = PATH;
|
||||
kind = 0;
|
||||
primitive = 0;
|
||||
|
||||
String pathData = element.getStringAttribute("d");
|
||||
if (pathData == null) return;
|
||||
@@ -485,7 +490,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,6 +514,7 @@ public class PShapeSVG extends PShape {
|
||||
float cx = 0;
|
||||
float cy = 0;
|
||||
int i = 0;
|
||||
|
||||
char implicitCommand = '\0';
|
||||
|
||||
while (i < pathDataKeys.length) {
|
||||
@@ -651,7 +657,7 @@ public class PShapeSVG extends PShape {
|
||||
float ctrlY = PApplet.parseFloat(pathDataKeys[i + 2]);
|
||||
float endX = PApplet.parseFloat(pathDataKeys[i + 3]);
|
||||
float endY = PApplet.parseFloat(pathDataKeys[i + 4]);
|
||||
parsePathCurveto(ctrlX, ctrlY, ctrlX, ctrlY, endX, endY);
|
||||
parsePathQuadto(cx, cy, ctrlX, ctrlY, endX, endY);
|
||||
cx = endX;
|
||||
cy = endY;
|
||||
i += 5;
|
||||
@@ -664,7 +670,7 @@ public class PShapeSVG extends PShape {
|
||||
float ctrlY = cy + PApplet.parseFloat(pathDataKeys[i + 2]);
|
||||
float endX = cx + PApplet.parseFloat(pathDataKeys[i + 3]);
|
||||
float endY = cy + PApplet.parseFloat(pathDataKeys[i + 4]);
|
||||
parsePathCurveto(ctrlX, ctrlY, ctrlX, ctrlY, endX, endY);
|
||||
parsePathQuadto(cx, cy, ctrlX, ctrlY, endX, endY);
|
||||
cx = endX;
|
||||
cy = endY;
|
||||
i += 5;
|
||||
@@ -686,7 +692,7 @@ public class PShapeSVG extends PShape {
|
||||
float ctrlY = py + (py - ppy);
|
||||
float endX = PApplet.parseFloat(pathDataKeys[i + 1]);
|
||||
float endY = PApplet.parseFloat(pathDataKeys[i + 2]);
|
||||
parsePathCurveto(ctrlX, ctrlY, ctrlX, ctrlY, endX, endY);
|
||||
parsePathQuadto(cx, cy, ctrlX, ctrlY, endX, endY);
|
||||
cx = endX;
|
||||
cy = endY;
|
||||
i += 3;
|
||||
@@ -703,7 +709,7 @@ public class PShapeSVG extends PShape {
|
||||
float ctrlY = py + (py - ppy);
|
||||
float endX = cx + PApplet.parseFloat(pathDataKeys[i + 1]);
|
||||
float endY = cy + PApplet.parseFloat(pathDataKeys[i + 2]);
|
||||
parsePathCurveto(ctrlX, ctrlY, ctrlX, ctrlY, endX, endY);
|
||||
parsePathQuadto(cx, cy, ctrlX, ctrlY, endX, endY);
|
||||
cx = endX;
|
||||
cy = endY;
|
||||
i += 3;
|
||||
@@ -788,6 +794,16 @@ public class PShapeSVG extends PShape {
|
||||
parsePathVertex(x3, y3);
|
||||
}
|
||||
|
||||
private void parsePathQuadto(float x1, float y1,
|
||||
float cx, float cy,
|
||||
float x2, float y2) {
|
||||
parsePathCode(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);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse the specified SVG matrix into a PMatrix2D. Note that PMatrix2D
|
||||
@@ -854,7 +870,12 @@ public class PShapeSVG extends PShape {
|
||||
|
||||
if (properties.hasAttribute("stroke")) {
|
||||
String strokeText = properties.getStringAttribute("stroke");
|
||||
setStroke(strokeText);
|
||||
setColor(strokeText, false);
|
||||
}
|
||||
|
||||
if (properties.hasAttribute("stroke-opacity")) {
|
||||
String strokeOpacityText = properties.getStringAttribute("stroke-opacity");
|
||||
setStrokeOpacity(strokeOpacityText);
|
||||
}
|
||||
|
||||
if (properties.hasAttribute("stroke-width")) {
|
||||
@@ -873,15 +894,18 @@ public class PShapeSVG extends PShape {
|
||||
setStrokeCap(linecap);
|
||||
}
|
||||
|
||||
|
||||
// fill defaults to black (though stroke defaults to "none")
|
||||
// http://www.w3.org/TR/SVG/painting.html#FillProperties
|
||||
if (properties.hasAttribute("fill")) {
|
||||
String fillText = properties.getStringAttribute("fill");
|
||||
setFill(fillText);
|
||||
|
||||
setColor(fillText, true);
|
||||
}
|
||||
|
||||
if (properties.hasAttribute("fill-opacity")) {
|
||||
String fillOpacityText = properties.getStringAttribute("fill-opacity");
|
||||
setFillOpacity(fillOpacityText);
|
||||
}
|
||||
|
||||
if (properties.hasAttribute("style")) {
|
||||
String styleText = properties.getStringAttribute("style");
|
||||
String[] styleTokens = PApplet.splitTokens(styleText, ";");
|
||||
@@ -894,13 +918,13 @@ public class PShapeSVG extends PShape {
|
||||
tokens[0] = PApplet.trim(tokens[0]);
|
||||
|
||||
if (tokens[0].equals("fill")) {
|
||||
setFill(tokens[1]);
|
||||
setColor(tokens[1], true);
|
||||
|
||||
} else if(tokens[0].equals("fill-opacity")) {
|
||||
setFillOpacity(tokens[1]);
|
||||
|
||||
} else if(tokens[0].equals("stroke")) {
|
||||
setStroke(tokens[1]);
|
||||
setColor(tokens[1], false);
|
||||
|
||||
} else if(tokens[0].equals("stroke-width")) {
|
||||
setStrokeWeight(tokens[1]);
|
||||
@@ -924,43 +948,24 @@ 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 = PApplet.parseFloat(lineweight);
|
||||
strokeWeight = parseUnitSize(lineweight);
|
||||
}
|
||||
|
||||
|
||||
void setStrokeOpacity(String opacityText) {
|
||||
strokeOpacity = PApplet.parseFloat(opacityText);
|
||||
strokeColor = ((int) (strokeOpacity * 255)) << 24 | strokeColor & 0xFFFFFF;
|
||||
}
|
||||
|
||||
void setStroke(String strokeText) {
|
||||
int opacityMask = strokeColor & 0xFF000000;
|
||||
if (strokeText.equals("none")) {
|
||||
stroke = false;
|
||||
} else if (strokeText.startsWith("#")) {
|
||||
stroke = true;
|
||||
strokeColor = opacityMask |
|
||||
(Integer.parseInt(strokeText.substring(1), 16)) & 0xFFFFFF;
|
||||
} else if (strokeText.startsWith("rgb")) {
|
||||
stroke = true;
|
||||
strokeColor = opacityMask | parseRGB(strokeText);
|
||||
} else if (strokeText.startsWith("url(#")) {
|
||||
strokeName = strokeText.substring(5, strokeText.length() - 1);
|
||||
Object strokeObject = findChild(strokeName);
|
||||
if (strokeObject instanceof Gradient) {
|
||||
strokeGradient = (Gradient) strokeObject;
|
||||
strokeGradientPaint = calcGradientPaint(strokeGradient); //, opacity);
|
||||
} else {
|
||||
System.err.println("url " + strokeName + " refers to unexpected data");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setStrokeJoin(String linejoin) {
|
||||
if (linejoin.equals("inherit")) {
|
||||
@@ -977,6 +982,7 @@ public class PShapeSVG extends PShape {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setStrokeCap(String linecap) {
|
||||
if (linecap.equals("inherit")) {
|
||||
// do nothing, will inherit automatically
|
||||
@@ -991,41 +997,67 @@ public class PShapeSVG extends PShape {
|
||||
strokeCap = PConstants.PROJECT;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setFillOpacity(String opacityText) {
|
||||
fillOpacity = PApplet.parseFloat(opacityText);
|
||||
fillColor = ((int) (fillOpacity * 255)) << 24 | fillColor & 0xFFFFFF;
|
||||
}
|
||||
|
||||
|
||||
void setFill(String fillText) {
|
||||
void setColor(String colorText, boolean isFill) {
|
||||
int opacityMask = fillColor & 0xFF000000;
|
||||
if (fillText.equals("none")) {
|
||||
fill = false;
|
||||
} else if (fillText.startsWith("#")) {
|
||||
fill = true;
|
||||
fillColor = opacityMask |
|
||||
(Integer.parseInt(fillText.substring(1), 16)) & 0xFFFFFF;
|
||||
boolean visible = true;
|
||||
int color = 0;
|
||||
String name = "";
|
||||
Gradient gradient = null;
|
||||
Shader paint = null;
|
||||
if (colorText.equals("none")) {
|
||||
visible = false;
|
||||
} else if (colorText.equals("black")) {
|
||||
color = opacityMask;
|
||||
} else if (colorText.equals("white")) {
|
||||
color = opacityMask | 0xFFFFFF;
|
||||
} else if (colorText.startsWith("#")) {
|
||||
if (colorText.length() == 4) {
|
||||
// Short form: #ABC, transform to long form #AABBCC
|
||||
colorText = colorText.replaceAll("^#(.)(.)(.)$", "#$1$1$2$2$3$3");
|
||||
}
|
||||
color = opacityMask |
|
||||
(Integer.parseInt(colorText.substring(1), 16)) & 0xFFFFFF;
|
||||
//System.out.println("hex for fill is " + PApplet.hex(fillColor));
|
||||
} else if (fillText.startsWith("rgb")) {
|
||||
fill = true;
|
||||
fillColor = opacityMask | parseRGB(fillText);
|
||||
} else if (fillText.startsWith("url(#")) {
|
||||
fillName = fillText.substring(5, fillText.length() - 1);
|
||||
//PApplet.println("looking for " + fillName);
|
||||
Object fillObject = findChild(fillName);
|
||||
} else if (colorText.startsWith("rgb")) {
|
||||
color = opacityMask | parseRGB(colorText);
|
||||
} else if (colorText.startsWith("url(#")) {
|
||||
name = colorText.substring(5, colorText.length() - 1);
|
||||
// PApplet.println("looking for " + name);
|
||||
Object object = findChild(name);
|
||||
//PApplet.println("found " + fillObject);
|
||||
if (fillObject instanceof Gradient) {
|
||||
fill = true;
|
||||
fillGradient = (Gradient) fillObject;
|
||||
fillGradientPaint = calcGradientPaint(fillGradient); //, opacity);
|
||||
if (object instanceof Gradient) {
|
||||
gradient = (Gradient) object;
|
||||
paint = calcGradientPaint(gradient); //, opacity);
|
||||
//PApplet.println("got filla " + fillObject);
|
||||
} else {
|
||||
System.err.println("url " + fillName + " refers to unexpected data");
|
||||
// visible = false;
|
||||
System.err.println("url " + name + " refers to unexpected data: " + object);
|
||||
}
|
||||
}
|
||||
if (isFill) {
|
||||
fill = visible;
|
||||
fillColor = color;
|
||||
fillName = name;
|
||||
fillGradient = gradient;
|
||||
fillGradientPaint = paint;
|
||||
} else {
|
||||
stroke = visible;
|
||||
strokeColor = color;
|
||||
strokeName = name;
|
||||
strokeGradient = gradient;
|
||||
strokeGradientPaint = paint;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static protected int parseRGB(String what) {
|
||||
int leftParen = what.indexOf('(') + 1;
|
||||
int rightParen = what.indexOf(')');
|
||||
@@ -1046,6 +1078,19 @@ public class PShapeSVG extends PShape {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @return unit-parsed version of the data
|
||||
*/
|
||||
static protected float getFloatWithUnit(XMLElement element, String attribute) {
|
||||
String val = element.getStringAttribute(attribute);
|
||||
return (val == null) ? 0 : parseUnitSize(val);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse a size that may have a suffix for its units.
|
||||
* Ignoring cases where this could also be a percentage.
|
||||
@@ -1079,85 +1124,6 @@ public class PShapeSVG extends PShape {
|
||||
}
|
||||
|
||||
|
||||
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
|
||||
|
||||
// these are a set of hacks so that gradients can be hacked into Java 2D.
|
||||
|
||||
/*
|
||||
protected Paint getGradient(String name, float cx, float cy, float r) {
|
||||
BaseObject obj = (BaseObject) findChild(name);
|
||||
|
||||
if (obj != null) {
|
||||
if (obj.fillGradient != null) {
|
||||
return obj.calcGradientPaint(obj.fillGradient, cx, cy, r);
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("No gradient found for shape " + name);
|
||||
}
|
||||
|
||||
|
||||
protected Paint getGradient(String name, float x1, float y1, float x2, float y2) {
|
||||
BaseObject obj = (BaseObject) findChild(name);
|
||||
|
||||
if (obj != null) {
|
||||
if (obj.fillGradient != null) {
|
||||
return obj.calcGradientPaint(obj.fillGradient, x1, y1, x2, y2);
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("No gradient found for shape " + name);
|
||||
}
|
||||
|
||||
|
||||
protected void strokeGradient(PGraphics g, String name, float x, float y, float r) {
|
||||
Paint paint = getGradient(name, x, y, r);
|
||||
|
||||
if (g instanceof PGraphicsJava2D) {
|
||||
PGraphicsJava2D p2d = (PGraphicsJava2D) g;
|
||||
|
||||
p2d.strokeGradient = true;
|
||||
p2d.strokeGradientObject = paint;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void strokeGradient(PGraphics g, String name, float x1, float y1, float x2, float y2) {
|
||||
Paint paint = getGradient(name, x1, y1, x2, y2);
|
||||
|
||||
if (g instanceof PGraphicsJava2D) {
|
||||
PGraphicsJava2D p2d = (PGraphicsJava2D) g;
|
||||
|
||||
p2d.strokeGradient = true;
|
||||
p2d.strokeGradientObject = paint;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void fillGradient(PGraphics g, String name, float x, float y, float r) {
|
||||
Paint paint = getGradient(name, x, y, r);
|
||||
|
||||
if (g instanceof PGraphicsJava2D) {
|
||||
PGraphicsJava2D p2d = (PGraphicsJava2D) g;
|
||||
|
||||
p2d.fillGradient = true;
|
||||
p2d.fillGradientObject = paint;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void fillGradient(PGraphics g, String name, float x1, float y1, float x2, float y2) {
|
||||
Paint paint = getGradient(name, x1, y1, x2, y2);
|
||||
|
||||
if (g instanceof PGraphicsJava2D) {
|
||||
PGraphicsJava2D p2d = (PGraphicsJava2D) g;
|
||||
|
||||
p2d.fillGradient = true;
|
||||
p2d.fillGradientObject = paint;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
|
||||
|
||||
@@ -1180,7 +1146,13 @@ public class PShapeSVG extends PShape {
|
||||
XMLElement elem = elements[i];
|
||||
String name = elem.getName();
|
||||
if (name.equals("stop")) {
|
||||
offset[count] = elem.getFloatAttribute("offset");
|
||||
String offsetAttr = elem.getStringAttribute("offset");
|
||||
float div = 1.0f;
|
||||
if (offsetAttr.endsWith("%")) {
|
||||
div = 100.0f;
|
||||
offsetAttr = offsetAttr.substring(0, offsetAttr.length() - 1);
|
||||
}
|
||||
offset[count] = PApplet.parseFloat(offsetAttr) / div;
|
||||
String style = elem.getStringAttribute("style");
|
||||
HashMap<String, String> styles = parseStyleAttributes(style);
|
||||
|
||||
@@ -1206,10 +1178,10 @@ public class PShapeSVG extends PShape {
|
||||
public LinearGradient(PShapeSVG parent, XMLElement properties) {
|
||||
super(parent, properties);
|
||||
|
||||
this.x1 = properties.getFloatAttribute("x1");
|
||||
this.y1 = properties.getFloatAttribute("y1");
|
||||
this.x2 = properties.getFloatAttribute("x2");
|
||||
this.y2 = properties.getFloatAttribute("y2");
|
||||
this.x1 = getFloatWithUnit(properties, "x1");
|
||||
this.y1 = getFloatWithUnit(properties, "y1");
|
||||
this.x2 = getFloatWithUnit(properties, "x2");
|
||||
this.y2 = getFloatWithUnit(properties, "y2");
|
||||
|
||||
String transformStr =
|
||||
properties.getStringAttribute("gradientTransform");
|
||||
@@ -1250,9 +1222,9 @@ public class PShapeSVG extends PShape {
|
||||
public RadialGradient(PShapeSVG parent, XMLElement properties) {
|
||||
super(parent, properties);
|
||||
|
||||
this.cx = properties.getFloatAttribute("cx");
|
||||
this.cy = properties.getFloatAttribute("cy");
|
||||
this.r = properties.getFloatAttribute("r");
|
||||
this.cx = getFloatWithUnit(properties, "cx");
|
||||
this.cy = getFloatWithUnit(properties, "cy");
|
||||
this.r = getFloatWithUnit(properties, "r");
|
||||
|
||||
String transformStr =
|
||||
properties.getStringAttribute("gradientTransform");
|
||||
@@ -1589,7 +1561,7 @@ public class PShapeSVG extends PShape {
|
||||
* beneath them can be used here.
|
||||
* <PRE>
|
||||
* // This code grabs "Layer 3" and the shapes beneath it.
|
||||
* SVG layer3 = svg.getChild("Layer 3");
|
||||
* PShape layer3 = svg.getChild("Layer 3");
|
||||
* </PRE>
|
||||
*/
|
||||
public PShape getChild(String name) {
|
||||
|
||||
Reference in New Issue
Block a user