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.
- checksums.yaml +4 -4
- data/.mvn/extensions.xml +1 -1
- data/.mvn/wrapper/MavenWrapperDownloader.java +1 -1
- data/.mvn/wrapper/maven-wrapper.properties +2 -2
- data/.travis.yml +1 -1
- data/CHANGELOG.md +3 -1
- data/README.md +5 -13
- data/Rakefile +1 -1
- data/lib/propane.rb +2 -1
- data/lib/propane/helper_methods.rb +0 -1
- data/lib/propane/runner.rb +2 -0
- data/lib/propane/version.rb +1 -1
- data/pom.rb +43 -43
- data/pom.xml +4 -4
- data/propane.gemspec +4 -3
- data/src/main/java/japplemenubar/JAppleMenuBar.java +3 -3
- data/src/main/java/processing/awt/PGraphicsJava2D.java +8 -17
- data/src/main/java/processing/awt/PImageAWT.java +123 -6
- data/src/main/java/processing/awt/PShapeJava2D.java +1 -0
- data/src/main/java/processing/awt/PSurfaceAWT.java +9 -7
- data/src/main/java/processing/awt/ShimAWT.java +2 -1
- data/src/main/java/processing/core/PApplet.java +4605 -6014
- data/src/main/java/processing/core/PConstants.java +5 -5
- data/src/main/java/processing/core/PFont.java +5 -17
- data/src/main/java/processing/core/PGraphics.java +308 -320
- data/src/main/java/processing/core/PImage.java +1440 -1537
- data/src/main/java/processing/core/PMatrix2D.java +24 -7
- data/src/main/java/processing/core/PMatrix3D.java +12 -5
- data/src/main/java/processing/core/PShape.java +155 -173
- data/src/main/java/processing/core/PShapeOBJ.java +2 -0
- data/src/main/java/processing/core/PShapeSVG.java +632 -611
- data/src/main/java/processing/core/PSurface.java +15 -10
- data/src/main/java/processing/core/PSurfaceNone.java +8 -4
- data/src/main/java/processing/core/PVector.java +35 -28
- data/src/main/java/processing/data/Table.java +20 -20
- data/src/main/java/processing/data/XML.java +1 -1
- data/src/main/java/processing/event/Event.java +1 -1
- data/src/main/java/processing/event/MouseEvent.java +7 -6
- data/src/main/java/processing/javafx/PGraphicsFX2D.java +20 -345
- data/src/main/java/processing/javafx/PSurfaceFX.java +127 -125
- data/src/main/java/processing/opengl/FrameBuffer.java +2 -4
- data/src/main/java/processing/opengl/LinePath.java +4 -0
- data/src/main/java/processing/opengl/LineStroker.java +2 -6
- data/src/main/java/processing/opengl/PGL.java +72 -45
- data/src/main/java/processing/opengl/PGraphicsOpenGL.java +106 -60
- data/src/main/java/processing/opengl/PJOGL.java +15 -3
- data/src/main/java/processing/opengl/PShader.java +26 -47
- data/src/main/java/processing/opengl/PShapeOpenGL.java +1041 -1001
- data/src/main/java/processing/opengl/PSurfaceJOGL.java +211 -208
- data/src/main/java/processing/opengl/Texture.java +7 -4
- data/src/main/java/processing/opengl/VertexBuffer.java +2 -2
- data/vendors/Rakefile +22 -33
- 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
|
42
|
-
* Instead, use loadShape() and methods like it, which will make
|
43
|
-
* class. Using this class directly will cause your code to break
|
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.
|
47
|
-
* vector format so it allows for "infinite" resolution and relatively
|
48
|
-
* file sizes. Most modern media software can view SVG files, including
|
49
|
-
* products, Firefox, etc. Illustrator and Inkscape can edit SVG files.
|
50
|
-
* SVG specification <
|
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.
|
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
|
-
* <
|
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
|
64
|
-
* full SVG import is still a considerable amount of work. Wiring it to
|
65
|
-
* wouldn't be too bad, but using it with OpenGL, JavaFX, and features
|
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
|
69
|
-
* specific subset of SVG, for instance the simpler SVG profiles known as
|
70
|
-
* <
|
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:
|
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
|
151
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
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
|
-
|
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.
|
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
|
-
|
371
|
+
return new Text(this, elem);
|
380
372
|
|
381
373
|
} else if (name.equals("tspan")) {
|
382
|
-
|
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
|
-
|
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
|
447
|
-
params[3] = ry
|
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.
|
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
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
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
|
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
|
-
|
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
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
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
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
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
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
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
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
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
|
-
//
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
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
|
-
//
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
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
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
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
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
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
|
-
//
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
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
|
-
|
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
|
-
//
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
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
|
-
//
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
float
|
847
|
-
float
|
848
|
-
|
849
|
-
|
850
|
-
|
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
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
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
|
-
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
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
|
-
|
939
|
-
|
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
|
-
|
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,
|
975
|
-
|
976
|
-
|
977
|
-
|
978
|
-
|
979
|
-
if (x1 == x2 && y1 == y2)
|
980
|
-
|
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),
|
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
|
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
|
-
|
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
|
-
|
1009
|
-
cxr =
|
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,
|
1020
|
-
float tx = (-x1r - cxr) / rx,
|
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
|
-
|
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),
|
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),
|
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
|
-
|
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
|
1071
|
-
* rotated relative to the SVG definition, so parameters are rearranged
|
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
|
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,
|
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],
|
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,
|
1115
|
+
return new PMatrix2D(1, 0, 1, PApplet.tan(m[0]), 0, 0);
|
1133
1116
|
case "skewY":
|
1134
|
-
return new PMatrix2D(1, 0, 1,
|
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
|
-
|
1195
|
-
|
1196
|
-
|
1197
|
-
|
1198
|
-
|
1199
|
-
|
1200
|
-
|
1201
|
-
|
1202
|
-
|
1203
|
-
|
1204
|
-
|
1205
|
-
|
1206
|
-
|
1207
|
-
|
1208
|
-
|
1209
|
-
|
1210
|
-
|
1211
|
-
|
1212
|
-
|
1213
|
-
|
1214
|
-
|
1215
|
-
|
1216
|
-
|
1217
|
-
|
1218
|
-
|
1219
|
-
|
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
|
-
|
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
|
-
|
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
|
-
*
|
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
|
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",
|
1356
|
-
{"black",
|
1357
|
-
{"blue",
|
1358
|
-
{"fuchsia", 0xff00ff},
|
1359
|
-
{"gray",
|
1360
|
-
{"grey",
|
1361
|
-
{"green",
|
1362
|
-
{"lime",
|
1363
|
-
{"maroon",
|
1364
|
-
{"navy",
|
1365
|
-
{"olive",
|
1366
|
-
{"purple",
|
1367
|
-
{"red",
|
1368
|
-
{"silver",
|
1369
|
-
{"teal",
|
1370
|
-
{"white",
|
1371
|
-
{"yellow",
|
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)
|
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
|
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
|
1443
|
-
* svgWidth for horizontal dimentions, svgHeight for vertical, and
|
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.
|
1454
|
-
|
1455
|
-
|
1456
|
-
|
1457
|
-
|
1458
|
-
|
1459
|
-
|
1460
|
-
|
1461
|
-
|
1462
|
-
*
|
1463
|
-
*
|
1464
|
-
*
|
1465
|
-
*
|
1466
|
-
*
|
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 (
|
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
|
-
|
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
|
-
|
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
|
1591
|
+
this.r = getFloatWithUnit(properties, "r", svgSizeXY);
|
1593
1592
|
|
1594
|
-
String transformStr
|
1595
|
-
|
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 (
|
1625
|
-
String[] tokens = PApplet.splitTokens(
|
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
|
-
|
1629
|
-
|
1630
|
-
|
1631
|
-
|
1632
|
-
|
1633
|
-
|
1634
|
-
|
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
|
-
|
1643
|
-
|
1644
|
-
|
1645
|
-
|
1646
|
-
|
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
|
-
|
1649
|
-
|
1650
|
-
|
1651
|
-
|
1652
|
-
|
1653
|
-
|
1654
|
-
|
1655
|
-
|
1656
|
-
|
1657
|
-
|
1658
|
-
|
1659
|
-
|
1660
|
-
|
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
|
-
|
1670
|
-
|
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
|
-
|
1673
|
-
|
1676
|
+
|
1677
|
+
} else if (tokens[0].equals("text-anchor")) {
|
1674
1678
|
// not supported
|
1675
|
-
|
1676
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
1810
|
-
|
1811
|
-
|
1812
|
-
if (fg.
|
1813
|
-
|
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
|
-
|
1821
|
-
|
1822
|
-
|
1823
|
-
|
1824
|
-
|
1825
|
-
|
1826
|
-
|
1827
|
-
|
1828
|
-
|
1829
|
-
|
1830
|
-
|
1831
|
-
|
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 =
|
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 =
|
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
|
-
|
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.
|
1962
|
-
|
1963
|
-
|
1964
|
-
|
1965
|
-
|
1966
|
-
|
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
|
*/
|