propane 3.5.0-java → 3.6.0-java

Sign up to get free protection for your applications and to get access to all the features.
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
  */