diff --git a/core/src/processing/core/PShapeSVG.java b/core/src/processing/core/PShapeSVG.java
index e85389f02..19731769f 100644
--- a/core/src/processing/core/PShapeSVG.java
+++ b/core/src/processing/core/PShapeSVG.java
@@ -514,53 +514,86 @@ public class PShapeSVG extends PShape {
char[] pathDataChars = pathData.toCharArray();
StringBuilder pathBuffer = new StringBuilder();
- boolean lastSeparate = false;
- boolean isOnDecimal = false;
+
+ /*
+ * The state of the lexer:
+ * -1: just after the command (i.e. a single alphabet)
+ * 0: neutral state
+ * 1: on a digit sequence for integer representation
+ * 2: on a decimal
+ * 3: on a digit or a sign in exponent in scientific notation, e.g. 3.14e-2)
+ * 4: on a digit sequence in exponent
+ */
+ int lexState = 0;
for (int i = 0; i < pathDataChars.length; i++) {
char c = pathDataChars[i];
- boolean separate = false;
- if (c == 'M' || c == 'm' ||
- c == 'L' || c == 'l' ||
- c == 'H' || c == 'h' ||
- c == 'V' || c == 'v' ||
- c == 'C' || c == 'c' || // beziers
- 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;
- if (i != 0) {
- pathBuffer.append("|");
- }
- }
- if (c == 'Z' || c == 'z') {
- separate = false;
- }
- if (c == '.' && !isOnDecimal) {
- isOnDecimal = true;
- }
- else if (isOnDecimal && (c < '0' || c > '9')) {
+ // Put a separator after a command.
+ if (lexState == -1) {
pathBuffer.append("|");
- isOnDecimal = c == '.';
+ lexState = 0;
}
- if (c == '-' && !lastSeparate) {
- // allow for 'e' notation in numbers, e.g. 2.10e-9
- // https://download.processing.org/bugzilla/1408.html
- if (i == 0 || pathDataChars[i-1] != 'e') {
+
+ if (c >= '0' && c <= '9') {
+ if (lexState == 0 || lexState == 3) {
+ // If it is a head of a number representation, enter the 'inside' of the digit sequence.
+ ++lexState;
+ }
+ pathBuffer.append(c);
+ continue;
+ }
+
+ if (c == '-') {
+ if (lexState == 0) {
+ // In neutral state, enter 'digit sequence'.
+ lexState = 1;
+ }
+ else if (lexState == 3) {
+ // In the begining of an exponent, enter 'exponent digit sequence'.
+ lexState = 4;
+ }
+ else {
+ // Otherwise, begin a new number representation.
+ pathBuffer.append("|");
+ lexState = 1;
+ }
+ pathBuffer.append("-");
+ continue;
+ }
+
+ if (c == '.') {
+ if (lexState >= 2) {
+ // Begin a new decimal number unless it is in a neutral state or after a digit sequence
pathBuffer.append("|");
}
+ pathBuffer.append(".");
+ lexState = 2;
+ continue;
}
+
+ if (c == 'e' || c == 'E') {
+ // Found 'e' or 'E', enter the 'exponent' state immediately.
+ pathBuffer.append("e");
+ lexState = 3;
+ continue;
+ }
+
+ // The following are executed for non-numeral elements
+
+ if (lexState != 0) {
+ pathBuffer.append("|");
+ lexState = 0;
+ }
+
if (c != ',') {
- pathBuffer.append(c); //"" + pathDataBuffer.charAt(i));
+ pathBuffer.append(c);
}
- if (separate && c != ',' && c != '-') {
- pathBuffer.append("|");
+
+ if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) {
+ // Every alphabet character except for 'e' and 'E' are considered as a command.
+ lexState = -1;
}
- lastSeparate = separate;
}
// use whitespace constant to get rid of extra spaces and CR or LF
diff --git a/core/test/processing/core/PShapeSVGTest.java b/core/test/processing/core/PShapeSVGTest.java
index 2b9ddd96c..a38c3ae1b 100644
--- a/core/test/processing/core/PShapeSVGTest.java
+++ b/core/test/processing/core/PShapeSVGTest.java
@@ -10,23 +10,47 @@ import java.awt.*;
public class PShapeSVGTest {
- private static final String TEST_CONTENT = "";
+ private static final String[] TEST_CONTENT = {
+ "",
+ ""
+ };
+ private static final int[] TEST_NVERTEX = {2, 8};
+ private static final String TEST_EXPONENT =
+ "";
@Test
public void testDecimals() {
try {
- XML xml = XML.parse(TEST_CONTENT);
- PShapeSVG shape = new PShapeSVG(xml);
- PShape[] children = shape.getChildren();
- Assert.assertEquals(1, children.length);
- PShape[] grandchildren = children[0].getChildren();
- Assert.assertEquals(1, grandchildren.length);
- Assert.assertEquals(0, grandchildren[0].getChildCount());
- Assert.assertEquals(2, grandchildren[0].getVertexCount());
+ for (int i = 0; i < TEST_CONTENT.length; ++i) {
+ XML xml = XML.parse(TEST_CONTENT[i]);
+ PShapeSVG shape = new PShapeSVG(xml);
+ PShape[] children = shape.getChildren();
+ Assert.assertEquals(1, children.length);
+ PShape[] grandchildren = children[0].getChildren();
+ Assert.assertEquals(1, grandchildren.length);
+ Assert.assertEquals(0, grandchildren[0].getChildCount());
+ Assert.assertEquals(TEST_NVERTEX[i], grandchildren[0].getVertexCount());
+ }
}
catch (Exception e) {
Assert.fail("Encountered exception " + e);
}
}
+ @Test
+ public void testExponent() {
+ try {
+ XML xml = XML.parse(TEST_EXPONENT);
+ PShapeSVG shape = new PShapeSVG(xml);
+ PShape[] children = shape.getChildren();
+ Assert.assertEquals(1, children.length);
+ PShape[] grandchildren = children[0].getChildren();
+ Assert.assertEquals(1, grandchildren.length);
+ Assert.assertEquals(0, grandchildren[0].getChildCount());
+ Assert.assertEquals(8, grandchildren[0].getVertexCount());
+ }
+ catch (Exception e) {
+ Assert.fail("Encountered exception " + e);
+ }
+ }
}