propane 3.5.0-java → 3.6.0-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.mvn/extensions.xml +1 -1
  3. data/.mvn/wrapper/MavenWrapperDownloader.java +1 -1
  4. data/.mvn/wrapper/maven-wrapper.properties +2 -2
  5. data/.travis.yml +1 -1
  6. data/CHANGELOG.md +3 -1
  7. data/README.md +5 -13
  8. data/Rakefile +1 -1
  9. data/lib/propane.rb +2 -1
  10. data/lib/propane/helper_methods.rb +0 -1
  11. data/lib/propane/runner.rb +2 -0
  12. data/lib/propane/version.rb +1 -1
  13. data/pom.rb +43 -43
  14. data/pom.xml +4 -4
  15. data/propane.gemspec +4 -3
  16. data/src/main/java/japplemenubar/JAppleMenuBar.java +3 -3
  17. data/src/main/java/processing/awt/PGraphicsJava2D.java +8 -17
  18. data/src/main/java/processing/awt/PImageAWT.java +123 -6
  19. data/src/main/java/processing/awt/PShapeJava2D.java +1 -0
  20. data/src/main/java/processing/awt/PSurfaceAWT.java +9 -7
  21. data/src/main/java/processing/awt/ShimAWT.java +2 -1
  22. data/src/main/java/processing/core/PApplet.java +4605 -6014
  23. data/src/main/java/processing/core/PConstants.java +5 -5
  24. data/src/main/java/processing/core/PFont.java +5 -17
  25. data/src/main/java/processing/core/PGraphics.java +308 -320
  26. data/src/main/java/processing/core/PImage.java +1440 -1537
  27. data/src/main/java/processing/core/PMatrix2D.java +24 -7
  28. data/src/main/java/processing/core/PMatrix3D.java +12 -5
  29. data/src/main/java/processing/core/PShape.java +155 -173
  30. data/src/main/java/processing/core/PShapeOBJ.java +2 -0
  31. data/src/main/java/processing/core/PShapeSVG.java +632 -611
  32. data/src/main/java/processing/core/PSurface.java +15 -10
  33. data/src/main/java/processing/core/PSurfaceNone.java +8 -4
  34. data/src/main/java/processing/core/PVector.java +35 -28
  35. data/src/main/java/processing/data/Table.java +20 -20
  36. data/src/main/java/processing/data/XML.java +1 -1
  37. data/src/main/java/processing/event/Event.java +1 -1
  38. data/src/main/java/processing/event/MouseEvent.java +7 -6
  39. data/src/main/java/processing/javafx/PGraphicsFX2D.java +20 -345
  40. data/src/main/java/processing/javafx/PSurfaceFX.java +127 -125
  41. data/src/main/java/processing/opengl/FrameBuffer.java +2 -4
  42. data/src/main/java/processing/opengl/LinePath.java +4 -0
  43. data/src/main/java/processing/opengl/LineStroker.java +2 -6
  44. data/src/main/java/processing/opengl/PGL.java +72 -45
  45. data/src/main/java/processing/opengl/PGraphicsOpenGL.java +106 -60
  46. data/src/main/java/processing/opengl/PJOGL.java +15 -3
  47. data/src/main/java/processing/opengl/PShader.java +26 -47
  48. data/src/main/java/processing/opengl/PShapeOpenGL.java +1041 -1001
  49. data/src/main/java/processing/opengl/PSurfaceJOGL.java +211 -208
  50. data/src/main/java/processing/opengl/Texture.java +7 -4
  51. data/src/main/java/processing/opengl/VertexBuffer.java +2 -2
  52. data/vendors/Rakefile +22 -33
  53. metadata +38 -18
@@ -23,6 +23,8 @@ public class PShapeOBJ extends PShape {
23
23
 
24
24
  /**
25
25
  * Initializes a new OBJ Object with the given filename.
26
+ * @param parent
27
+ * @param filename
26
28
  */
27
29
  public PShapeOBJ(PApplet parent, String filename) {
28
30
  this(parent, parent.createReader(filename), getBasePath(parent, filename));
@@ -1,6 +1,6 @@
1
1
  /* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
2
2
 
3
- /*
3
+ /*
4
4
  Part of the Processing project - http://processing.org
5
5
 
6
6
  Copyright (c) 2012-15 The Processing Foundation
@@ -20,7 +20,8 @@
20
20
  Public License along with this library; if not, write to the
21
21
  Free Software Foundation, Inc., 59 Temple Place, Suite 330,
22
22
  Boston, MA 02111-1307 USA
23
- */
23
+ */
24
+
24
25
  package processing.core;
25
26
 
26
27
  import static java.awt.Font.BOLD;
@@ -37,45 +38,44 @@ import java.util.HashMap;
37
38
  import java.util.regex.Matcher;
38
39
  import java.util.regex.Pattern;
39
40
 
41
+
40
42
  /**
41
- * This class is not part of the Processing API and should not be used directly.
42
- * Instead, use loadShape() and methods like it, which will make use of this
43
- * class. Using this class directly will cause your code to break when combined
44
- * with future versions of Processing.
43
+ * This class is not part of the Processing API and should not be used
44
+ * directly. Instead, use loadShape() and methods like it, which will make
45
+ * use of this class. Using this class directly will cause your code to break
46
+ * when combined with future versions of Processing.
45
47
  * <p>
46
- * SVG stands for Scalable Vector Graphics, a portable graphics format. It is a
47
- * vector format so it allows for "infinite" resolution and relatively small
48
- * file sizes. Most modern media software can view SVG files, including Adobe
49
- * products, Firefox, etc. Illustrator and Inkscape can edit SVG files. View the
50
- * SVG specification <a href="http://www.w3.org/TR/SVG">here</a>.
48
+ * SVG stands for Scalable Vector Graphics, a portable graphics format.
49
+ * It is a vector format so it allows for "infinite" resolution and relatively
50
+ * small file sizes. Most modern media software can view SVG files, including
51
+ * Adobe products, Firefox, etc. Illustrator and Inkscape can edit SVG files.
52
+ * View the SVG specification <A HREF="http://www.w3.org/TR/SVG">here</A>.
51
53
  * <p>
52
- * We have no intention of turning this into a full-featured SVG library. The
53
- * goal of this project is a basic shape importer that originally was small
54
+ * We have no intention of turning this into a full-featured SVG library.
55
+ * The goal of this project is a basic shape importer that originally was small
54
56
  * enough to be included with applets, meaning that its download size should be
55
57
  * in the neighborhood of 25-30 Kb. Though we're far less limited nowadays on
56
58
  * size constraints, we remain extremely limited in terms of time, and do not
57
59
  * have volunteers who are available to maintain a larger SVG library.
58
60
  * <p>
59
61
  * For more sophisticated import/export, consider the
60
- * <a href="http://xmlgraphics.apache.org/batik/">Batik</a>
62
+ * <A HREF="http://xmlgraphics.apache.org/batik/">Batik</A>
61
63
  * library from the Apache Software Foundation.
62
64
  * <p>
63
- * Batik is used in the SVG Export library in Processing 3, however using it for
64
- * full SVG import is still a considerable amount of work. Wiring it to Java2D
65
- * wouldn't be too bad, but using it with OpenGL, JavaFX, and features like
66
- * begin/endRecord() and begin/endRaw() would be considerable effort.
65
+ * Batik is used in the SVG Export library in Processing 3, however using it
66
+ * for full SVG import is still a considerable amount of work. Wiring it to
67
+ * Java2D wouldn't be too bad, but using it with OpenGL, JavaFX, and features
68
+ * like begin/endRecord() and begin/endRaw() would be considerable effort.
67
69
  * <p>
68
- * Future improvements to this library may focus on this properly supporting a
69
- * specific subset of SVG, for instance the simpler SVG profiles known as
70
- * <a href="http://www.w3.org/TR/SVGMobile/">SVG Tiny or Basic</a>, although we
71
- * still would not support the interactivity options.
70
+ * Future improvements to this library may focus on this properly supporting
71
+ * a specific subset of SVG, for instance the simpler SVG profiles known as
72
+ * <A HREF="http://www.w3.org/TR/SVGMobile/">SVG Tiny or Basic</A>,
73
+ * although we still would not support the interactivity options.
72
74
  *
73
- * <p>
74
- * <hr noshade>
75
- * <p>
75
+ * <p> <hr noshade> <p>
76
76
  *
77
- * A minimal example program using SVG: (assuming a working moo.svg is in your
78
- * data folder)
77
+ * A minimal example program using SVG:
78
+ * (assuming a working moo.svg is in your data folder)
79
79
  *
80
80
  * <PRE>
81
81
  * PShape moo;
@@ -91,7 +91,6 @@ import java.util.regex.Pattern;
91
91
  * </PRE>
92
92
  */
93
93
  public class PShapeSVG extends PShape {
94
-
95
94
  XML element;
96
95
 
97
96
  /// Values between 0 and 1.
@@ -99,19 +98,13 @@ public class PShapeSVG extends PShape {
99
98
  float strokeOpacity;
100
99
  float fillOpacity;
101
100
 
102
- /**
103
- * Width of containing SVG (used for percentages).
104
- */
101
+ /** Width of containing SVG (used for percentages). */
105
102
  protected float svgWidth;
106
103
 
107
- /**
108
- * Height of containing SVG (used for percentages).
109
- */
104
+ /** Height of containing SVG (used for percentages). */
110
105
  protected float svgHeight;
111
106
 
112
- /**
113
- * √((w² + h²)/2) of containing SVG (used for percentages).
114
- */
107
+ /** √((w² + h²)/2) of containing SVG (used for percentages). */
115
108
  protected float svgSizeXY;
116
109
 
117
110
  protected Gradient strokeGradient;
@@ -120,8 +113,10 @@ public class PShapeSVG extends PShape {
120
113
  protected Gradient fillGradient;
121
114
  String fillName; // id of another object
122
115
 
116
+
123
117
  /**
124
118
  * Initializes a new SVG object from the given XML object.
119
+ * @param svg
125
120
  */
126
121
  public PShapeSVG(XML svg) {
127
122
  this(null, svg, true);
@@ -136,6 +131,7 @@ public class PShapeSVG extends PShape {
136
131
  }
137
132
  }
138
133
 
134
+
139
135
  protected PShapeSVG(PShapeSVG parent, XML properties, boolean parseKids) {
140
136
  setParent(parent);
141
137
 
@@ -147,12 +143,8 @@ public class PShapeSVG extends PShape {
147
143
  // Can't handle width/height as percentages easily. I'm just going
148
144
  // to put in 100 as a dummy value, beacuse this means that it will
149
145
  // come out as a reasonable value.
150
- if (unitWidth != null) {
151
- width = parseUnitSize(unitWidth, 100);
152
- }
153
- if (unitHeight != null) {
154
- height = parseUnitSize(unitHeight, 100);
155
- }
146
+ if (unitWidth != null) width = parseUnitSize(unitWidth, 100);
147
+ if (unitHeight != null) height = parseUnitSize(unitHeight, 100);
156
148
 
157
149
  String viewBoxStr = properties.getString("viewBox");
158
150
  if (viewBoxStr != null) {
@@ -165,26 +157,23 @@ public class PShapeSVG extends PShape {
165
157
  } else {
166
158
  // http://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute
167
159
  // TODO: preserveAspectRatio.
168
- if (matrix == null) {
169
- matrix = new PMatrix2D();
170
- }
171
- matrix.scale(width / viewBox[2], height / viewBox[3]);
160
+ if (matrix == null) matrix = new PMatrix2D();
161
+ matrix.scale(width/viewBox[2], height/viewBox[3]);
172
162
  matrix.translate(-viewBox[0], -viewBox[1]);
173
163
  }
174
164
  }
175
165
 
176
166
  // Negative size is illegal.
177
- if (width < 0 || height < 0) {
178
- throw new RuntimeException("<svg>: width (" + width
179
- + ") and height (" + height + ") must not be negative.");
180
- }
167
+ if (width < 0 || height < 0)
168
+ throw new RuntimeException("<svg>: width (" + width +
169
+ ") and height (" + height + ") must not be negative.");
181
170
 
182
171
  // It's technically valid to have width or height == 0. Not specified at
183
172
  // all is what to test for.
184
173
  if ((unitWidth == null || unitHeight == null) && viewBoxStr == null) {
185
174
  //throw new RuntimeException("width/height not specified");
186
- PGraphics.showWarning("The width and/or height is not "
187
- + "readable in the <svg> tag of this file.");
175
+ PGraphics.showWarning("The width and/or height is not " +
176
+ "readable in the <svg> tag of this file.");
188
177
  // For the spec, the default is 100% and 100%. For purposes
189
178
  // here, insert a dummy value because this is prolly just a
190
179
  // font or something for which the w/h doesn't matter.
@@ -194,7 +183,7 @@ public class PShapeSVG extends PShape {
194
183
 
195
184
  svgWidth = width;
196
185
  svgHeight = height;
197
- svgSizeXY = PApplet.sqrt((svgWidth * svgWidth + svgHeight * svgHeight) / 2.0f);
186
+ svgSizeXY = PApplet.sqrt((svgWidth*svgWidth + svgHeight*svgHeight)/2.0f);
198
187
  }
199
188
 
200
189
  element = properties;
@@ -203,9 +192,7 @@ public class PShapeSVG extends PShape {
203
192
  if (name != null) {
204
193
  while (true) {
205
194
  String[] m = PApplet.match(name, "_x([A-Za-z0-9]{2})_");
206
- if (m == null) {
207
- break;
208
- }
195
+ if (m == null) break;
209
196
  char repair = (char) PApplet.unhex(m[1]);
210
197
  name = name.replace(m[0], "" + repair);
211
198
  }
@@ -229,6 +216,7 @@ public class PShapeSVG extends PShape {
229
216
  }
230
217
  }
231
218
 
219
+
232
220
  // Broken out so that subclasses can copy any additional variables
233
221
  // (i.e. fillGradientPaint and strokeGradientPaint)
234
222
  protected void setParent(PShapeSVG parent) {
@@ -255,7 +243,9 @@ public class PShapeSVG extends PShape {
255
243
 
256
244
  //hasTransform = false;
257
245
  //transformation = null; //new float[] { 1, 0, 0, 1, 0, 0 };
246
+
258
247
  // svgWidth, svgHeight, and svgXYSize done below.
248
+
259
249
  strokeOpacity = 1;
260
250
  fillOpacity = 1;
261
251
  opacity = 1;
@@ -276,7 +266,7 @@ public class PShapeSVG extends PShape {
276
266
  // fillGradientPaint = parent.fillGradientPaint;
277
267
  fillName = parent.fillName;
278
268
 
279
- svgWidth = parent.svgWidth;
269
+ svgWidth = parent.svgWidth;
280
270
  svgHeight = parent.svgHeight;
281
271
  svgSizeXY = parent.svgSizeXY;
282
272
 
@@ -289,13 +279,13 @@ public class PShapeSVG extends PShape {
289
279
  ellipseMode = CORNER;
290
280
  }
291
281
 
292
- /**
293
- * Factory method for subclasses.
294
- */
282
+
283
+ /** Factory method for subclasses. */
295
284
  protected PShapeSVG createShape(PShapeSVG parent, XML properties, boolean parseKids) {
296
285
  return new PShapeSVG(parent, properties, parseKids);
297
286
  }
298
287
 
288
+
299
289
  protected void parseChildren(XML graphics) {
300
290
  XML[] elements = graphics.getChildren();
301
291
  children = new PShape[elements.length];
@@ -303,22 +293,22 @@ public class PShapeSVG extends PShape {
303
293
 
304
294
  for (XML elem : elements) {
305
295
  PShape kid = parseChild(elem);
306
- if (kid != null) {
307
- addChild(kid);
308
- }
296
+ if (kid != null) addChild(kid);
309
297
  }
310
298
  children = (PShape[]) PApplet.subset(children, 0, childCount);
311
299
  }
312
300
 
301
+
313
302
  /**
314
- * Parse a child XML element. Override this method to add parsing for more SVG
315
- * elements.
303
+ * Parse a child XML element.
304
+ * Override this method to add parsing for more SVG elements.
316
305
  */
317
306
  protected PShape parseChild(XML elem) {
318
307
  // System.err.println("parsing child in pshape " + elem.getName());
319
308
  String name = elem.getName();
320
309
  PShapeSVG shape = null;
321
310
 
311
+
322
312
  if (name == null) {
323
313
  // just some whitespace that can be ignored (hopefully)
324
314
 
@@ -373,13 +363,15 @@ public class PShapeSVG extends PShape {
373
363
 
374
364
  // } else if (name.equals("font-face")) {
375
365
  // return new FontFace(this, elem);
366
+
376
367
  // } else if (name.equals("glyph") || name.equals("missing-glyph")) {
377
368
  // return new FontGlyph(this, elem);
369
+
378
370
  } else if (name.equals("text")) { // || name.equals("font")) {
379
- return new Text(this, elem);
371
+ return new Text(this, elem);
380
372
 
381
373
  } else if (name.equals("tspan")) {
382
- return new LineOfText(this, elem);
374
+ return new LineOfText(this, elem);
383
375
 
384
376
  } else if (name.equals("filter")) {
385
377
  PGraphics.showWarning("Filters are not supported.");
@@ -397,7 +389,7 @@ public class PShapeSVG extends PShape {
397
389
  // these are always in Inkscape files, the warnings get tedious
398
390
 
399
391
  } else if (name.equals("metadata")
400
- || name.equals("title") || name.equals("desc")) {
392
+ || name.equals("title") || name.equals("desc")) {
401
393
  // fontforge just stuffs <metadata> in as a comment.
402
394
  // All harmless stuff, irrelevant to rendering.
403
395
  return null;
@@ -409,10 +401,11 @@ public class PShapeSVG extends PShape {
409
401
  return shape;
410
402
  }
411
403
 
404
+
412
405
  protected void parseLine() {
413
406
  kind = LINE;
414
407
  family = PRIMITIVE;
415
- params = new float[]{
408
+ params = new float[] {
416
409
  getFloatWithUnit(element, "x1", svgWidth),
417
410
  getFloatWithUnit(element, "y1", svgHeight),
418
411
  getFloatWithUnit(element, "x2", svgWidth),
@@ -420,9 +413,9 @@ public class PShapeSVG extends PShape {
420
413
  };
421
414
  }
422
415
 
416
+
423
417
  /**
424
418
  * Handles parsing ellipse and circle tags.
425
- *
426
419
  * @param circle true if this is a circle and not an ellipse
427
420
  */
428
421
  protected void parseEllipse(boolean circle) {
@@ -443,14 +436,15 @@ public class PShapeSVG extends PShape {
443
436
  params[0] -= rx;
444
437
  params[1] -= ry;
445
438
 
446
- params[2] = rx * 2;
447
- params[3] = ry * 2;
439
+ params[2] = rx*2;
440
+ params[3] = ry*2;
448
441
  }
449
442
 
443
+
450
444
  protected void parseRect() {
451
445
  kind = RECT;
452
446
  family = PRIMITIVE;
453
- params = new float[]{
447
+ params = new float[] {
454
448
  getFloatWithUnit(element, "x", svgWidth),
455
449
  getFloatWithUnit(element, "y", svgHeight),
456
450
  getFloatWithUnit(element, "width", svgWidth),
@@ -458,12 +452,13 @@ public class PShapeSVG extends PShape {
458
452
  };
459
453
  }
460
454
 
455
+
461
456
  protected void parseImage() {
462
457
  kind = RECT;
463
458
  textureMode = NORMAL;
464
459
 
465
460
  family = PRIMITIVE;
466
- params = new float[]{
461
+ params = new float[] {
467
462
  getFloatWithUnit(element, "x", svgWidth),
468
463
  getFloatWithUnit(element, "y", svgHeight),
469
464
  getFloatWithUnit(element, "width", svgWidth),
@@ -474,9 +469,8 @@ public class PShapeSVG extends PShape {
474
469
  }
475
470
 
476
471
  /**
477
- * Parse a polyline or polygon from an SVG file. Syntax defined at
478
- * http://www.w3.org/TR/SVG/shapes.html#PointsBNF
479
- *
472
+ * Parse a polyline or polygon from an SVG file.
473
+ * Syntax defined at http://www.w3.org/TR/SVG/shapes.html#PointsBNF
480
474
  * @param close true if shape is closed (polygon), false if not (polyline)
481
475
  */
482
476
  protected void parsePoly(boolean close) {
@@ -509,6 +503,7 @@ public class PShapeSVG extends PShape {
509
503
  }
510
504
  }
511
505
 
506
+
512
507
  protected void parsePath() {
513
508
  family = PATH;
514
509
  kind = 0;
@@ -526,21 +521,17 @@ public class PShapeSVG extends PShape {
526
521
  char c = pathDataChars[i];
527
522
  boolean separate = false;
528
523
 
529
- if (c == 'M' || c == 'm'
530
- || c == 'L' || c == 'l'
531
- || c == 'H' || c == 'h'
532
- || c == 'V' || c == 'v'
533
- || c == 'C' || c == 'c'
534
- || // beziers
535
- c == 'S' || c == 's'
536
- || c == 'Q' || c == 'q'
537
- || // quadratic beziers
538
- c == 'T' || c == 't'
539
- || c == 'A' || c == 'a'
540
- || // elliptical arc
541
- c == 'Z' || c == 'z'
542
- || // closepath
543
- c == ',') {
524
+ if (c == 'M' || c == 'm' ||
525
+ c == 'L' || c == 'l' ||
526
+ c == 'H' || c == 'h' ||
527
+ c == 'V' || c == 'v' ||
528
+ c == 'C' || c == 'c' || // beziers
529
+ c == 'S' || c == 's' ||
530
+ c == 'Q' || c == 'q' || // quadratic beziers
531
+ c == 'T' || c == 't' ||
532
+ c == 'A' || c == 'a' || // elliptical arc
533
+ c == 'Z' || c == 'z' || // closepath
534
+ c == ',') {
544
535
  separate = true;
545
536
  if (i != 0) {
546
537
  pathBuffer.append("|");
@@ -552,7 +543,7 @@ public class PShapeSVG extends PShape {
552
543
  if (c == '-' && !lastSeparate) {
553
544
  // allow for 'e' notation in numbers, e.g. 2.10e-9
554
545
  // http://dev.processing.org/bugs/show_bug.cgi?id=1408
555
- if (i == 0 || pathDataChars[i - 1] != 'e') {
546
+ if (i == 0 || pathDataChars[i-1] != 'e') {
556
547
  pathBuffer.append("|");
557
548
  }
558
549
  }
@@ -566,8 +557,8 @@ public class PShapeSVG extends PShape {
566
557
  }
567
558
 
568
559
  // use whitespace constant to get rid of extra spaces and CR or LF
569
- String[] pathTokens
570
- = PApplet.splitTokens(pathBuffer.toString(), "|" + WHITESPACE);
560
+ String[] pathTokens =
561
+ PApplet.splitTokens(pathBuffer.toString(), "|" + WHITESPACE);
571
562
  vertices = new float[pathTokens.length][2];
572
563
  vertexCodes = new int[pathTokens.length];
573
564
 
@@ -593,307 +584,308 @@ public class PShapeSVG extends PShape {
593
584
  }
594
585
  switch (c) {
595
586
 
596
- case 'M': // M - move to (absolute)
597
- cx = PApplet.parseFloat(pathTokens[i + 1]);
598
- cy = PApplet.parseFloat(pathTokens[i + 2]);
599
- movetoX = cx;
600
- movetoY = cy;
601
- parsePathMoveto(cx, cy);
602
- implicitCommand = 'L';
603
- i += 3;
604
- break;
605
-
606
- case 'm': // m - move to (relative)
607
- cx = cx + PApplet.parseFloat(pathTokens[i + 1]);
608
- cy = cy + PApplet.parseFloat(pathTokens[i + 2]);
609
- movetoX = cx;
610
- movetoY = cy;
611
- parsePathMoveto(cx, cy);
612
- implicitCommand = 'l';
613
- i += 3;
614
- break;
615
-
616
- case 'L':
617
- cx = PApplet.parseFloat(pathTokens[i + 1]);
618
- cy = PApplet.parseFloat(pathTokens[i + 2]);
619
- parsePathLineto(cx, cy);
620
- i += 3;
621
- break;
622
-
623
- case 'l':
624
- cx = cx + PApplet.parseFloat(pathTokens[i + 1]);
625
- cy = cy + PApplet.parseFloat(pathTokens[i + 2]);
626
- parsePathLineto(cx, cy);
627
- i += 3;
628
- break;
629
-
630
- // horizontal lineto absolute
631
- case 'H':
632
- cx = PApplet.parseFloat(pathTokens[i + 1]);
633
- parsePathLineto(cx, cy);
634
- i += 2;
635
- break;
587
+ case 'M': // M - move to (absolute)
588
+ cx = PApplet.parseFloat(pathTokens[i + 1]);
589
+ cy = PApplet.parseFloat(pathTokens[i + 2]);
590
+ movetoX = cx;
591
+ movetoY = cy;
592
+ parsePathMoveto(cx, cy);
593
+ implicitCommand = 'L';
594
+ i += 3;
595
+ break;
636
596
 
637
- // horizontal lineto relative
638
- case 'h':
639
- cx = cx + PApplet.parseFloat(pathTokens[i + 1]);
640
- parsePathLineto(cx, cy);
641
- i += 2;
642
- break;
643
-
644
- case 'V':
645
- cy = PApplet.parseFloat(pathTokens[i + 1]);
646
- parsePathLineto(cx, cy);
647
- i += 2;
648
- break;
649
-
650
- case 'v':
651
- cy = cy + PApplet.parseFloat(pathTokens[i + 1]);
652
- parsePathLineto(cx, cy);
653
- i += 2;
654
- break;
597
+ case 'm': // m - move to (relative)
598
+ cx = cx + PApplet.parseFloat(pathTokens[i + 1]);
599
+ cy = cy + PApplet.parseFloat(pathTokens[i + 2]);
600
+ movetoX = cx;
601
+ movetoY = cy;
602
+ parsePathMoveto(cx, cy);
603
+ implicitCommand = 'l';
604
+ i += 3;
605
+ break;
655
606
 
656
- // C - curve to (absolute)
657
- case 'C': {
658
- float ctrlX1 = PApplet.parseFloat(pathTokens[i + 1]);
659
- float ctrlY1 = PApplet.parseFloat(pathTokens[i + 2]);
660
- float ctrlX2 = PApplet.parseFloat(pathTokens[i + 3]);
661
- float ctrlY2 = PApplet.parseFloat(pathTokens[i + 4]);
662
- float endX = PApplet.parseFloat(pathTokens[i + 5]);
663
- float endY = PApplet.parseFloat(pathTokens[i + 6]);
664
- parsePathCurveto(ctrlX1, ctrlY1, ctrlX2, ctrlY2, endX, endY);
665
- cx = endX;
666
- cy = endY;
667
- i += 7;
668
- prevCurve = true;
669
- }
607
+ case 'L':
608
+ cx = PApplet.parseFloat(pathTokens[i + 1]);
609
+ cy = PApplet.parseFloat(pathTokens[i + 2]);
610
+ parsePathLineto(cx, cy);
611
+ i += 3;
670
612
  break;
671
613
 
672
- // c - curve to (relative)
673
- case 'c': {
674
- float ctrlX1 = cx + PApplet.parseFloat(pathTokens[i + 1]);
675
- float ctrlY1 = cy + PApplet.parseFloat(pathTokens[i + 2]);
676
- float ctrlX2 = cx + PApplet.parseFloat(pathTokens[i + 3]);
677
- float ctrlY2 = cy + PApplet.parseFloat(pathTokens[i + 4]);
678
- float endX = cx + PApplet.parseFloat(pathTokens[i + 5]);
679
- float endY = cy + PApplet.parseFloat(pathTokens[i + 6]);
680
- parsePathCurveto(ctrlX1, ctrlY1, ctrlX2, ctrlY2, endX, endY);
681
- cx = endX;
682
- cy = endY;
683
- i += 7;
684
- prevCurve = true;
685
- }
614
+ case 'l':
615
+ cx = cx + PApplet.parseFloat(pathTokens[i + 1]);
616
+ cy = cy + PApplet.parseFloat(pathTokens[i + 2]);
617
+ parsePathLineto(cx, cy);
618
+ i += 3;
686
619
  break;
687
620
 
688
- // S - curve to shorthand (absolute)
689
- // Draws a cubic Bézier curve from the current point to (x,y). The first
690
- // control point is assumed to be the reflection of the second control
691
- // point on the previous command relative to the current point.
692
- // (x2,y2) is the second control point (i.e., the control point
693
- // at the end of the curve). S (uppercase) indicates that absolute
694
- // coordinates will follow; s (lowercase) indicates that relative
695
- // coordinates will follow. Multiple sets of coordinates may be specified
696
- // to draw a polybézier. At the end of the command, the new current point
697
- // becomes the final (x,y) coordinate pair used in the polybézier.
698
- case 'S': {
699
- // (If there is no previous command or if the previous command was not
700
- // an C, c, S or s, assume the first control point is coincident with
701
- // the current point.)
702
- if (!prevCurve) {
703
- ctrlX = cx;
704
- ctrlY = cy;
705
- } else {
706
- float ppx = vertices[vertexCount - 2][X];
707
- float ppy = vertices[vertexCount - 2][Y];
708
- float px = vertices[vertexCount - 1][X];
709
- float py = vertices[vertexCount - 1][Y];
710
- ctrlX = px + (px - ppx);
711
- ctrlY = py + (py - ppy);
712
- }
713
- float ctrlX2 = PApplet.parseFloat(pathTokens[i + 1]);
714
- float ctrlY2 = PApplet.parseFloat(pathTokens[i + 2]);
715
- float endX = PApplet.parseFloat(pathTokens[i + 3]);
716
- float endY = PApplet.parseFloat(pathTokens[i + 4]);
717
- parsePathCurveto(ctrlX, ctrlY, ctrlX2, ctrlY2, endX, endY);
718
- cx = endX;
719
- cy = endY;
720
- i += 5;
721
- prevCurve = true;
722
- }
621
+ // horizontal lineto absolute
622
+ case 'H':
623
+ cx = PApplet.parseFloat(pathTokens[i + 1]);
624
+ parsePathLineto(cx, cy);
625
+ i += 2;
723
626
  break;
724
627
 
725
- // s - curve to shorthand (relative)
726
- case 's': {
727
- if (!prevCurve) {
728
- ctrlX = cx;
729
- ctrlY = cy;
730
- } else {
731
- float ppx = vertices[vertexCount - 2][X];
732
- float ppy = vertices[vertexCount - 2][Y];
733
- float px = vertices[vertexCount - 1][X];
734
- float py = vertices[vertexCount - 1][Y];
735
- ctrlX = px + (px - ppx);
736
- ctrlY = py + (py - ppy);
737
- }
738
- float ctrlX2 = cx + PApplet.parseFloat(pathTokens[i + 1]);
739
- float ctrlY2 = cy + PApplet.parseFloat(pathTokens[i + 2]);
740
- float endX = cx + PApplet.parseFloat(pathTokens[i + 3]);
741
- float endY = cy + PApplet.parseFloat(pathTokens[i + 4]);
742
- parsePathCurveto(ctrlX, ctrlY, ctrlX2, ctrlY2, endX, endY);
743
- cx = endX;
744
- cy = endY;
745
- i += 5;
746
- prevCurve = true;
747
- }
628
+ // horizontal lineto relative
629
+ case 'h':
630
+ cx = cx + PApplet.parseFloat(pathTokens[i + 1]);
631
+ parsePathLineto(cx, cy);
632
+ i += 2;
748
633
  break;
749
634
 
750
- // Q - quadratic curve to (absolute)
751
- // Draws a quadratic Bézier curve from the current point to (x,y) using
752
- // (x1,y1) as the control point. Q (uppercase) indicates that absolute
753
- // coordinates will follow; q (lowercase) indicates that relative
754
- // coordinates will follow. Multiple sets of coordinates may be specified
755
- // to draw a polybézier. At the end of the command, the new current point
756
- // becomes the final (x,y) coordinate pair used in the polybézier.
757
- case 'Q': {
758
- ctrlX = PApplet.parseFloat(pathTokens[i + 1]);
759
- ctrlY = PApplet.parseFloat(pathTokens[i + 2]);
760
- float endX = PApplet.parseFloat(pathTokens[i + 3]);
761
- float endY = PApplet.parseFloat(pathTokens[i + 4]);
762
- //parsePathQuadto(cx, cy, ctrlX, ctrlY, endX, endY);
763
- parsePathQuadto(ctrlX, ctrlY, endX, endY);
764
- cx = endX;
765
- cy = endY;
766
- i += 5;
767
- prevCurve = true;
768
- }
635
+ case 'V':
636
+ cy = PApplet.parseFloat(pathTokens[i + 1]);
637
+ parsePathLineto(cx, cy);
638
+ i += 2;
769
639
  break;
770
640
 
771
- // q - quadratic curve to (relative)
772
- case 'q': {
773
- ctrlX = cx + PApplet.parseFloat(pathTokens[i + 1]);
774
- ctrlY = cy + PApplet.parseFloat(pathTokens[i + 2]);
775
- float endX = cx + PApplet.parseFloat(pathTokens[i + 3]);
776
- float endY = cy + PApplet.parseFloat(pathTokens[i + 4]);
777
- //parsePathQuadto(cx, cy, ctrlX, ctrlY, endX, endY);
778
- parsePathQuadto(ctrlX, ctrlY, endX, endY);
779
- cx = endX;
780
- cy = endY;
781
- i += 5;
782
- prevCurve = true;
783
- }
641
+ case 'v':
642
+ cy = cy + PApplet.parseFloat(pathTokens[i + 1]);
643
+ parsePathLineto(cx, cy);
644
+ i += 2;
784
645
  break;
785
646
 
786
- // T - quadratic curveto shorthand (absolute)
787
- // The control point is assumed to be the reflection of the control
788
- // point on the previous command relative to the current point.
789
- case 'T': {
790
- // If there is no previous command or if the previous command was
791
- // not a Q, q, T or t, assume the control point is coincident
792
- // with the current point.
793
- if (!prevCurve) {
794
- ctrlX = cx;
795
- ctrlY = cy;
796
- } else {
797
- float ppx = vertices[vertexCount - 2][X];
798
- float ppy = vertices[vertexCount - 2][Y];
799
- float px = vertices[vertexCount - 1][X];
800
- float py = vertices[vertexCount - 1][Y];
801
- ctrlX = px + (px - ppx);
802
- ctrlY = py + (py - ppy);
803
- }
804
- float endX = PApplet.parseFloat(pathTokens[i + 1]);
805
- float endY = PApplet.parseFloat(pathTokens[i + 2]);
806
- //parsePathQuadto(cx, cy, ctrlX, ctrlY, endX, endY);
807
- parsePathQuadto(ctrlX, ctrlY, endX, endY);
808
- cx = endX;
809
- cy = endY;
810
- i += 3;
811
- prevCurve = true;
647
+ // C - curve to (absolute)
648
+ case 'C': {
649
+ float ctrlX1 = PApplet.parseFloat(pathTokens[i + 1]);
650
+ float ctrlY1 = PApplet.parseFloat(pathTokens[i + 2]);
651
+ float ctrlX2 = PApplet.parseFloat(pathTokens[i + 3]);
652
+ float ctrlY2 = PApplet.parseFloat(pathTokens[i + 4]);
653
+ float endX = PApplet.parseFloat(pathTokens[i + 5]);
654
+ float endY = PApplet.parseFloat(pathTokens[i + 6]);
655
+ parsePathCurveto(ctrlX1, ctrlY1, ctrlX2, ctrlY2, endX, endY);
656
+ cx = endX;
657
+ cy = endY;
658
+ i += 7;
659
+ prevCurve = true;
660
+ }
661
+ break;
662
+
663
+ // c - curve to (relative)
664
+ case 'c': {
665
+ float ctrlX1 = cx + PApplet.parseFloat(pathTokens[i + 1]);
666
+ float ctrlY1 = cy + PApplet.parseFloat(pathTokens[i + 2]);
667
+ float ctrlX2 = cx + PApplet.parseFloat(pathTokens[i + 3]);
668
+ float ctrlY2 = cy + PApplet.parseFloat(pathTokens[i + 4]);
669
+ float endX = cx + PApplet.parseFloat(pathTokens[i + 5]);
670
+ float endY = cy + PApplet.parseFloat(pathTokens[i + 6]);
671
+ parsePathCurveto(ctrlX1, ctrlY1, ctrlX2, ctrlY2, endX, endY);
672
+ cx = endX;
673
+ cy = endY;
674
+ i += 7;
675
+ prevCurve = true;
676
+ }
677
+ break;
678
+
679
+ // S - curve to shorthand (absolute)
680
+ // Draws a cubic Bézier curve from the current point to (x,y). The first
681
+ // control point is assumed to be the reflection of the second control
682
+ // point on the previous command relative to the current point.
683
+ // (x2,y2) is the second control point (i.e., the control point
684
+ // at the end of the curve). S (uppercase) indicates that absolute
685
+ // coordinates will follow; s (lowercase) indicates that relative
686
+ // coordinates will follow. Multiple sets of coordinates may be specified
687
+ // to draw a polybézier. At the end of the command, the new current point
688
+ // becomes the final (x,y) coordinate pair used in the polybézier.
689
+ case 'S': {
690
+ // (If there is no previous command or if the previous command was not
691
+ // an C, c, S or s, assume the first control point is coincident with
692
+ // the current point.)
693
+ if (!prevCurve) {
694
+ ctrlX = cx;
695
+ ctrlY = cy;
696
+ } else {
697
+ float ppx = vertices[vertexCount-2][X];
698
+ float ppy = vertices[vertexCount-2][Y];
699
+ float px = vertices[vertexCount-1][X];
700
+ float py = vertices[vertexCount-1][Y];
701
+ ctrlX = px + (px - ppx);
702
+ ctrlY = py + (py - ppy);
812
703
  }
813
- break;
704
+ float ctrlX2 = PApplet.parseFloat(pathTokens[i + 1]);
705
+ float ctrlY2 = PApplet.parseFloat(pathTokens[i + 2]);
706
+ float endX = PApplet.parseFloat(pathTokens[i + 3]);
707
+ float endY = PApplet.parseFloat(pathTokens[i + 4]);
708
+ parsePathCurveto(ctrlX, ctrlY, ctrlX2, ctrlY2, endX, endY);
709
+ cx = endX;
710
+ cy = endY;
711
+ i += 5;
712
+ prevCurve = true;
713
+ }
714
+ break;
814
715
 
815
- // t - quadratic curveto shorthand (relative)
816
- case 't': {
817
- if (!prevCurve) {
818
- ctrlX = cx;
819
- ctrlY = cy;
820
- } else {
821
- float ppx = vertices[vertexCount - 2][X];
822
- float ppy = vertices[vertexCount - 2][Y];
823
- float px = vertices[vertexCount - 1][X];
824
- float py = vertices[vertexCount - 1][Y];
825
- ctrlX = px + (px - ppx);
826
- ctrlY = py + (py - ppy);
827
- }
828
- float endX = cx + PApplet.parseFloat(pathTokens[i + 1]);
829
- float endY = cy + PApplet.parseFloat(pathTokens[i + 2]);
830
- //parsePathQuadto(cx, cy, ctrlX, ctrlY, endX, endY);
831
- parsePathQuadto(ctrlX, ctrlY, endX, endY);
832
- cx = endX;
833
- cy = endY;
834
- i += 3;
835
- prevCurve = true;
716
+ // s - curve to shorthand (relative)
717
+ case 's': {
718
+ if (!prevCurve) {
719
+ ctrlX = cx;
720
+ ctrlY = cy;
721
+ } else {
722
+ float ppx = vertices[vertexCount-2][X];
723
+ float ppy = vertices[vertexCount-2][Y];
724
+ float px = vertices[vertexCount-1][X];
725
+ float py = vertices[vertexCount-1][Y];
726
+ ctrlX = px + (px - ppx);
727
+ ctrlY = py + (py - ppy);
836
728
  }
729
+ float ctrlX2 = cx + PApplet.parseFloat(pathTokens[i + 1]);
730
+ float ctrlY2 = cy + PApplet.parseFloat(pathTokens[i + 2]);
731
+ float endX = cx + PApplet.parseFloat(pathTokens[i + 3]);
732
+ float endY = cy + PApplet.parseFloat(pathTokens[i + 4]);
733
+ parsePathCurveto(ctrlX, ctrlY, ctrlX2, ctrlY2, endX, endY);
734
+ cx = endX;
735
+ cy = endY;
736
+ i += 5;
737
+ prevCurve = true;
738
+ }
739
+ break;
740
+
741
+ // Q - quadratic curve to (absolute)
742
+ // Draws a quadratic Bézier curve from the current point to (x,y) using
743
+ // (x1,y1) as the control point. Q (uppercase) indicates that absolute
744
+ // coordinates will follow; q (lowercase) indicates that relative
745
+ // coordinates will follow. Multiple sets of coordinates may be specified
746
+ // to draw a polybézier. At the end of the command, the new current point
747
+ // becomes the final (x,y) coordinate pair used in the polybézier.
748
+ case 'Q': {
749
+ ctrlX = PApplet.parseFloat(pathTokens[i + 1]);
750
+ ctrlY = PApplet.parseFloat(pathTokens[i + 2]);
751
+ float endX = PApplet.parseFloat(pathTokens[i + 3]);
752
+ float endY = PApplet.parseFloat(pathTokens[i + 4]);
753
+ //parsePathQuadto(cx, cy, ctrlX, ctrlY, endX, endY);
754
+ parsePathQuadto(ctrlX, ctrlY, endX, endY);
755
+ cx = endX;
756
+ cy = endY;
757
+ i += 5;
758
+ prevCurve = true;
759
+ }
760
+ break;
761
+
762
+ // q - quadratic curve to (relative)
763
+ case 'q': {
764
+ ctrlX = cx + PApplet.parseFloat(pathTokens[i + 1]);
765
+ ctrlY = cy + PApplet.parseFloat(pathTokens[i + 2]);
766
+ float endX = cx + PApplet.parseFloat(pathTokens[i + 3]);
767
+ float endY = cy + PApplet.parseFloat(pathTokens[i + 4]);
768
+ //parsePathQuadto(cx, cy, ctrlX, ctrlY, endX, endY);
769
+ parsePathQuadto(ctrlX, ctrlY, endX, endY);
770
+ cx = endX;
771
+ cy = endY;
772
+ i += 5;
773
+ prevCurve = true;
774
+ }
775
+ break;
776
+
777
+ // T - quadratic curveto shorthand (absolute)
778
+ // The control point is assumed to be the reflection of the control
779
+ // point on the previous command relative to the current point.
780
+ case 'T': {
781
+ // If there is no previous command or if the previous command was
782
+ // not a Q, q, T or t, assume the control point is coincident
783
+ // with the current point.
784
+ if (!prevCurve) {
785
+ ctrlX = cx;
786
+ ctrlY = cy;
787
+ } else {
788
+ float ppx = vertices[vertexCount-2][X];
789
+ float ppy = vertices[vertexCount-2][Y];
790
+ float px = vertices[vertexCount-1][X];
791
+ float py = vertices[vertexCount-1][Y];
792
+ ctrlX = px + (px - ppx);
793
+ ctrlY = py + (py - ppy);
794
+ }
795
+ float endX = PApplet.parseFloat(pathTokens[i + 1]);
796
+ float endY = PApplet.parseFloat(pathTokens[i + 2]);
797
+ //parsePathQuadto(cx, cy, ctrlX, ctrlY, endX, endY);
798
+ parsePathQuadto(ctrlX, ctrlY, endX, endY);
799
+ cx = endX;
800
+ cy = endY;
801
+ i += 3;
802
+ prevCurve = true;
803
+ }
837
804
  break;
838
805
 
839
- // A - elliptical arc to (absolute)
840
- case 'A': {
841
- float rx = PApplet.parseFloat(pathTokens[i + 1]);
842
- float ry = PApplet.parseFloat(pathTokens[i + 2]);
843
- float angle = PApplet.parseFloat(pathTokens[i + 3]);
844
- boolean fa = PApplet.parseFloat(pathTokens[i + 4]) != 0;
845
- boolean fs = PApplet.parseFloat(pathTokens[i + 5]) != 0;
846
- float endX = PApplet.parseFloat(pathTokens[i + 6]);
847
- float endY = PApplet.parseFloat(pathTokens[i + 7]);
848
- parsePathArcto(cx, cy, rx, ry, angle, fa, fs, endX, endY);
849
- cx = endX;
850
- cy = endY;
851
- i += 8;
852
- prevCurve = true;
806
+ // t - quadratic curveto shorthand (relative)
807
+ case 't': {
808
+ if (!prevCurve) {
809
+ ctrlX = cx;
810
+ ctrlY = cy;
811
+ } else {
812
+ float ppx = vertices[vertexCount-2][X];
813
+ float ppy = vertices[vertexCount-2][Y];
814
+ float px = vertices[vertexCount-1][X];
815
+ float py = vertices[vertexCount-1][Y];
816
+ ctrlX = px + (px - ppx);
817
+ ctrlY = py + (py - ppy);
853
818
  }
819
+ float endX = cx + PApplet.parseFloat(pathTokens[i + 1]);
820
+ float endY = cy + PApplet.parseFloat(pathTokens[i + 2]);
821
+ //parsePathQuadto(cx, cy, ctrlX, ctrlY, endX, endY);
822
+ parsePathQuadto(ctrlX, ctrlY, endX, endY);
823
+ cx = endX;
824
+ cy = endY;
825
+ i += 3;
826
+ prevCurve = true;
827
+ }
854
828
  break;
855
829
 
856
- // a - elliptical arc to (relative)
857
- case 'a': {
858
- float rx = PApplet.parseFloat(pathTokens[i + 1]);
859
- float ry = PApplet.parseFloat(pathTokens[i + 2]);
860
- float angle = PApplet.parseFloat(pathTokens[i + 3]);
861
- boolean fa = PApplet.parseFloat(pathTokens[i + 4]) != 0;
862
- boolean fs = PApplet.parseFloat(pathTokens[i + 5]) != 0;
863
- float endX = cx + PApplet.parseFloat(pathTokens[i + 6]);
864
- float endY = cy + PApplet.parseFloat(pathTokens[i + 7]);
865
- parsePathArcto(cx, cy, rx, ry, angle, fa, fs, endX, endY);
866
- cx = endX;
867
- cy = endY;
868
- i += 8;
869
- prevCurve = true;
870
- }
830
+ // A - elliptical arc to (absolute)
831
+ case 'A': {
832
+ float rx = PApplet.parseFloat(pathTokens[i + 1]);
833
+ float ry = PApplet.parseFloat(pathTokens[i + 2]);
834
+ float angle = PApplet.parseFloat(pathTokens[i + 3]);
835
+ boolean fa = PApplet.parseFloat(pathTokens[i + 4]) != 0;
836
+ boolean fs = PApplet.parseFloat(pathTokens[i + 5]) != 0;
837
+ float endX = PApplet.parseFloat(pathTokens[i + 6]);
838
+ float endY = PApplet.parseFloat(pathTokens[i + 7]);
839
+ parsePathArcto(cx, cy, rx, ry, angle, fa, fs, endX, endY);
840
+ cx = endX;
841
+ cy = endY;
842
+ i += 8;
843
+ prevCurve = true;
844
+ }
845
+ break;
846
+
847
+ // a - elliptical arc to (relative)
848
+ case 'a': {
849
+ float rx = PApplet.parseFloat(pathTokens[i + 1]);
850
+ float ry = PApplet.parseFloat(pathTokens[i + 2]);
851
+ float angle = PApplet.parseFloat(pathTokens[i + 3]);
852
+ boolean fa = PApplet.parseFloat(pathTokens[i + 4]) != 0;
853
+ boolean fs = PApplet.parseFloat(pathTokens[i + 5]) != 0;
854
+ float endX = cx + PApplet.parseFloat(pathTokens[i + 6]);
855
+ float endY = cy + PApplet.parseFloat(pathTokens[i + 7]);
856
+ parsePathArcto(cx, cy, rx, ry, angle, fa, fs, endX, endY);
857
+ cx = endX;
858
+ cy = endY;
859
+ i += 8;
860
+ prevCurve = true;
861
+ }
862
+ break;
863
+
864
+ case 'Z':
865
+ case 'z':
866
+ // since closing the path, the 'current' point needs
867
+ // to return back to the last moveto location.
868
+ // http://code.google.com/p/processing/issues/detail?id=1058
869
+ cx = movetoX;
870
+ cy = movetoY;
871
+ close = true;
872
+ i++;
871
873
  break;
872
874
 
873
- case 'Z':
874
- case 'z':
875
- // since closing the path, the 'current' point needs
876
- // to return back to the last moveto location.
877
- // http://code.google.com/p/processing/issues/detail?id=1058
878
- cx = movetoX;
879
- cy = movetoY;
880
- close = true;
881
- i++;
882
- break;
883
-
884
- default:
885
- String parsed
886
- = PApplet.join(PApplet.subset(pathTokens, 0, i), ",");
887
- String unparsed
888
- = PApplet.join(PApplet.subset(pathTokens, i), ",");
889
- System.err.println("parsed: " + parsed);
890
- System.err.println("unparsed: " + unparsed);
891
- throw new RuntimeException("shape command not handled: " + pathTokens[i]);
875
+ default:
876
+ String parsed =
877
+ PApplet.join(PApplet.subset(pathTokens, 0, i), ",");
878
+ String unparsed =
879
+ PApplet.join(PApplet.subset(pathTokens, i), ",");
880
+ System.err.println("parsed: " + parsed);
881
+ System.err.println("unparsed: " + unparsed);
882
+ throw new RuntimeException("shape command not handled: " + pathTokens[i]);
892
883
  }
893
884
  // prevCommand = c;
894
885
  }
895
886
  }
896
887
 
888
+
897
889
  // private void parsePathCheck(int num) {
898
890
  // if (vertexCount + num-1 >= vertices.length) {
899
891
  // //vertices = (float[][]) PApplet.expand(vertices);
@@ -902,6 +894,7 @@ public class PShapeSVG extends PShape {
902
894
  // vertices = temp;
903
895
  // }
904
896
  // }
897
+
905
898
  private void parsePathVertex(float x, float y) {
906
899
  if (vertexCount == vertices.length) {
907
900
  //vertices = (float[][]) PApplet.expand(vertices);
@@ -914,6 +907,7 @@ public class PShapeSVG extends PShape {
914
907
  vertexCount++;
915
908
  }
916
909
 
910
+
917
911
  private void parsePathCode(int what) {
918
912
  if (vertexCodeCount == vertexCodes.length) {
919
913
  vertexCodes = PApplet.expand(vertexCodes);
@@ -921,6 +915,7 @@ public class PShapeSVG extends PShape {
921
915
  vertexCodes[vertexCodeCount++] = what;
922
916
  }
923
917
 
918
+
924
919
  private void parsePathMoveto(float px, float py) {
925
920
  if (vertexCount > 0) {
926
921
  parsePathCode(BREAK);
@@ -929,14 +924,16 @@ public class PShapeSVG extends PShape {
929
924
  parsePathVertex(px, py);
930
925
  }
931
926
 
927
+
932
928
  private void parsePathLineto(float px, float py) {
933
929
  parsePathCode(VERTEX);
934
930
  parsePathVertex(px, py);
935
931
  }
936
932
 
933
+
937
934
  private void parsePathCurveto(float x1, float y1,
938
- float x2, float y2,
939
- float x3, float y3) {
935
+ float x2, float y2,
936
+ float x3, float y3) {
940
937
  parsePathCode(BEZIER_VERTEX);
941
938
  parsePathVertex(x1, y1);
942
939
  parsePathVertex(x2, y2);
@@ -955,8 +952,9 @@ public class PShapeSVG extends PShape {
955
952
  // parsePathVertex(x2 + ((cx-x2)*2/3.0f), y2 + ((cy-y2)*2/3.0f));
956
953
  // parsePathVertex(x2, y2);
957
954
  // }
955
+
958
956
  private void parsePathQuadto(float cx, float cy,
959
- float x2, float y2) {
957
+ float x2, float y2) {
960
958
  //System.out.println("quadto: " + x1 + "," + y1 + " " + cx + "," + cy + " " + x2 + "," + y2);
961
959
  // parsePathCode(BEZIER_VERTEX);
962
960
  parsePathCode(QUADRATIC_VERTEX);
@@ -965,48 +963,41 @@ public class PShapeSVG extends PShape {
965
963
  parsePathVertex(x2, y2);
966
964
  }
967
965
 
966
+
968
967
  // Approximates elliptical arc by several bezier segments.
969
968
  // Meets SVG standard requirements from:
970
969
  // http://www.w3.org/TR/SVG/paths.html#PathDataEllipticalArcCommands
971
970
  // http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes
972
971
  // Based on arc to bezier curve equations from:
973
972
  // http://www.spaceroots.org/documents/ellipse/node22.html
974
- private void parsePathArcto(float x1, float y1,
975
- float rx, float ry,
976
- float angle,
977
- boolean fa, boolean fs,
978
- float x2, float y2) {
979
- if (x1 == x2 && y1 == y2) {
980
- return;
981
- }
982
- if (rx == 0 || ry == 0) {
983
- parsePathLineto(x2, y2);
984
- return;
985
- }
973
+ private void parsePathArcto(float x1, float y1,
974
+ float rx, float ry,
975
+ float angle,
976
+ boolean fa, boolean fs,
977
+ float x2, float y2) {
978
+ if (x1 == x2 && y1 == y2) return;
979
+ if (rx == 0 || ry == 0) { parsePathLineto(x2, y2); return; }
986
980
 
987
- rx = PApplet.abs(rx);
988
- ry = PApplet.abs(ry);
981
+ rx = PApplet.abs(rx); ry = PApplet.abs(ry);
989
982
 
990
983
  float phi = PApplet.radians(((angle % 360) + 360) % 360);
991
- float cosPhi = PApplet.cos(phi), sinPhi = PApplet.sin(phi);
984
+ float cosPhi = PApplet.cos(phi), sinPhi = PApplet.sin(phi);
992
985
 
993
- float x1r = (cosPhi * (x1 - x2) + sinPhi * (y1 - y2)) / 2;
986
+ float x1r = ( cosPhi * (x1 - x2) + sinPhi * (y1 - y2)) / 2;
994
987
  float y1r = (-sinPhi * (x1 - x2) + cosPhi * (y1 - y2)) / 2;
995
988
 
996
989
  float cxr, cyr;
997
990
  {
998
- float A = (x1r * x1r) / (rx * rx) + (y1r * y1r) / (ry * ry);
991
+ float A = (x1r*x1r) / (rx*rx) + (y1r*y1r) / (ry*ry);
999
992
  if (A > 1) {
1000
993
  // No solution, scale ellipse up according to SVG standard
1001
994
  float sqrtA = PApplet.sqrt(A);
1002
- rx *= sqrtA;
1003
- cxr = 0;
1004
- ry *= sqrtA;
1005
- cyr = 0;
995
+ rx *= sqrtA; cxr = 0;
996
+ ry *= sqrtA; cyr = 0;
1006
997
  } else {
1007
- float k = ((fa == fs) ? -1f : 1f)
1008
- * PApplet.sqrt((rx * rx * ry * ry) / ((rx * rx * y1r * y1r) + (ry * ry * x1r * x1r)) - 1f);
1009
- cxr = k * rx * y1r / ry;
998
+ float k = ((fa == fs) ? -1f : 1f) *
999
+ PApplet.sqrt((rx*rx * ry*ry) / ((rx*rx * y1r*y1r) + (ry*ry * x1r*x1r)) - 1f);
1000
+ cxr = k * rx * y1r / ry;
1010
1001
  cyr = -k * ry * x1r / rx;
1011
1002
  }
1012
1003
  }
@@ -1016,13 +1007,11 @@ public class PShapeSVG extends PShape {
1016
1007
 
1017
1008
  float phi1, phiDelta;
1018
1009
  {
1019
- float sx = (x1r - cxr) / rx, sy = (y1r - cyr) / ry;
1020
- float tx = (-x1r - cxr) / rx, ty = (-y1r - cyr) / ry;
1010
+ float sx = ( x1r - cxr) / rx, sy = ( y1r - cyr) / ry;
1011
+ float tx = (-x1r - cxr) / rx, ty = (-y1r - cyr) / ry;
1021
1012
  phi1 = PApplet.atan2(sy, sx);
1022
1013
  phiDelta = (((PApplet.atan2(ty, tx) - phi1) % TWO_PI) + TWO_PI) % TWO_PI;
1023
- if (!fs) {
1024
- phiDelta -= TWO_PI;
1025
- }
1014
+ if (!fs) phiDelta -= TWO_PI;
1026
1015
  }
1027
1016
 
1028
1017
  // One segment can not cover more that PI, less than PI/2 is
@@ -1030,10 +1019,10 @@ public class PShapeSVG extends PShape {
1030
1019
  int segmentCount = PApplet.ceil(PApplet.abs(phiDelta) / TWO_PI * 4);
1031
1020
 
1032
1021
  float inc = phiDelta / segmentCount;
1033
- float a = PApplet.sin(inc)
1034
- * (PApplet.sqrt(4 + 3 * PApplet.sq(PApplet.tan(inc / 2))) - 1) / 3;
1022
+ float a = PApplet.sin(inc) *
1023
+ (PApplet.sqrt(4 + 3 * PApplet.sq(PApplet.tan(inc / 2))) - 1) / 3;
1035
1024
 
1036
- float sinPhi1 = PApplet.sin(phi1), cosPhi1 = PApplet.cos(phi1);
1025
+ float sinPhi1 = PApplet.sin(phi1), cosPhi1 = PApplet.cos(phi1);
1037
1026
 
1038
1027
  float p1x = x1;
1039
1028
  float p1y = y1;
@@ -1042,38 +1031,32 @@ public class PShapeSVG extends PShape {
1042
1031
 
1043
1032
  for (int i = 0; i < segmentCount; i++) {
1044
1033
  float eta = phi1 + (i + 1) * inc;
1045
- float sinEta = PApplet.sin(eta), cosEta = PApplet.cos(eta);
1034
+ float sinEta = PApplet.sin(eta), cosEta = PApplet.cos(eta);
1046
1035
 
1047
1036
  float p2x = cx + rx * cosPhi * cosEta - ry * sinPhi * sinEta;
1048
1037
  float p2y = cy + rx * sinPhi * cosEta + ry * cosPhi * sinEta;
1049
1038
  float relq2x = a * (-rx * cosPhi * sinEta - ry * sinPhi * cosEta);
1050
1039
  float relq2y = a * (-rx * sinPhi * sinEta + ry * cosPhi * cosEta);
1051
1040
 
1052
- if (i == segmentCount - 1) {
1053
- p2x = x2;
1054
- p2y = y2;
1055
- }
1041
+ if (i == segmentCount - 1) { p2x = x2; p2y = y2; }
1056
1042
 
1057
1043
  parsePathCode(BEZIER_VERTEX);
1058
1044
  parsePathVertex(p1x + relq1x, p1y + relq1y);
1059
1045
  parsePathVertex(p2x - relq2x, p2y - relq2y);
1060
1046
  parsePathVertex(p2x, p2y);
1061
1047
 
1062
- p1x = p2x;
1063
- relq1x = relq2x;
1064
- p1y = p2y;
1065
- relq1y = relq2y;
1048
+ p1x = p2x; relq1x = relq2x;
1049
+ p1y = p2y; relq1y = relq2y;
1066
1050
  }
1067
1051
  }
1068
1052
 
1053
+
1069
1054
  /**
1070
- * Parse the specified SVG matrix into a PMatrix2D. Note that PMatrix2D is
1071
- * rotated relative to the SVG definition, so parameters are rearranged here.
1072
- * More about the transformation matrices in
1073
- * <a href="http://www.w3.org/TR/SVG/coords.html#TransformAttribute">this
1074
- * section</a>
1055
+ * Parse the specified SVG matrix into a PMatrix2D. Note that PMatrix2D
1056
+ * is rotated relative to the SVG definition, so parameters are rearranged
1057
+ * here. More about the transformation matrices in
1058
+ * <a href="http://www.w3.org/TR/SVG/coords.html#TransformAttribute">this section</a>
1075
1059
  * of the SVG documentation.
1076
- *
1077
1060
  * @param matrixStr text of the matrix param.
1078
1061
  * @return a good old-fashioned PMatrix2D
1079
1062
  */
@@ -1083,7 +1066,7 @@ public class PShapeSVG extends PShape {
1083
1066
  int start = 0;
1084
1067
  int stop = -1;
1085
1068
  while ((stop = matrixStr.indexOf(')', start)) != -1) {
1086
- PMatrix2D m = parseSingleTransform(matrixStr.substring(start, stop + 1));
1069
+ PMatrix2D m = parseSingleTransform(matrixStr.substring(start, stop+1));
1087
1070
  if (outgoing == null) {
1088
1071
  outgoing = m;
1089
1072
  } else {
@@ -1094,6 +1077,7 @@ public class PShapeSVG extends PShape {
1094
1077
  return outgoing;
1095
1078
  }
1096
1079
 
1080
+
1097
1081
  static protected PMatrix2D parseSingleTransform(String matrixStr) {
1098
1082
  //String[] pieces = PApplet.match(matrixStr, "^\\s*(\\w+)\\((.*)\\)\\s*$");
1099
1083
  String[] pieces = PApplet.match(matrixStr, "[,\\s]*(\\w+)\\((.*)\\)");
@@ -1112,7 +1096,7 @@ public class PShapeSVG extends PShape {
1112
1096
  case "scale":
1113
1097
  float sx = m[0];
1114
1098
  float sy = (m.length == 2) ? m[1] : m[0];
1115
- return new PMatrix2D(sx, 0, 0, 0, sy, 0);
1099
+ return new PMatrix2D(sx, 0, 0, 0, sy, 0);
1116
1100
  case "rotate":
1117
1101
  float angle = m[0];
1118
1102
  if (m.length == 1) {
@@ -1120,24 +1104,24 @@ public class PShapeSVG extends PShape {
1120
1104
  float s = PApplet.sin(angle);
1121
1105
  // SVG version is cos(a) sin(a) -sin(a) cos(a) 0 0
1122
1106
  return new PMatrix2D(c, -s, 0, s, c, 0);
1123
-
1107
+
1124
1108
  } else if (m.length == 3) {
1125
- PMatrix2D mat = new PMatrix2D(0, 1, m[1], 1, 0, m[2]);
1109
+ PMatrix2D mat = new PMatrix2D(0, 1, m[1], 1, 0, m[2]);
1126
1110
  mat.rotate(m[0]);
1127
1111
  mat.translate(-m[1], -m[2]);
1128
1112
  return mat;
1129
- }
1130
- break;
1113
+ } break;
1131
1114
  case "skewX":
1132
- return new PMatrix2D(1, 0, 1, PApplet.tan(m[0]), 0, 0);
1115
+ return new PMatrix2D(1, 0, 1, PApplet.tan(m[0]), 0, 0);
1133
1116
  case "skewY":
1134
- return new PMatrix2D(1, 0, 1, 0, PApplet.tan(m[0]), 0);
1117
+ return new PMatrix2D(1, 0, 1, 0, PApplet.tan(m[0]), 0);
1135
1118
  default:
1136
1119
  break;
1137
1120
  }
1138
1121
  return null;
1139
1122
  }
1140
1123
 
1124
+
1141
1125
  protected void parseColors(XML properties) {
1142
1126
  if (properties.hasAttribute("opacity")) {
1143
1127
  String opacityText = properties.getString("opacity");
@@ -1191,55 +1175,61 @@ public class PShapeSVG extends PShape {
1191
1175
  String[] tokens = PApplet.splitTokens(styleToken, ":");
1192
1176
  //PApplet.println(tokens);
1193
1177
  tokens[0] = PApplet.trim(tokens[0]);
1194
- if (tokens[0].equals("fill")) {
1195
- setColor(tokens[1], true);
1196
-
1197
- } else if (tokens[0].equals("fill-opacity")) {
1198
- setFillOpacity(tokens[1]);
1199
-
1200
- } else if (tokens[0].equals("stroke")) {
1201
- setColor(tokens[1], false);
1202
-
1203
- } else if (tokens[0].equals("stroke-width")) {
1204
- setStrokeWeight(tokens[1]);
1205
-
1206
- } else if (tokens[0].equals("stroke-linecap")) {
1207
- setStrokeCap(tokens[1]);
1208
-
1209
- } else if (tokens[0].equals("stroke-linejoin")) {
1210
- setStrokeJoin(tokens[1]);
1211
-
1212
- } else if (tokens[0].equals("stroke-opacity")) {
1213
- setStrokeOpacity(tokens[1]);
1214
-
1215
- } else if (tokens[0].equals("opacity")) {
1216
- setOpacity(tokens[1]);
1217
-
1218
- } else {
1219
- // Other attributes are not yet implemented
1178
+ switch (tokens[0]) {
1179
+ case "fill":
1180
+ setColor(tokens[1], true);
1181
+ break;
1182
+ case "fill-opacity":
1183
+ setFillOpacity(tokens[1]);
1184
+ break;
1185
+ case "stroke":
1186
+ setColor(tokens[1], false);
1187
+ break;
1188
+ case "stroke-width":
1189
+ setStrokeWeight(tokens[1]);
1190
+ break;
1191
+ case "stroke-linecap":
1192
+ setStrokeCap(tokens[1]);
1193
+ break;
1194
+ case "stroke-linejoin":
1195
+ setStrokeJoin(tokens[1]);
1196
+ break;
1197
+ case "stroke-opacity":
1198
+ setStrokeOpacity(tokens[1]);
1199
+ break;
1200
+ case "opacity":
1201
+ setOpacity(tokens[1]);
1202
+ break;
1203
+ // Other attributes are not yet implemented
1204
+ default:
1205
+ break;
1220
1206
  }
1221
1207
  }
1222
1208
  }
1223
1209
  }
1224
1210
 
1211
+
1225
1212
  void setOpacity(String opacityText) {
1226
1213
  opacity = PApplet.parseFloat(opacityText);
1227
1214
  strokeColor = ((int) (opacity * 255)) << 24 | strokeColor & 0xFFFFFF;
1228
1215
  fillColor = ((int) (opacity * 255)) << 24 | fillColor & 0xFFFFFF;
1229
1216
  }
1230
1217
 
1218
+
1231
1219
  void setStrokeWeight(String lineweight) {
1232
1220
  strokeWeight = parseUnitSize(lineweight, svgSizeXY);
1233
1221
  }
1234
1222
 
1223
+
1235
1224
  void setStrokeOpacity(String opacityText) {
1236
1225
  strokeOpacity = PApplet.parseFloat(opacityText);
1237
1226
  strokeColor = ((int) (strokeOpacity * 255)) << 24 | strokeColor & 0xFFFFFF;
1238
1227
  }
1239
1228
 
1229
+
1240
1230
  void setStrokeJoin(String linejoin) {
1241
1231
  switch (linejoin) {
1242
- // do nothing, will inherit automatically
1232
+ // do nothing, will inherit automatically
1243
1233
  case "inherit":
1244
1234
  break;
1245
1235
  case "miter":
@@ -1256,9 +1246,10 @@ public class PShapeSVG extends PShape {
1256
1246
  }
1257
1247
  }
1258
1248
 
1249
+
1259
1250
  void setStrokeCap(String linecap) {
1260
1251
  switch (linecap) {
1261
- // do nothing, will inherit automatically
1252
+ // do nothing, will inherit automatically
1262
1253
  case "inherit":
1263
1254
  break;
1264
1255
  case "butt":
@@ -1275,11 +1266,13 @@ public class PShapeSVG extends PShape {
1275
1266
  }
1276
1267
  }
1277
1268
 
1269
+
1278
1270
  void setFillOpacity(String opacityText) {
1279
1271
  fillOpacity = PApplet.parseFloat(opacityText);
1280
1272
  fillColor = ((int) (fillOpacity * 255)) << 24 | fillColor & 0xFFFFFF;
1281
1273
  }
1282
1274
 
1275
+
1283
1276
  void setColor(String colorText, boolean isFill) {
1284
1277
  colorText = colorText.trim();
1285
1278
  int opacityMask = fillColor & 0xFF000000;
@@ -1321,10 +1314,10 @@ public class PShapeSVG extends PShape {
1321
1314
  }
1322
1315
  }
1323
1316
 
1317
+
1324
1318
  /**
1325
- * Parses the "color" datatype only, and prints an error if it is not of this
1326
- * form. http://www.w3.org/TR/SVG/types.html#DataTypeColor
1327
- *
1319
+ * Parses the "color" datatype only, and prints an error if it is not of this form.http://www.w3.org/TR/SVG/types.html#DataTypeColor
1320
+ * @param colorText
1328
1321
  * @return 0xRRGGBB (no alpha). Zero on error.
1329
1322
  */
1330
1323
  static protected int parseSimpleColor(String colorText) {
@@ -1347,28 +1340,29 @@ public class PShapeSVG extends PShape {
1347
1340
  }
1348
1341
  }
1349
1342
 
1343
+
1350
1344
  /**
1351
- * Deliberately conforms to the HTML 4.01 color spec + en-gb grey, rather than
1352
- * the (unlikely to be useful) entire 147-color system used in SVG.
1345
+ * Deliberately conforms to the HTML 4.01 color spec + en-gb grey, rather
1346
+ * than the (unlikely to be useful) entire 147-color system used in SVG.
1353
1347
  */
1354
- static protected IntDict colorNames = new IntDict(new Object[][]{
1355
- {"aqua", 0x00ffff},
1356
- {"black", 0x000000},
1357
- {"blue", 0x0000ff},
1358
- {"fuchsia", 0xff00ff},
1359
- {"gray", 0x808080},
1360
- {"grey", 0x808080},
1361
- {"green", 0x008000},
1362
- {"lime", 0x00ff00},
1363
- {"maroon", 0x800000},
1364
- {"navy", 0x000080},
1365
- {"olive", 0x808000},
1366
- {"purple", 0x800080},
1367
- {"red", 0xff0000},
1368
- {"silver", 0xc0c0c0},
1369
- {"teal", 0x008080},
1370
- {"white", 0xffffff},
1371
- {"yellow", 0xffff00}
1348
+ static protected IntDict colorNames = new IntDict(new Object[][] {
1349
+ { "aqua", 0x00ffff },
1350
+ { "black", 0x000000 },
1351
+ { "blue", 0x0000ff },
1352
+ { "fuchsia", 0xff00ff },
1353
+ { "gray", 0x808080 },
1354
+ { "grey", 0x808080 },
1355
+ { "green", 0x008000 },
1356
+ { "lime", 0x00ff00 },
1357
+ { "maroon", 0x800000 },
1358
+ { "navy", 0x000080 },
1359
+ { "olive", 0x808000 },
1360
+ { "purple", 0x800080 },
1361
+ { "red", 0xff0000 },
1362
+ { "silver", 0xc0c0c0 },
1363
+ { "teal", 0x008080 },
1364
+ { "white", 0xffffff },
1365
+ { "yellow", 0xffff00 }
1372
1366
  });
1373
1367
 
1374
1368
  /*
@@ -1393,7 +1387,8 @@ public class PShapeSVG extends PShape {
1393
1387
  colorNames.put("white", 0xffffff);
1394
1388
  colorNames.put("yellow", 0xffff00);
1395
1389
  }
1396
- */
1390
+ */
1391
+
1397
1392
  static protected int parseRGB(String what) {
1398
1393
  int leftParen = what.indexOf('(') + 1;
1399
1394
  int rightParen = what.indexOf(')');
@@ -1405,18 +1400,17 @@ public class PShapeSVG extends PShape {
1405
1400
  for (int i = 0; i < 3; i++) {
1406
1401
  rgbValue <<= 8;
1407
1402
  if (values[i].endsWith("%")) {
1408
- rgbValue |= (int) (PApplet.constrain(255 * parseFloatOrPercent(values[i]), 0, 255));
1403
+ rgbValue |= (int)(PApplet.constrain(255*parseFloatOrPercent(values[i]), 0, 255));
1409
1404
  } else {
1410
1405
  rgbValue |= PApplet.constrain(PApplet.parseInt(values[i]), 0, 255);
1411
1406
  }
1412
1407
  }
1413
- } else {
1414
- System.err.println("Could not read color \"" + what + "\".");
1415
- }
1408
+ } else System.err.println("Could not read color \"" + what + "\".");
1416
1409
 
1417
1410
  return rgbValue;
1418
1411
  }
1419
1412
 
1413
+
1420
1414
  //static protected Map<String, String> parseStyleAttributes(String style) {
1421
1415
  static protected StringDict parseStyleAttributes(String style) {
1422
1416
  //Map<String, String> table = new HashMap<String, String>();
@@ -1433,15 +1427,15 @@ public class PShapeSVG extends PShape {
1433
1427
  return table;
1434
1428
  }
1435
1429
 
1430
+
1436
1431
  /**
1437
- * Used in place of element.getFloatAttribute(a) because we can have a unit
1438
- * suffix (length or coordinate).
1439
- *
1432
+ * Used in place of element.getFloatAttribute(a) because we can
1433
+ * have a unit suffix (length or coordinate).
1440
1434
  * @param element what to parse
1441
1435
  * @param attribute name of the attribute to get
1442
- * @param relativeTo (float) Used for %. When relative to viewbox, should be
1443
- * svgWidth for horizontal dimentions, svgHeight for vertical, and svgXYSize
1444
- * for anything else.
1436
+ * @param relativeTo (float) Used for %. When relative to viewbox, should
1437
+ * be svgWidth for horizontal dimentions, svgHeight for vertical, and
1438
+ * svgXYSize for anything else.
1445
1439
  * @return unit-parsed version of the data
1446
1440
  */
1447
1441
  static protected float getFloatWithUnit(XML element, String attribute, float relativeTo) {
@@ -1449,21 +1443,22 @@ public class PShapeSVG extends PShape {
1449
1443
  return (val == null) ? 0 : parseUnitSize(val, relativeTo);
1450
1444
  }
1451
1445
 
1446
+
1452
1447
  /**
1453
- * Parse a size that may have a suffix for its units. This assumes 90dpi,
1454
- * which implies, as given in the
1455
- * <a href="http://www.w3.org/TR/SVG/coords.html#Units">units</a> spec:
1456
- * <ul>
1457
- * <li>"1pt" equals "1.25px" (and therefore 1.25 user units)
1458
- * <li>"1pc" equals "15px" (and therefore 15 user units)
1459
- * <li>"1mm" would be "3.543307px" (3.543307 user units)
1460
- * <li>"1cm" equals "35.43307px" (and therefore 35.43307 user units)
1461
- * <li>"1in" equals "90px" (and therefore 90 user units)
1462
- * </ul>
1463
- *
1464
- * @param relativeTo (float) Used for %. When relative to viewbox, should be
1465
- * svgWidth for horizontal dimentions, svgHeight for vertical, and svgXYSize
1466
- * for anything else.
1448
+ * Parse a size that may have a suffix for its units.This assumes 90dpi, which implies, as given in the
1449
+ <A HREF="http://www.w3.org/TR/SVG/coords.html#Units">units</A> spec:
1450
+ <UL>
1451
+ <LI>"1pt" equals "1.25px" (and therefore 1.25 user units)
1452
+ <LI>"1pc" equals "15px" (and therefore 15 user units)
1453
+ <LI>"1mm" would be "3.543307px" (3.543307 user units)
1454
+ <LI>"1cm" equals "35.43307px" (and therefore 35.43307 user units)
1455
+ <LI>"1in" equals "90px" (and therefore 90 user units)
1456
+ </UL>
1457
+ * @param text
1458
+ * @param relativeTo (float) Used for %. When relative to viewbox, should
1459
+ * be svgWidth for horizontal dimentions, svgHeight for vertical, and
1460
+ * svgXYSize for anything else.
1461
+ * @return
1467
1462
  */
1468
1463
  static protected float parseUnitSize(String text, float relativeTo) {
1469
1464
  int len = text.length() - 2;
@@ -1487,6 +1482,7 @@ public class PShapeSVG extends PShape {
1487
1482
  }
1488
1483
  }
1489
1484
 
1485
+
1490
1486
  static protected float parseFloatOrPercent(String text) {
1491
1487
  text = text.trim();
1492
1488
  if (text.endsWith("%")) {
@@ -1496,9 +1492,11 @@ public class PShapeSVG extends PShape {
1496
1492
  }
1497
1493
  }
1498
1494
 
1495
+
1499
1496
  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1500
- static public class Gradient extends PShapeSVG {
1501
1497
 
1498
+
1499
+ static public class Gradient extends PShapeSVG {
1502
1500
  AffineTransform transform;
1503
1501
 
1504
1502
  public float[] offset;
@@ -1513,7 +1511,8 @@ public class PShapeSVG extends PShape {
1513
1511
  color = new int[elements.length];
1514
1512
 
1515
1513
  // <stop offset="0" style="stop-color:#967348"/>
1516
- for (XML elem : elements) {
1514
+ for (int i = 0; i < elements.length; i++) {
1515
+ XML elem = elements[i];
1517
1516
  String name = elem.getName();
1518
1517
  if (name.equals("stop")) {
1519
1518
  String offsetAttr = elem.getString("offset");
@@ -1526,19 +1525,15 @@ public class PShapeSVG extends PShape {
1526
1525
  String colorStr = styles.get("stop-color");
1527
1526
  if (colorStr == null) {
1528
1527
  colorStr = elem.getString("stop-color");
1529
- if (colorStr == null) {
1530
- colorStr = "#000000";
1531
- }
1528
+ if (colorStr == null) colorStr = "#000000";
1532
1529
  }
1533
1530
  String opacityStr = styles.get("stop-opacity");
1534
1531
  if (opacityStr == null) {
1535
1532
  opacityStr = elem.getString("stop-opacity");
1536
- if (opacityStr == null) {
1537
- opacityStr = "1";
1538
- }
1533
+ if (opacityStr == null) opacityStr = "1";
1539
1534
  }
1540
1535
  int tupacity = PApplet.constrain(
1541
- (int) (PApplet.parseFloat(opacityStr) * 255), 0, 255);
1536
+ (int)(PApplet.parseFloat(opacityStr) * 255), 0, 255);
1542
1537
  color[count] = (tupacity << 24) | parseSimpleColor(colorStr);
1543
1538
  count++;
1544
1539
  }
@@ -1548,9 +1543,11 @@ public class PShapeSVG extends PShape {
1548
1543
  }
1549
1544
  }
1550
1545
 
1546
+
1551
1547
  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1552
- static public class LinearGradient extends Gradient {
1553
1548
 
1549
+
1550
+ static public class LinearGradient extends Gradient {
1554
1551
  public float x1, y1, x2, y2;
1555
1552
 
1556
1553
  public LinearGradient(PShapeSVG parent, XML properties) {
@@ -1561,8 +1558,8 @@ public class PShapeSVG extends PShape {
1561
1558
  this.x2 = getFloatWithUnit(properties, "x2", svgWidth);
1562
1559
  this.y2 = getFloatWithUnit(properties, "y2", svgHeight);
1563
1560
 
1564
- String transformStr
1565
- = properties.getString("gradientTransform");
1561
+ String transformStr =
1562
+ properties.getString("gradientTransform");
1566
1563
 
1567
1564
  if (transformStr != null) {
1568
1565
  float[] t = parseTransform(transformStr).get(null);
@@ -1579,9 +1576,11 @@ public class PShapeSVG extends PShape {
1579
1576
  }
1580
1577
  }
1581
1578
 
1579
+
1582
1580
  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1583
- static public class RadialGradient extends Gradient {
1584
1581
 
1582
+
1583
+ static public class RadialGradient extends Gradient {
1585
1584
  public float cx, cy, r;
1586
1585
 
1587
1586
  public RadialGradient(PShapeSVG parent, XML properties) {
@@ -1589,10 +1588,10 @@ public class PShapeSVG extends PShape {
1589
1588
 
1590
1589
  this.cx = getFloatWithUnit(properties, "cx", svgWidth);
1591
1590
  this.cy = getFloatWithUnit(properties, "cy", svgHeight);
1592
- this.r = getFloatWithUnit(properties, "r", svgSizeXY);
1591
+ this.r = getFloatWithUnit(properties, "r", svgSizeXY);
1593
1592
 
1594
- String transformStr
1595
- = properties.getString("gradientTransform");
1593
+ String transformStr =
1594
+ properties.getString("gradientTransform");
1596
1595
 
1597
1596
  if (transformStr != null) {
1598
1597
  float[] t = parseTransform(transformStr).get(null);
@@ -1608,8 +1607,12 @@ public class PShapeSVG extends PShape {
1608
1607
  }
1609
1608
  }
1610
1609
 
1610
+
1611
1611
  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1612
+
1613
+
1612
1614
  // static private float TEXT_QUALITY = 1;
1615
+
1613
1616
  static private PFont parseFont(XML properties) {
1614
1617
  String fontFamily = null;
1615
1618
  float size = 10;
@@ -1621,62 +1624,61 @@ public class PShapeSVG extends PShape {
1621
1624
  String[] styleTokens = PApplet.splitTokens(styleText, ";");
1622
1625
 
1623
1626
  //PApplet.println(styleTokens);
1624
- for (String styleToken : styleTokens) {
1625
- String[] tokens = PApplet.splitTokens(styleToken, ":");
1627
+ for (int i = 0; i < styleTokens.length; i++) {
1628
+ String[] tokens = PApplet.splitTokens(styleTokens[i], ":");
1626
1629
  //PApplet.println(tokens);
1630
+
1627
1631
  tokens[0] = PApplet.trim(tokens[0]);
1628
- switch (tokens[0]) {
1629
- case "font-style":
1630
- // PApplet.println("font-style: " + tokens[1]);
1631
- if (tokens[1].contains("italic")) {
1632
- italic = ITALIC;
1633
- }
1634
- break;
1632
+
1633
+ if (tokens[0].equals("font-style")) {
1634
+ // PApplet.println("font-style: " + tokens[1]);
1635
+ if (tokens[1].contains("italic")) {
1636
+ italic = ITALIC;
1637
+ }
1638
+ } else if (tokens[0].equals("font-variant")) {
1635
1639
  // PApplet.println("font-variant: " + tokens[1]);
1636
1640
  // setFillOpacity(tokens[1]);
1637
- case "font-variant":
1638
- break;
1639
- case "font-weight":
1640
- // PApplet.println("font-weight: " + tokens[1]);
1641
1641
 
1642
- if (tokens[1].contains("bold")) {
1643
- weight = BOLD;
1644
- // PApplet.println("Bold weight ! ");
1645
- }
1646
- break;
1642
+ } else if (tokens[0].equals("font-weight")) {
1643
+ // PApplet.println("font-weight: " + tokens[1]);
1644
+
1645
+ if (tokens[1].contains("bold")) {
1646
+ weight = BOLD;
1647
+ // PApplet.println("Bold weight ! ");
1648
+ }
1649
+
1650
+
1651
+ } else if (tokens[0].equals("font-stretch")) {
1647
1652
  // not supported.
1648
- case "font-stretch":
1649
- break;
1650
- case "font-size":
1651
- // PApplet.println("font-size: " + tokens[1]);
1652
- size = Float.parseFloat(tokens[1].split("px")[0]);
1653
- // PApplet.println("font-size-parsed: " + size);
1654
- break;
1655
- // not supported
1656
- case "line-height":
1657
- break;
1658
- case "font-family":
1659
- // PApplet.println("Font-family: " + tokens[1]);
1660
- fontFamily = tokens[1];
1661
- break;
1662
- // not supported
1663
- case "text-align":
1664
- break;
1665
- // not supported
1666
- case "letter-spacing":
1667
- break;
1653
+
1654
+ } else if (tokens[0].equals("font-size")) {
1655
+ // PApplet.println("font-size: " + tokens[1]);
1656
+ size = Float.parseFloat(tokens[1].split("px")[0]);
1657
+ // PApplet.println("font-size-parsed: " + size);
1658
+ } else if (tokens[0].equals("line-height")) {
1659
+ // not supported
1660
+
1661
+ } else if (tokens[0].equals("font-family")) {
1662
+ // PApplet.println("Font-family: " + tokens[1]);
1663
+ fontFamily = tokens[1];
1664
+
1665
+ } else if (tokens[0].equals("text-align")) {
1668
1666
  // not supported
1669
- case "word-spacing":
1670
- break;
1667
+
1668
+ } else if (tokens[0].equals("letter-spacing")) {
1669
+ // not supported
1670
+
1671
+ } else if (tokens[0].equals("word-spacing")) {
1672
+ // not supported
1673
+
1674
+ } else if (tokens[0].equals("writing-mode")) {
1671
1675
  // not supported
1672
- case "writing-mode":
1673
- break;
1676
+
1677
+ } else if (tokens[0].equals("text-anchor")) {
1674
1678
  // not supported
1675
- case "text-anchor":
1676
- break;
1679
+
1680
+ } else {
1677
1681
  // Other attributes are not yet implemented
1678
- default:
1679
- break;
1680
1682
  }
1681
1683
  }
1682
1684
  }
@@ -1688,8 +1690,9 @@ public class PShapeSVG extends PShape {
1688
1690
  return createFont(fontFamily, weight | italic, size, true);
1689
1691
  }
1690
1692
 
1693
+
1691
1694
  static protected PFont createFont(String name, int weight,
1692
- float size, boolean smooth) {
1695
+ float size, boolean smooth) {
1693
1696
  //System.out.println("Try to create a font of " + name + " family, " + weight);
1694
1697
  java.awt.Font baseFont = new java.awt.Font(name, weight, (int) size);
1695
1698
 
@@ -1697,15 +1700,17 @@ public class PShapeSVG extends PShape {
1697
1700
  return new PFont(baseFont.deriveFont(size), smooth, null);
1698
1701
  }
1699
1702
 
1703
+
1700
1704
  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1701
- static public class Text extends PShapeSVG {
1702
1705
 
1706
+
1707
+ static public class Text extends PShapeSVG {
1703
1708
  protected PFont font;
1704
1709
 
1705
1710
  public Text(PShapeSVG parent, XML properties) {
1706
1711
  super(parent, properties, true);
1707
1712
 
1708
- // get location
1713
+ // get location
1709
1714
  float x = Float.parseFloat(properties.getString("x"));
1710
1715
  float y = Float.parseFloat(properties.getString("y"));
1711
1716
 
@@ -1720,9 +1725,11 @@ public class PShapeSVG extends PShape {
1720
1725
  }
1721
1726
  }
1722
1727
 
1728
+
1723
1729
  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1724
- static public class LineOfText extends PShapeSVG {
1725
1730
 
1731
+
1732
+ static public class LineOfText extends PShapeSVG {
1726
1733
  String textToDisplay;
1727
1734
  PFont font;
1728
1735
 
@@ -1737,9 +1744,7 @@ public class PShapeSVG extends PShape {
1737
1744
  float parentX = Float.parseFloat(parent.element.getString("x"));
1738
1745
  float parentY = Float.parseFloat(parent.element.getString("y"));
1739
1746
 
1740
- if (matrix == null) {
1741
- matrix = new PMatrix2D();
1742
- }
1747
+ if (matrix == null) matrix = new PMatrix2D();
1743
1748
  matrix.translate(x - parentX, (y - parentY) / 2f);
1744
1749
 
1745
1750
  // get the first properties
@@ -1748,6 +1753,7 @@ public class PShapeSVG extends PShape {
1748
1753
 
1749
1754
  // cleaned up syntax but removing b/c unused [fry 190118]
1750
1755
  //boolean isLine = properties.getString("role").equals("line");
1756
+
1751
1757
  if (this.childCount > 0) {
1752
1758
  // no inline content yet.
1753
1759
  }
@@ -1773,9 +1779,11 @@ public class PShapeSVG extends PShape {
1773
1779
  }
1774
1780
  }
1775
1781
 
1782
+
1776
1783
  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1777
- static public class Font extends PShapeSVG {
1778
1784
 
1785
+
1786
+ static public class Font extends PShapeSVG {
1779
1787
  public FontFace face;
1780
1788
 
1781
1789
  public Map<String, FontGlyph> namedGlyphs;
@@ -1787,6 +1795,7 @@ public class PShapeSVG extends PShape {
1787
1795
 
1788
1796
  int horizAdvX;
1789
1797
 
1798
+
1790
1799
  public Font(PShapeSVG parent, XML properties) {
1791
1800
  super(parent, properties, false);
1792
1801
  // handle(parent, properties);
@@ -1805,44 +1814,43 @@ public class PShapeSVG extends PShape {
1805
1814
  XML elem = element1;
1806
1815
  if (null == name) {
1807
1816
  // skip it
1808
- } else {
1809
- switch (name) {
1810
- case "glyph":
1811
- FontGlyph fg = new FontGlyph(this, elem, this);
1812
- if (fg.isLegit()) {
1813
- if (fg.name != null) {
1814
- namedGlyphs.put(fg.name, fg);
1815
- }
1816
- if (fg.unicode != 0) {
1817
- unicodeGlyphs.put(fg.unicode, fg);
1818
- }
1817
+ } else switch (name) {
1818
+ case "glyph":
1819
+ FontGlyph fg = new FontGlyph(this, elem, this);
1820
+ if (fg.isLegit()) {
1821
+ if (fg.name != null) {
1822
+ namedGlyphs.put(fg.name, fg);
1819
1823
  }
1820
- glyphs[glyphCount++] = fg;
1821
- break;
1822
- case "missing-glyph":
1823
- // System.out.println("got missing glyph inside <font>");
1824
- missingGlyph = new FontGlyph(this, elem, this);
1825
- break;
1826
- case "font-face":
1827
- face = new FontFace(this, elem);
1828
- break;
1829
- default:
1830
- System.err.println("Ignoring " + name + " inside <font>");
1831
- break;
1832
- }
1824
+ if (fg.unicode != 0) {
1825
+ unicodeGlyphs.put(fg.unicode, fg);
1826
+ }
1827
+ } glyphs[glyphCount++] = fg;
1828
+ break;
1829
+ case "missing-glyph":
1830
+ // System.out.println("got missing glyph inside <font>");
1831
+ missingGlyph = new FontGlyph(this, elem, this);
1832
+ break;
1833
+ case "font-face":
1834
+ face = new FontFace(this, elem);
1835
+ break;
1836
+ default:
1837
+ System.err.println("Ignoring " + name + " inside <font>");
1838
+ break;
1833
1839
  }
1834
1840
  }
1835
1841
  }
1836
1842
 
1843
+
1837
1844
  protected void drawShape() {
1838
1845
  // does nothing for fonts
1839
1846
  }
1840
1847
 
1848
+
1841
1849
  public void drawString(PGraphics g, String str, float x, float y, float size) {
1842
1850
  // 1) scale by the 1.0/unitsPerEm
1843
1851
  // 2) scale up by a font size
1844
1852
  g.pushMatrix();
1845
- float s = size / face.unitsPerEm;
1853
+ float s = size / face.unitsPerEm;
1846
1854
  //System.out.println("scale is " + s);
1847
1855
  // swap y coord at the same time, since fonts have y=0 at baseline
1848
1856
  g.translate(x, y);
@@ -1862,18 +1870,18 @@ public class PShapeSVG extends PShape {
1862
1870
  g.popMatrix();
1863
1871
  }
1864
1872
 
1873
+
1865
1874
  public void drawChar(PGraphics g, char c, float x, float y, float size) {
1866
1875
  g.pushMatrix();
1867
- float s = size / face.unitsPerEm;
1876
+ float s = size / face.unitsPerEm;
1868
1877
  g.translate(x, y);
1869
1878
  g.scale(s, -s);
1870
1879
  FontGlyph fg = unicodeGlyphs.get(c);
1871
- if (fg != null) {
1872
- g.shape(fg);
1873
- }
1880
+ if (fg != null) g.shape(fg);
1874
1881
  g.popMatrix();
1875
1882
  }
1876
1883
 
1884
+
1877
1885
  public float textWidth(String str, float size) {
1878
1886
  float w = 0;
1879
1887
  char[] c = str.toCharArray();
@@ -1888,9 +1896,11 @@ public class PShapeSVG extends PShape {
1888
1896
  }
1889
1897
  }
1890
1898
 
1899
+
1891
1900
  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1892
- static class FontFace extends PShapeSVG {
1893
1901
 
1902
+
1903
+ static class FontFace extends PShapeSVG {
1894
1904
  int horizOriginX; // dflt 0
1895
1905
  int horizOriginY; // dflt 0
1896
1906
  // int horizAdvX; // no dflt?
@@ -1910,20 +1920,24 @@ public class PShapeSVG extends PShape {
1910
1920
  int underlinePosition;
1911
1921
  //String unicodeRange; // gonna ignore for now
1912
1922
 
1923
+
1913
1924
  public FontFace(PShapeSVG parent, XML properties) {
1914
1925
  super(parent, properties, true);
1915
1926
 
1916
1927
  unitsPerEm = properties.getInt("units-per-em", 1000);
1917
1928
  }
1918
1929
 
1930
+
1919
1931
  protected void drawShape() {
1920
1932
  // nothing to draw in the font face attribute
1921
1933
  }
1922
1934
  }
1923
1935
 
1936
+
1924
1937
  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1925
- static public class FontGlyph extends PShapeSVG { // extends Path
1926
1938
 
1939
+
1940
+ static public class FontGlyph extends PShapeSVG { // extends Path
1927
1941
  public String name;
1928
1942
  char unicode;
1929
1943
  int horizAdvX;
@@ -1940,8 +1954,8 @@ public class PShapeSVG extends PShape {
1940
1954
  unicode = u.charAt(0);
1941
1955
  //System.out.println("unicode for " + name + " is " + u);
1942
1956
  } else {
1943
- System.err.println("unicode for " + name
1944
- + " is more than one char: " + u);
1957
+ System.err.println("unicode for " + name +
1958
+ " is more than one char: " + u);
1945
1959
  }
1946
1960
  }
1947
1961
  if (properties.hasAttribute("horiz-adv-x")) {
@@ -1951,22 +1965,28 @@ public class PShapeSVG extends PShape {
1951
1965
  }
1952
1966
  }
1953
1967
 
1968
+
1954
1969
  protected boolean isLegit() { // TODO need a better way to handle this...
1955
1970
  return vertexCount != 0;
1956
1971
  }
1957
1972
  }
1958
1973
 
1974
+
1959
1975
  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1976
+
1977
+
1960
1978
  /**
1961
- * Get a particular element based on its SVG ID. When editing SVG by hand,
1962
- * this is the id="" tag on any SVG element. When editing from Illustrator,
1963
- * these IDs can be edited by expanding the layers palette. The names used in
1964
- * the layers palette, both for the layers or the shapes and groups beneath
1965
- * them can be used here.
1966
- * <PRE>
1979
+ * Get a particular element based on its SVG ID.When editing SVG by hand,
1980
+ this is the id="" tag on any SVG element.When editing from Illustrator,
1981
+ these IDs can be edited by expanding the layers palette. The names used
1982
+ in the layers palette, both for the layers or the shapes and groups
1983
+ beneath them can be used here.
1984
+ <PRE>
1967
1985
  * // This code grabs "Layer 3" and the shapes beneath it.
1968
1986
  * PShape layer3 = svg.getChild("Layer 3");
1969
1987
  * </PRE>
1988
+ * @param name
1989
+ * @return
1970
1990
  */
1971
1991
  @Override
1972
1992
  public PShape getChild(String name) {
@@ -1986,6 +2006,7 @@ public class PShapeSVG extends PShape {
1986
2006
  return found;
1987
2007
  }
1988
2008
 
2009
+
1989
2010
  /**
1990
2011
  * Prints out the SVG document. Useful for parsing.
1991
2012
  */