propane 3.10.0-java → 3.11.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (163) hide show
  1. checksums.yaml +4 -4
  2. data/.mvn/wrapper/maven-wrapper.properties +1 -1
  3. data/CHANGELOG.md +2 -0
  4. data/README.md +7 -7
  5. data/lib/propane/app.rb +2 -5
  6. data/lib/propane/helper_methods.rb +6 -6
  7. data/lib/propane/version.rb +1 -1
  8. data/lib/{propane-3.10.0.jar → propane-3.11.0.jar} +0 -0
  9. data/pom.rb +6 -6
  10. data/pom.xml +6 -6
  11. data/propane.gemspec +3 -3
  12. data/src/main/java/monkstone/noise/OpenSimplex2F.java +838 -737
  13. data/src/main/java/monkstone/vecmath/vec2/Vec2.java +8 -13
  14. data/src/main/java/monkstone/vecmath/vec3/Vec3.java +14 -28
  15. data/src/main/java/processing/awt/PImageAWT.java +6 -4
  16. data/src/main/java/processing/core/PApplet.java +71 -59
  17. data/src/main/java/processing/core/PImage.java +14 -14
  18. data/src/main/java/processing/opengl/PGraphicsOpenGL.java +13 -13
  19. data/src/main/java/processing/opengl/PShader.java +1 -6
  20. data/src/main/java/processing/opengl/PSurfaceJOGL.java +6 -6
  21. data/{lib/java/processing/opengl → src/main/resources}/cursors/arrow.png +0 -0
  22. data/{lib/java/processing/opengl → src/main/resources}/cursors/cross.png +0 -0
  23. data/{lib/java/processing/opengl → src/main/resources}/cursors/hand.png +0 -0
  24. data/{lib/java/processing/opengl → src/main/resources}/cursors/license.txt +0 -0
  25. data/{lib/java/processing/opengl → src/main/resources}/cursors/move.png +0 -0
  26. data/{lib/java/processing/opengl → src/main/resources}/cursors/text.png +0 -0
  27. data/{lib/java/processing/opengl → src/main/resources}/cursors/wait.png +0 -0
  28. data/{lib/java/processing/opengl → src/main/resources}/shaders/ColorFrag.glsl +0 -0
  29. data/{lib/java/processing/opengl → src/main/resources}/shaders/ColorVert.glsl +0 -0
  30. data/{lib/java/processing/opengl → src/main/resources}/shaders/LightFrag.glsl +0 -0
  31. data/{lib/java/processing/opengl → src/main/resources}/shaders/LightVert.glsl +0 -0
  32. data/{lib/java/processing/opengl → src/main/resources}/shaders/LineFrag.glsl +0 -0
  33. data/{lib/java/processing/opengl → src/main/resources}/shaders/LineVert.glsl +0 -0
  34. data/{lib/java/processing/opengl → src/main/resources}/shaders/MaskFrag.glsl +0 -0
  35. data/{lib/java/processing/opengl → src/main/resources}/shaders/PointFrag.glsl +0 -0
  36. data/{lib/java/processing/opengl → src/main/resources}/shaders/PointVert.glsl +0 -0
  37. data/{lib/java/processing/opengl → src/main/resources}/shaders/TexFrag.glsl +0 -0
  38. data/{lib/java/processing/opengl → src/main/resources}/shaders/TexLightFrag.glsl +0 -0
  39. data/{lib/java/processing/opengl → src/main/resources}/shaders/TexLightVert.glsl +0 -0
  40. data/{lib/java/processing/opengl → src/main/resources}/shaders/TexVert.glsl +0 -0
  41. data/test/test_helper.rb +1 -0
  42. data/vendors/Rakefile +1 -1
  43. metadata +29 -155
  44. data/lib/java/japplemenubar/JAppleMenuBar.java +0 -88
  45. data/lib/java/japplemenubar/libjAppleMenuBar.jnilib +0 -0
  46. data/lib/java/monkstone/ColorUtil.java +0 -127
  47. data/lib/java/monkstone/MathToolModule.java +0 -287
  48. data/lib/java/monkstone/PropaneLibrary.java +0 -46
  49. data/lib/java/monkstone/core/LibraryProxy.java +0 -136
  50. data/lib/java/monkstone/fastmath/DegLutTables.java +0 -111
  51. data/lib/java/monkstone/fastmath/Deglut.java +0 -71
  52. data/lib/java/monkstone/fastmath/package-info.java +0 -6
  53. data/lib/java/monkstone/filechooser/Chooser.java +0 -39
  54. data/lib/java/monkstone/noise/FastTerrain.java +0 -874
  55. data/lib/java/monkstone/noise/Noise.java +0 -90
  56. data/lib/java/monkstone/noise/NoiseGenerator.java +0 -75
  57. data/lib/java/monkstone/noise/NoiseMode.java +0 -28
  58. data/lib/java/monkstone/noise/OpenSimplex2F.java +0 -881
  59. data/lib/java/monkstone/noise/OpenSimplex2S.java +0 -1106
  60. data/lib/java/monkstone/noise/SmoothTerrain.java +0 -1099
  61. data/lib/java/monkstone/slider/CustomHorizontalSlider.java +0 -164
  62. data/lib/java/monkstone/slider/CustomVerticalSlider.java +0 -178
  63. data/lib/java/monkstone/slider/SimpleHorizontalSlider.java +0 -145
  64. data/lib/java/monkstone/slider/SimpleSlider.java +0 -166
  65. data/lib/java/monkstone/slider/SimpleVerticalSlider.java +0 -157
  66. data/lib/java/monkstone/slider/Slider.java +0 -61
  67. data/lib/java/monkstone/slider/SliderBar.java +0 -245
  68. data/lib/java/monkstone/slider/SliderGroup.java +0 -56
  69. data/lib/java/monkstone/slider/WheelHandler.java +0 -35
  70. data/lib/java/monkstone/vecmath/GfxRender.java +0 -86
  71. data/lib/java/monkstone/vecmath/JRender.java +0 -56
  72. data/lib/java/monkstone/vecmath/ShapeRender.java +0 -87
  73. data/lib/java/monkstone/vecmath/package-info.java +0 -20
  74. data/lib/java/monkstone/vecmath/vec2/Vec2.java +0 -802
  75. data/lib/java/monkstone/vecmath/vec2/package-info.java +0 -6
  76. data/lib/java/monkstone/vecmath/vec3/Vec3.java +0 -727
  77. data/lib/java/monkstone/vecmath/vec3/package-info.java +0 -6
  78. data/lib/java/monkstone/videoevent/CaptureEvent.java +0 -27
  79. data/lib/java/monkstone/videoevent/MovieEvent.java +0 -32
  80. data/lib/java/monkstone/videoevent/package-info.java +0 -20
  81. data/lib/java/processing/awt/PGraphicsJava2D.java +0 -3040
  82. data/lib/java/processing/awt/PImageAWT.java +0 -377
  83. data/lib/java/processing/awt/PShapeJava2D.java +0 -387
  84. data/lib/java/processing/awt/PSurfaceAWT.java +0 -1581
  85. data/lib/java/processing/awt/ShimAWT.java +0 -581
  86. data/lib/java/processing/core/PApplet.java +0 -15156
  87. data/lib/java/processing/core/PConstants.java +0 -523
  88. data/lib/java/processing/core/PFont.java +0 -1126
  89. data/lib/java/processing/core/PGraphics.java +0 -8600
  90. data/lib/java/processing/core/PImage.java +0 -3377
  91. data/lib/java/processing/core/PMatrix.java +0 -208
  92. data/lib/java/processing/core/PMatrix2D.java +0 -562
  93. data/lib/java/processing/core/PMatrix3D.java +0 -890
  94. data/lib/java/processing/core/PShape.java +0 -3561
  95. data/lib/java/processing/core/PShapeOBJ.java +0 -483
  96. data/lib/java/processing/core/PShapeSVG.java +0 -2016
  97. data/lib/java/processing/core/PStyle.java +0 -63
  98. data/lib/java/processing/core/PSurface.java +0 -198
  99. data/lib/java/processing/core/PSurfaceNone.java +0 -431
  100. data/lib/java/processing/core/PVector.java +0 -1066
  101. data/lib/java/processing/core/ThinkDifferent.java +0 -115
  102. data/lib/java/processing/data/DoubleDict.java +0 -850
  103. data/lib/java/processing/data/DoubleList.java +0 -928
  104. data/lib/java/processing/data/FloatDict.java +0 -847
  105. data/lib/java/processing/data/FloatList.java +0 -936
  106. data/lib/java/processing/data/IntDict.java +0 -807
  107. data/lib/java/processing/data/IntList.java +0 -936
  108. data/lib/java/processing/data/JSONArray.java +0 -1260
  109. data/lib/java/processing/data/JSONObject.java +0 -2282
  110. data/lib/java/processing/data/JSONTokener.java +0 -435
  111. data/lib/java/processing/data/LongDict.java +0 -802
  112. data/lib/java/processing/data/LongList.java +0 -937
  113. data/lib/java/processing/data/Sort.java +0 -46
  114. data/lib/java/processing/data/StringDict.java +0 -613
  115. data/lib/java/processing/data/StringList.java +0 -800
  116. data/lib/java/processing/data/Table.java +0 -4936
  117. data/lib/java/processing/data/TableRow.java +0 -198
  118. data/lib/java/processing/data/XML.java +0 -1156
  119. data/lib/java/processing/dxf/RawDXF.java +0 -404
  120. data/lib/java/processing/event/Event.java +0 -125
  121. data/lib/java/processing/event/KeyEvent.java +0 -70
  122. data/lib/java/processing/event/MouseEvent.java +0 -114
  123. data/lib/java/processing/event/TouchEvent.java +0 -57
  124. data/lib/java/processing/javafx/PGraphicsFX2D.java +0 -32
  125. data/lib/java/processing/javafx/PSurfaceFX.java +0 -173
  126. data/lib/java/processing/net/Client.java +0 -744
  127. data/lib/java/processing/net/Server.java +0 -388
  128. data/lib/java/processing/opengl/FontTexture.java +0 -378
  129. data/lib/java/processing/opengl/FrameBuffer.java +0 -513
  130. data/lib/java/processing/opengl/LinePath.java +0 -627
  131. data/lib/java/processing/opengl/LineStroker.java +0 -681
  132. data/lib/java/processing/opengl/PGL.java +0 -3483
  133. data/lib/java/processing/opengl/PGraphics2D.java +0 -615
  134. data/lib/java/processing/opengl/PGraphics3D.java +0 -281
  135. data/lib/java/processing/opengl/PGraphicsOpenGL.java +0 -13753
  136. data/lib/java/processing/opengl/PJOGL.java +0 -2008
  137. data/lib/java/processing/opengl/PShader.java +0 -1484
  138. data/lib/java/processing/opengl/PShapeOpenGL.java +0 -5269
  139. data/lib/java/processing/opengl/PSurfaceJOGL.java +0 -1385
  140. data/lib/java/processing/opengl/Texture.java +0 -1696
  141. data/lib/java/processing/opengl/VertexBuffer.java +0 -88
  142. data/lib/java/processing/pdf/PGraphicsPDF.java +0 -581
  143. data/lib/java/processing/svg/PGraphicsSVG.java +0 -378
  144. data/src/main/java/processing/opengl/cursors/arrow.png +0 -0
  145. data/src/main/java/processing/opengl/cursors/cross.png +0 -0
  146. data/src/main/java/processing/opengl/cursors/hand.png +0 -0
  147. data/src/main/java/processing/opengl/cursors/license.txt +0 -27
  148. data/src/main/java/processing/opengl/cursors/move.png +0 -0
  149. data/src/main/java/processing/opengl/cursors/text.png +0 -0
  150. data/src/main/java/processing/opengl/cursors/wait.png +0 -0
  151. data/src/main/java/processing/opengl/shaders/ColorFrag.glsl +0 -32
  152. data/src/main/java/processing/opengl/shaders/ColorVert.glsl +0 -34
  153. data/src/main/java/processing/opengl/shaders/LightFrag.glsl +0 -33
  154. data/src/main/java/processing/opengl/shaders/LightVert.glsl +0 -151
  155. data/src/main/java/processing/opengl/shaders/LineFrag.glsl +0 -32
  156. data/src/main/java/processing/opengl/shaders/LineVert.glsl +0 -100
  157. data/src/main/java/processing/opengl/shaders/MaskFrag.glsl +0 -40
  158. data/src/main/java/processing/opengl/shaders/PointFrag.glsl +0 -32
  159. data/src/main/java/processing/opengl/shaders/PointVert.glsl +0 -56
  160. data/src/main/java/processing/opengl/shaders/TexFrag.glsl +0 -37
  161. data/src/main/java/processing/opengl/shaders/TexLightFrag.glsl +0 -37
  162. data/src/main/java/processing/opengl/shaders/TexLightVert.glsl +0 -157
  163. data/src/main/java/processing/opengl/shaders/TexVert.glsl +0 -38
@@ -1,2016 +0,0 @@
1
- /* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
2
-
3
- /*
4
- Part of the Processing project - http://processing.org
5
-
6
- Copyright (c) 2012-15 The Processing Foundation
7
- Copyright (c) 2006-12 Ben Fry and Casey Reas
8
- Copyright (c) 2004-06 Michael Chang
9
-
10
- This library is free software; you can redistribute it and/or
11
- modify it under the terms of the GNU Lesser General Public
12
- License version 2.1 as published by the Free Software Foundation.
13
-
14
- This library is distributed in the hope that it will be useful,
15
- but WITHOUT ANY WARRANTY; without even the implied warranty of
16
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17
- Lesser General Public License for more details.
18
-
19
- You should have received a copy of the GNU Lesser General
20
- Public License along with this library; if not, write to the
21
- Free Software Foundation, Inc., 59 Temple Place, Suite 330,
22
- Boston, MA 02111-1307 USA
23
- */
24
-
25
- package processing.core;
26
-
27
- import static java.awt.Font.BOLD;
28
- import static java.awt.Font.ITALIC;
29
- import static java.awt.Font.PLAIN;
30
- import processing.data.*;
31
-
32
- // TODO replace these with PMatrix2D
33
- import java.awt.geom.AffineTransform;
34
- import java.awt.geom.Point2D;
35
-
36
- import java.util.Map;
37
- import java.util.HashMap;
38
- import java.util.regex.Matcher;
39
- import java.util.regex.Pattern;
40
-
41
-
42
- /**
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.
47
- * <p>
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>.
53
- * <p>
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
56
- * enough to be included with applets, meaning that its download size should be
57
- * in the neighborhood of 25-30 Kb. Though we're far less limited nowadays on
58
- * size constraints, we remain extremely limited in terms of time, and do not
59
- * have volunteers who are available to maintain a larger SVG library.
60
- * <p>
61
- * For more sophisticated import/export, consider the
62
- * <A HREF="http://xmlgraphics.apache.org/batik/">Batik</A>
63
- * library from the Apache Software Foundation.
64
- * <p>
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.
69
- * <p>
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.
74
- *
75
- * <p> <hr noshade> <p>
76
- *
77
- * A minimal example program using SVG:
78
- * (assuming a working moo.svg is in your data folder)
79
- *
80
- * <PRE>
81
- * PShape moo;
82
- *
83
- * void setup() {
84
- * size(400, 400);
85
- * moo = loadShape("moo.svg");
86
- * }
87
- * void draw() {
88
- * background(255);
89
- * shape(moo, mouseX, mouseY);
90
- * }
91
- * </PRE>
92
- */
93
- public class PShapeSVG extends PShape {
94
- XML element;
95
-
96
- /// Values between 0 and 1.
97
- protected float opacity;
98
- float strokeOpacity;
99
- float fillOpacity;
100
-
101
- /** Width of containing SVG (used for percentages). */
102
- protected float svgWidth;
103
-
104
- /** Height of containing SVG (used for percentages). */
105
- protected float svgHeight;
106
-
107
- /** √((w² + h²)/2) of containing SVG (used for percentages). */
108
- protected float svgSizeXY;
109
-
110
- protected Gradient strokeGradient;
111
- String strokeName; // id of another object, gradients only?
112
-
113
- protected Gradient fillGradient;
114
- String fillName; // id of another object
115
-
116
-
117
- /**
118
- * Initializes a new SVG object from the given XML object.
119
- * @param svg
120
- */
121
- public PShapeSVG(XML svg) {
122
- this(null, svg, true);
123
-
124
- if (!svg.getName().equals("svg")) {
125
- if (svg.getName().toLowerCase().equals("html")) {
126
- // Common case is that files aren't downloaded properly
127
- throw new RuntimeException("This appears to be a web page, not an SVG file.");
128
- } else {
129
- throw new RuntimeException("The root node is not <svg>, it's <" + svg.getName() + ">");
130
- }
131
- }
132
- }
133
-
134
-
135
- protected PShapeSVG(PShapeSVG parent, XML properties, boolean parseKids) {
136
- setParent(parent);
137
-
138
- // Need to get width/height in early.
139
- if (properties.getName().equals("svg")) {
140
- String unitWidth = properties.getString("width");
141
- String unitHeight = properties.getString("height");
142
-
143
- // Can't handle width/height as percentages easily. I'm just going
144
- // to put in 100 as a dummy value, beacuse this means that it will
145
- // come out as a reasonable value.
146
- if (unitWidth != null) width = parseUnitSize(unitWidth, 100);
147
- if (unitHeight != null) height = parseUnitSize(unitHeight, 100);
148
-
149
- String viewBoxStr = properties.getString("viewBox");
150
- if (viewBoxStr != null) {
151
- float[] viewBox = PApplet.parseFloat(PApplet.splitTokens(viewBoxStr));
152
- if (unitWidth == null || unitHeight == null) {
153
- // Not proper parsing of the viewBox, but will cover us for cases where
154
- // the width and height of the object is not specified.
155
- width = viewBox[2];
156
- height = viewBox[3];
157
- } else {
158
- // http://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute
159
- // TODO: preserveAspectRatio.
160
- if (matrix == null) matrix = new PMatrix2D();
161
- matrix.scale(width/viewBox[2], height/viewBox[3]);
162
- matrix.translate(-viewBox[0], -viewBox[1]);
163
- }
164
- }
165
-
166
- // Negative size is illegal.
167
- if (width < 0 || height < 0)
168
- throw new RuntimeException("<svg>: width (" + width +
169
- ") and height (" + height + ") must not be negative.");
170
-
171
- // It's technically valid to have width or height == 0. Not specified at
172
- // all is what to test for.
173
- if ((unitWidth == null || unitHeight == null) && viewBoxStr == null) {
174
- //throw new RuntimeException("width/height not specified");
175
- PGraphics.showWarning("The width and/or height is not " +
176
- "readable in the <svg> tag of this file.");
177
- // For the spec, the default is 100% and 100%. For purposes
178
- // here, insert a dummy value because this is prolly just a
179
- // font or something for which the w/h doesn't matter.
180
- width = 1;
181
- height = 1;
182
- }
183
-
184
- svgWidth = width;
185
- svgHeight = height;
186
- svgSizeXY = PApplet.sqrt((svgWidth*svgWidth + svgHeight*svgHeight)/2.0f);
187
- }
188
-
189
- element = properties;
190
- name = properties.getString("id");
191
- // @#$(* adobe illustrator mangles names of objects when re-saving
192
- if (name != null) {
193
- while (true) {
194
- String[] m = PApplet.match(name, "_x([A-Za-z0-9]{2})_");
195
- if (m == null) break;
196
- char repair = (char) PApplet.unhex(m[1]);
197
- name = name.replace(m[0], "" + repair);
198
- }
199
- }
200
-
201
- String displayStr = properties.getString("display", "inline");
202
- visible = !displayStr.equals("none");
203
-
204
- String transformStr = properties.getString("transform");
205
- if (transformStr != null) {
206
- if (matrix == null) {
207
- matrix = parseTransform(transformStr);
208
- } else {
209
- matrix.preApply(parseTransform(transformStr));
210
- }
211
- }
212
-
213
- if (parseKids) {
214
- parseColors(properties);
215
- parseChildren(properties);
216
- }
217
- }
218
-
219
-
220
- // Broken out so that subclasses can copy any additional variables
221
- // (i.e. fillGradientPaint and strokeGradientPaint)
222
- protected void setParent(PShapeSVG parent) {
223
- // Need to set this so that findChild() works.
224
- // Otherwise 'parent' is null until addChild() is called later.
225
- this.parent = parent;
226
-
227
- if (parent == null) {
228
- // set values to their defaults according to the SVG spec
229
- stroke = false;
230
- strokeColor = 0xff000000;
231
- strokeWeight = 1;
232
- strokeCap = PConstants.SQUARE; // equivalent to BUTT in svg spec
233
- strokeJoin = PConstants.MITER;
234
- strokeGradient = null;
235
- // strokeGradientPaint = null;
236
- strokeName = null;
237
-
238
- fill = true;
239
- fillColor = 0xff000000;
240
- fillGradient = null;
241
- // fillGradientPaint = null;
242
- fillName = null;
243
-
244
- //hasTransform = false;
245
- //transformation = null; //new float[] { 1, 0, 0, 1, 0, 0 };
246
-
247
- // svgWidth, svgHeight, and svgXYSize done below.
248
-
249
- strokeOpacity = 1;
250
- fillOpacity = 1;
251
- opacity = 1;
252
-
253
- } else {
254
- stroke = parent.stroke;
255
- strokeColor = parent.strokeColor;
256
- strokeWeight = parent.strokeWeight;
257
- strokeCap = parent.strokeCap;
258
- strokeJoin = parent.strokeJoin;
259
- strokeGradient = parent.strokeGradient;
260
- // strokeGradientPaint = parent.strokeGradientPaint;
261
- strokeName = parent.strokeName;
262
-
263
- fill = parent.fill;
264
- fillColor = parent.fillColor;
265
- fillGradient = parent.fillGradient;
266
- // fillGradientPaint = parent.fillGradientPaint;
267
- fillName = parent.fillName;
268
-
269
- svgWidth = parent.svgWidth;
270
- svgHeight = parent.svgHeight;
271
- svgSizeXY = parent.svgSizeXY;
272
-
273
- opacity = parent.opacity;
274
- }
275
-
276
- // The rect and ellipse modes are set to CORNER since it is the expected
277
- // mode for svg shapes.
278
- rectMode = CORNER;
279
- ellipseMode = CORNER;
280
- }
281
-
282
-
283
- /** Factory method for subclasses. */
284
- protected PShapeSVG createShape(PShapeSVG parent, XML properties, boolean parseKids) {
285
- return new PShapeSVG(parent, properties, parseKids);
286
- }
287
-
288
-
289
- protected void parseChildren(XML graphics) {
290
- XML[] elements = graphics.getChildren();
291
- children = new PShape[elements.length];
292
- childCount = 0;
293
-
294
- for (XML elem : elements) {
295
- PShape kid = parseChild(elem);
296
- if (kid != null) addChild(kid);
297
- }
298
- children = (PShape[]) PApplet.subset(children, 0, childCount);
299
- }
300
-
301
-
302
- /**
303
- * Parse a child XML element.
304
- * Override this method to add parsing for more SVG elements.
305
- */
306
- protected PShape parseChild(XML elem) {
307
- // System.err.println("parsing child in pshape " + elem.getName());
308
- String name = elem.getName();
309
- PShapeSVG shape = null;
310
-
311
-
312
- if (name == null) {
313
- // just some whitespace that can be ignored (hopefully)
314
-
315
- } else if (name.equals("g")) {
316
- shape = createShape(this, elem, true);
317
-
318
- } else if (name.equals("defs")) {
319
- // generally this will contain gradient info, so may
320
- // as well just throw it into a group element for parsing
321
- shape = createShape(this, elem, true);
322
-
323
- } else if (name.equals("line")) {
324
- shape = createShape(this, elem, true);
325
- shape.parseLine();
326
-
327
- } else if (name.equals("circle")) {
328
- shape = createShape(this, elem, true);
329
- shape.parseEllipse(true);
330
-
331
- } else if (name.equals("ellipse")) {
332
- shape = createShape(this, elem, true);
333
- shape.parseEllipse(false);
334
-
335
- } else if (name.equals("rect")) {
336
- shape = createShape(this, elem, true);
337
- shape.parseRect();
338
-
339
- } else if (name.equals("image")) {
340
- shape = createShape(this, elem, true);
341
- shape.parseImage();
342
-
343
- } else if (name.equals("polygon")) {
344
- shape = createShape(this, elem, true);
345
- shape.parsePoly(true);
346
-
347
- } else if (name.equals("polyline")) {
348
- shape = createShape(this, elem, true);
349
- shape.parsePoly(false);
350
-
351
- } else if (name.equals("path")) {
352
- shape = createShape(this, elem, true);
353
- shape.parsePath();
354
-
355
- } else if (name.equals("radialGradient")) {
356
- return new RadialGradient(this, elem);
357
-
358
- } else if (name.equals("linearGradient")) {
359
- return new LinearGradient(this, elem);
360
-
361
- } else if (name.equals("font")) {
362
- return new Font(this, elem);
363
-
364
- // } else if (name.equals("font-face")) {
365
- // return new FontFace(this, elem);
366
-
367
- // } else if (name.equals("glyph") || name.equals("missing-glyph")) {
368
- // return new FontGlyph(this, elem);
369
-
370
- } else if (name.equals("text")) { // || name.equals("font")) {
371
- return new Text(this, elem);
372
-
373
- } else if (name.equals("tspan")) {
374
- return new LineOfText(this, elem);
375
-
376
- } else if (name.equals("filter")) {
377
- PGraphics.showWarning("Filters are not supported.");
378
-
379
- } else if (name.equals("mask")) {
380
- PGraphics.showWarning("Masks are not supported.");
381
-
382
- } else if (name.equals("pattern")) {
383
- PGraphics.showWarning("Patterns are not supported.");
384
-
385
- } else if (name.equals("stop")) {
386
- // stop tag is handled by gradient parser, so don't warn about it
387
-
388
- } else if (name.equals("sodipodi:namedview")) {
389
- // these are always in Inkscape files, the warnings get tedious
390
-
391
- } else if (name.equals("metadata")
392
- || name.equals("title") || name.equals("desc")) {
393
- // fontforge just stuffs <metadata> in as a comment.
394
- // All harmless stuff, irrelevant to rendering.
395
- return null;
396
-
397
- } else if (!name.startsWith("#")) {
398
- PGraphics.showWarning("Ignoring <" + name + "> tag.");
399
- // new Exception().printStackTrace();
400
- }
401
- return shape;
402
- }
403
-
404
-
405
- protected void parseLine() {
406
- kind = LINE;
407
- family = PRIMITIVE;
408
- params = new float[] {
409
- getFloatWithUnit(element, "x1", svgWidth),
410
- getFloatWithUnit(element, "y1", svgHeight),
411
- getFloatWithUnit(element, "x2", svgWidth),
412
- getFloatWithUnit(element, "y2", svgHeight)
413
- };
414
- }
415
-
416
-
417
- /**
418
- * Handles parsing ellipse and circle tags.
419
- * @param circle true if this is a circle and not an ellipse
420
- */
421
- protected void parseEllipse(boolean circle) {
422
- kind = ELLIPSE;
423
- family = PRIMITIVE;
424
- params = new float[4];
425
-
426
- params[0] = getFloatWithUnit(element, "cx", svgWidth);
427
- params[1] = getFloatWithUnit(element, "cy", svgHeight);
428
-
429
- float rx, ry;
430
- if (circle) {
431
- rx = ry = getFloatWithUnit(element, "r", svgSizeXY);
432
- } else {
433
- rx = getFloatWithUnit(element, "rx", svgWidth);
434
- ry = getFloatWithUnit(element, "ry", svgHeight);
435
- }
436
- params[0] -= rx;
437
- params[1] -= ry;
438
-
439
- params[2] = rx*2;
440
- params[3] = ry*2;
441
- }
442
-
443
-
444
- protected void parseRect() {
445
- kind = RECT;
446
- family = PRIMITIVE;
447
- params = new float[] {
448
- getFloatWithUnit(element, "x", svgWidth),
449
- getFloatWithUnit(element, "y", svgHeight),
450
- getFloatWithUnit(element, "width", svgWidth),
451
- getFloatWithUnit(element, "height", svgHeight)
452
- };
453
- }
454
-
455
-
456
- protected void parseImage() {
457
- kind = RECT;
458
- textureMode = NORMAL;
459
-
460
- family = PRIMITIVE;
461
- params = new float[] {
462
- getFloatWithUnit(element, "x", svgWidth),
463
- getFloatWithUnit(element, "y", svgHeight),
464
- getFloatWithUnit(element, "width", svgWidth),
465
- getFloatWithUnit(element, "height", svgHeight)
466
- };
467
-
468
- this.imagePath = element.getString("xlink:href");
469
- }
470
-
471
- /**
472
- * Parse a polyline or polygon from an SVG file.
473
- * Syntax defined at http://www.w3.org/TR/SVG/shapes.html#PointsBNF
474
- * @param close true if shape is closed (polygon), false if not (polyline)
475
- */
476
- protected void parsePoly(boolean close) {
477
- family = PATH;
478
- this.close = close;
479
-
480
- String pointsAttr = element.getString("points");
481
- if (pointsAttr != null) {
482
- Pattern pattern = Pattern.compile("([+-]?[\\d]+(\\.[\\d]+)?([eE][+-][\\d]+)?)(,?\\s*)([+-]?[\\d]+(\\.[\\d]+)?([eE][+-][\\d]+)?)");
483
- Matcher matcher = pattern.matcher(pointsAttr);
484
- vertexCount = 0;
485
- while (matcher.find()) {
486
- vertexCount++;
487
- }
488
- matcher.reset();
489
- vertices = new float[vertexCount][2];
490
- for (int i = 0; i < vertexCount; i++) {
491
- matcher.find();
492
- vertices[i][X] = Float.parseFloat(matcher.group(1));
493
- vertices[i][Y] = Float.parseFloat(matcher.group(5));
494
- }
495
- // String[] pointsBuffer = PApplet.splitTokens(pointsAttr);
496
- // vertexCount = pointsBuffer.length;
497
- // vertices = new float[vertexCount][2];
498
- // for (int i = 0; i < vertexCount; i++) {
499
- // String pb[] = PApplet.splitTokens(pointsBuffer[i], ", \t\r\n");
500
- // vertices[i][X] = Float.parseFloat(pb[0]);
501
- // vertices[i][Y] = Float.parseFloat(pb[1]);
502
- // }
503
- }
504
- }
505
-
506
-
507
- protected void parsePath() {
508
- family = PATH;
509
- kind = 0;
510
-
511
- String pathData = element.getString("d");
512
- if (pathData == null || PApplet.trim(pathData).length() == 0) {
513
- return;
514
- }
515
- char[] pathDataChars = pathData.toCharArray();
516
-
517
- StringBuilder pathBuffer = new StringBuilder();
518
- boolean lastSeparate = false;
519
-
520
- for (int i = 0; i < pathDataChars.length; i++) {
521
- char c = pathDataChars[i];
522
- boolean separate = false;
523
-
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 == ',') {
535
- separate = true;
536
- if (i != 0) {
537
- pathBuffer.append("|");
538
- }
539
- }
540
- if (c == 'Z' || c == 'z') {
541
- separate = false;
542
- }
543
- if (c == '-' && !lastSeparate) {
544
- // allow for 'e' notation in numbers, e.g. 2.10e-9
545
- // http://dev.processing.org/bugs/show_bug.cgi?id=1408
546
- if (i == 0 || pathDataChars[i-1] != 'e') {
547
- pathBuffer.append("|");
548
- }
549
- }
550
- if (c != ',') {
551
- pathBuffer.append(c); //"" + pathDataBuffer.charAt(i));
552
- }
553
- if (separate && c != ',' && c != '-') {
554
- pathBuffer.append("|");
555
- }
556
- lastSeparate = separate;
557
- }
558
-
559
- // use whitespace constant to get rid of extra spaces and CR or LF
560
- String[] pathTokens =
561
- PApplet.splitTokens(pathBuffer.toString(), "|" + WHITESPACE);
562
- vertices = new float[pathTokens.length][2];
563
- vertexCodes = new int[pathTokens.length];
564
-
565
- float cx = 0;
566
- float cy = 0;
567
- int i = 0;
568
-
569
- char implicitCommand = '\0';
570
- // char prevCommand = '\0';
571
- boolean prevCurve = false;
572
- float ctrlX, ctrlY;
573
- // store values for closepath so that relative coords work properly
574
- float movetoX = 0;
575
- float movetoY = 0;
576
-
577
- while (i < pathTokens.length) {
578
- char c = pathTokens[i].charAt(0);
579
- if (((c >= '0' && c <= '9') || (c == '-')) && implicitCommand != '\0') {
580
- c = implicitCommand;
581
- i--;
582
- } else {
583
- implicitCommand = c;
584
- }
585
- switch (c) {
586
-
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;
596
-
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;
606
-
607
- case 'L':
608
- cx = PApplet.parseFloat(pathTokens[i + 1]);
609
- cy = PApplet.parseFloat(pathTokens[i + 2]);
610
- parsePathLineto(cx, cy);
611
- i += 3;
612
- break;
613
-
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;
619
- break;
620
-
621
- // horizontal lineto absolute
622
- case 'H':
623
- cx = PApplet.parseFloat(pathTokens[i + 1]);
624
- parsePathLineto(cx, cy);
625
- i += 2;
626
- break;
627
-
628
- // horizontal lineto relative
629
- case 'h':
630
- cx = cx + PApplet.parseFloat(pathTokens[i + 1]);
631
- parsePathLineto(cx, cy);
632
- i += 2;
633
- break;
634
-
635
- case 'V':
636
- cy = PApplet.parseFloat(pathTokens[i + 1]);
637
- parsePathLineto(cx, cy);
638
- i += 2;
639
- break;
640
-
641
- case 'v':
642
- cy = cy + PApplet.parseFloat(pathTokens[i + 1]);
643
- parsePathLineto(cx, cy);
644
- i += 2;
645
- break;
646
-
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);
703
- }
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;
715
-
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);
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
- }
804
- break;
805
-
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);
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
- }
828
- break;
829
-
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++;
873
- break;
874
-
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]);
883
- }
884
- // prevCommand = c;
885
- }
886
- }
887
-
888
-
889
- // private void parsePathCheck(int num) {
890
- // if (vertexCount + num-1 >= vertices.length) {
891
- // //vertices = (float[][]) PApplet.expand(vertices);
892
- // float[][] temp = new float[vertexCount << 1][2];
893
- // System.arraycopy(vertices, 0, temp, 0, vertexCount);
894
- // vertices = temp;
895
- // }
896
- // }
897
-
898
- private void parsePathVertex(float x, float y) {
899
- if (vertexCount == vertices.length) {
900
- //vertices = (float[][]) PApplet.expand(vertices);
901
- float[][] temp = new float[vertexCount << 1][2];
902
- System.arraycopy(vertices, 0, temp, 0, vertexCount);
903
- vertices = temp;
904
- }
905
- vertices[vertexCount][X] = x;
906
- vertices[vertexCount][Y] = y;
907
- vertexCount++;
908
- }
909
-
910
-
911
- private void parsePathCode(int what) {
912
- if (vertexCodeCount == vertexCodes.length) {
913
- vertexCodes = PApplet.expand(vertexCodes);
914
- }
915
- vertexCodes[vertexCodeCount++] = what;
916
- }
917
-
918
-
919
- private void parsePathMoveto(float px, float py) {
920
- if (vertexCount > 0) {
921
- parsePathCode(BREAK);
922
- }
923
- parsePathCode(VERTEX);
924
- parsePathVertex(px, py);
925
- }
926
-
927
-
928
- private void parsePathLineto(float px, float py) {
929
- parsePathCode(VERTEX);
930
- parsePathVertex(px, py);
931
- }
932
-
933
-
934
- private void parsePathCurveto(float x1, float y1,
935
- float x2, float y2,
936
- float x3, float y3) {
937
- parsePathCode(BEZIER_VERTEX);
938
- parsePathVertex(x1, y1);
939
- parsePathVertex(x2, y2);
940
- parsePathVertex(x3, y3);
941
- }
942
-
943
- // private void parsePathQuadto(float x1, float y1,
944
- // float cx, float cy,
945
- // float x2, float y2) {
946
- // //System.out.println("quadto: " + x1 + "," + y1 + " " + cx + "," + cy + " " + x2 + "," + y2);
947
- //// parsePathCode(BEZIER_VERTEX);
948
- // parsePathCode(QUAD_BEZIER_VERTEX);
949
- // // x1/y1 already covered by last moveto, lineto, or curveto
950
- //
951
- // parsePathVertex(x1 + ((cx-x1)*2/3.0f), y1 + ((cy-y1)*2/3.0f));
952
- // parsePathVertex(x2 + ((cx-x2)*2/3.0f), y2 + ((cy-y2)*2/3.0f));
953
- // parsePathVertex(x2, y2);
954
- // }
955
-
956
- private void parsePathQuadto(float cx, float cy,
957
- float x2, float y2) {
958
- //System.out.println("quadto: " + x1 + "," + y1 + " " + cx + "," + cy + " " + x2 + "," + y2);
959
- // parsePathCode(BEZIER_VERTEX);
960
- parsePathCode(QUADRATIC_VERTEX);
961
- // x1/y1 already covered by last moveto, lineto, or curveto
962
- parsePathVertex(cx, cy);
963
- parsePathVertex(x2, y2);
964
- }
965
-
966
-
967
- // Approximates elliptical arc by several bezier segments.
968
- // Meets SVG standard requirements from:
969
- // http://www.w3.org/TR/SVG/paths.html#PathDataEllipticalArcCommands
970
- // http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes
971
- // Based on arc to bezier curve equations from:
972
- // http://www.spaceroots.org/documents/ellipse/node22.html
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; }
980
-
981
- rx = PApplet.abs(rx); ry = PApplet.abs(ry);
982
-
983
- float phi = PApplet.radians(((angle % 360) + 360) % 360);
984
- float cosPhi = PApplet.cos(phi), sinPhi = PApplet.sin(phi);
985
-
986
- float x1r = ( cosPhi * (x1 - x2) + sinPhi * (y1 - y2)) / 2;
987
- float y1r = (-sinPhi * (x1 - x2) + cosPhi * (y1 - y2)) / 2;
988
-
989
- float cxr, cyr;
990
- {
991
- float A = (x1r*x1r) / (rx*rx) + (y1r*y1r) / (ry*ry);
992
- if (A > 1) {
993
- // No solution, scale ellipse up according to SVG standard
994
- float sqrtA = PApplet.sqrt(A);
995
- rx *= sqrtA; cxr = 0;
996
- ry *= sqrtA; cyr = 0;
997
- } else {
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;
1001
- cyr = -k * ry * x1r / rx;
1002
- }
1003
- }
1004
-
1005
- float cx = cosPhi * cxr - sinPhi * cyr + (x1 + x2) / 2;
1006
- float cy = sinPhi * cxr + cosPhi * cyr + (y1 + y2) / 2;
1007
-
1008
- float phi1, phiDelta;
1009
- {
1010
- float sx = ( x1r - cxr) / rx, sy = ( y1r - cyr) / ry;
1011
- float tx = (-x1r - cxr) / rx, ty = (-y1r - cyr) / ry;
1012
- phi1 = PApplet.atan2(sy, sx);
1013
- phiDelta = (((PApplet.atan2(ty, tx) - phi1) % TWO_PI) + TWO_PI) % TWO_PI;
1014
- if (!fs) phiDelta -= TWO_PI;
1015
- }
1016
-
1017
- // One segment can not cover more that PI, less than PI/2 is
1018
- // recommended to avoid visible inaccuracies caused by rounding errors
1019
- int segmentCount = PApplet.ceil(PApplet.abs(phiDelta) / TWO_PI * 4);
1020
-
1021
- float inc = phiDelta / segmentCount;
1022
- float a = PApplet.sin(inc) *
1023
- (PApplet.sqrt(4 + 3 * PApplet.sq(PApplet.tan(inc / 2))) - 1) / 3;
1024
-
1025
- float sinPhi1 = PApplet.sin(phi1), cosPhi1 = PApplet.cos(phi1);
1026
-
1027
- float p1x = x1;
1028
- float p1y = y1;
1029
- float relq1x = a * (-rx * cosPhi * sinPhi1 - ry * sinPhi * cosPhi1);
1030
- float relq1y = a * (-rx * sinPhi * sinPhi1 + ry * cosPhi * cosPhi1);
1031
-
1032
- for (int i = 0; i < segmentCount; i++) {
1033
- float eta = phi1 + (i + 1) * inc;
1034
- float sinEta = PApplet.sin(eta), cosEta = PApplet.cos(eta);
1035
-
1036
- float p2x = cx + rx * cosPhi * cosEta - ry * sinPhi * sinEta;
1037
- float p2y = cy + rx * sinPhi * cosEta + ry * cosPhi * sinEta;
1038
- float relq2x = a * (-rx * cosPhi * sinEta - ry * sinPhi * cosEta);
1039
- float relq2y = a * (-rx * sinPhi * sinEta + ry * cosPhi * cosEta);
1040
-
1041
- if (i == segmentCount - 1) { p2x = x2; p2y = y2; }
1042
-
1043
- parsePathCode(BEZIER_VERTEX);
1044
- parsePathVertex(p1x + relq1x, p1y + relq1y);
1045
- parsePathVertex(p2x - relq2x, p2y - relq2y);
1046
- parsePathVertex(p2x, p2y);
1047
-
1048
- p1x = p2x; relq1x = relq2x;
1049
- p1y = p2y; relq1y = relq2y;
1050
- }
1051
- }
1052
-
1053
-
1054
- /**
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>
1059
- * of the SVG documentation.
1060
- * @param matrixStr text of the matrix param.
1061
- * @return a good old-fashioned PMatrix2D
1062
- */
1063
- static protected PMatrix2D parseTransform(String matrixStr) {
1064
- matrixStr = matrixStr.trim();
1065
- PMatrix2D outgoing = null;
1066
- int start = 0;
1067
- int stop = -1;
1068
- while ((stop = matrixStr.indexOf(')', start)) != -1) {
1069
- PMatrix2D m = parseSingleTransform(matrixStr.substring(start, stop+1));
1070
- if (outgoing == null) {
1071
- outgoing = m;
1072
- } else {
1073
- outgoing.apply(m);
1074
- }
1075
- start = stop + 1;
1076
- }
1077
- return outgoing;
1078
- }
1079
-
1080
-
1081
- static protected PMatrix2D parseSingleTransform(String matrixStr) {
1082
- //String[] pieces = PApplet.match(matrixStr, "^\\s*(\\w+)\\((.*)\\)\\s*$");
1083
- String[] pieces = PApplet.match(matrixStr, "[,\\s]*(\\w+)\\((.*)\\)");
1084
- if (pieces == null) {
1085
- System.err.println("Could not parse transform " + matrixStr);
1086
- return null;
1087
- }
1088
- float[] m = PApplet.parseFloat(PApplet.splitTokens(pieces[2], ", "));
1089
- switch (pieces[1]) {
1090
- case "matrix":
1091
- return new PMatrix2D(m[0], m[2], m[4], m[1], m[3], m[5]);
1092
- case "translate":
1093
- float tx = m[0];
1094
- float ty = (m.length == 2) ? m[1] : m[0];
1095
- return new PMatrix2D(1, 0, tx, 0, 1, ty);
1096
- case "scale":
1097
- float sx = m[0];
1098
- float sy = (m.length == 2) ? m[1] : m[0];
1099
- return new PMatrix2D(sx, 0, 0, 0, sy, 0);
1100
- case "rotate":
1101
- float angle = m[0];
1102
- if (m.length == 1) {
1103
- float c = PApplet.cos(angle);
1104
- float s = PApplet.sin(angle);
1105
- // SVG version is cos(a) sin(a) -sin(a) cos(a) 0 0
1106
- return new PMatrix2D(c, -s, 0, s, c, 0);
1107
-
1108
- } else if (m.length == 3) {
1109
- PMatrix2D mat = new PMatrix2D(0, 1, m[1], 1, 0, m[2]);
1110
- mat.rotate(m[0]);
1111
- mat.translate(-m[1], -m[2]);
1112
- return mat;
1113
- } break;
1114
- case "skewX":
1115
- return new PMatrix2D(1, 0, 1, PApplet.tan(m[0]), 0, 0);
1116
- case "skewY":
1117
- return new PMatrix2D(1, 0, 1, 0, PApplet.tan(m[0]), 0);
1118
- default:
1119
- break;
1120
- }
1121
- return null;
1122
- }
1123
-
1124
-
1125
- protected void parseColors(XML properties) {
1126
- if (properties.hasAttribute("opacity")) {
1127
- String opacityText = properties.getString("opacity");
1128
- setOpacity(opacityText);
1129
- }
1130
-
1131
- if (properties.hasAttribute("stroke")) {
1132
- String strokeText = properties.getString("stroke");
1133
- setColor(strokeText, false);
1134
- }
1135
-
1136
- if (properties.hasAttribute("stroke-opacity")) {
1137
- String strokeOpacityText = properties.getString("stroke-opacity");
1138
- setStrokeOpacity(strokeOpacityText);
1139
- }
1140
-
1141
- if (properties.hasAttribute("stroke-width")) {
1142
- // if NaN (i.e. if it's 'inherit') then default back to the inherit setting
1143
- String lineweight = properties.getString("stroke-width");
1144
- setStrokeWeight(lineweight);
1145
- }
1146
-
1147
- if (properties.hasAttribute("stroke-linejoin")) {
1148
- String linejoin = properties.getString("stroke-linejoin");
1149
- setStrokeJoin(linejoin);
1150
- }
1151
-
1152
- if (properties.hasAttribute("stroke-linecap")) {
1153
- String linecap = properties.getString("stroke-linecap");
1154
- setStrokeCap(linecap);
1155
- }
1156
-
1157
- // fill defaults to black (though stroke defaults to "none")
1158
- // http://www.w3.org/TR/SVG/painting.html#FillProperties
1159
- if (properties.hasAttribute("fill")) {
1160
- String fillText = properties.getString("fill");
1161
- setColor(fillText, true);
1162
- }
1163
-
1164
- if (properties.hasAttribute("fill-opacity")) {
1165
- String fillOpacityText = properties.getString("fill-opacity");
1166
- setFillOpacity(fillOpacityText);
1167
- }
1168
-
1169
- if (properties.hasAttribute("style")) {
1170
- String styleText = properties.getString("style");
1171
- String[] styleTokens = PApplet.splitTokens(styleText, ";");
1172
-
1173
- //PApplet.println(styleTokens);
1174
- for (String styleToken : styleTokens) {
1175
- String[] tokens = PApplet.splitTokens(styleToken, ":");
1176
- //PApplet.println(tokens);
1177
- tokens[0] = PApplet.trim(tokens[0]);
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;
1206
- }
1207
- }
1208
- }
1209
- }
1210
-
1211
-
1212
- void setOpacity(String opacityText) {
1213
- opacity = PApplet.parseFloat(opacityText);
1214
- strokeColor = ((int) (opacity * 255)) << 24 | strokeColor & 0xFFFFFF;
1215
- fillColor = ((int) (opacity * 255)) << 24 | fillColor & 0xFFFFFF;
1216
- }
1217
-
1218
-
1219
- void setStrokeWeight(String lineweight) {
1220
- strokeWeight = parseUnitSize(lineweight, svgSizeXY);
1221
- }
1222
-
1223
-
1224
- void setStrokeOpacity(String opacityText) {
1225
- strokeOpacity = PApplet.parseFloat(opacityText);
1226
- strokeColor = ((int) (strokeOpacity * 255)) << 24 | strokeColor & 0xFFFFFF;
1227
- }
1228
-
1229
-
1230
- void setStrokeJoin(String linejoin) {
1231
- switch (linejoin) {
1232
- // do nothing, will inherit automatically
1233
- case "inherit":
1234
- break;
1235
- case "miter":
1236
- strokeJoin = PConstants.MITER;
1237
- break;
1238
- case "round":
1239
- strokeJoin = PConstants.ROUND;
1240
- break;
1241
- case "bevel":
1242
- strokeJoin = PConstants.BEVEL;
1243
- break;
1244
- default:
1245
- break;
1246
- }
1247
- }
1248
-
1249
-
1250
- void setStrokeCap(String linecap) {
1251
- switch (linecap) {
1252
- // do nothing, will inherit automatically
1253
- case "inherit":
1254
- break;
1255
- case "butt":
1256
- strokeCap = PConstants.SQUARE;
1257
- break;
1258
- case "round":
1259
- strokeCap = PConstants.ROUND;
1260
- break;
1261
- case "square":
1262
- strokeCap = PConstants.PROJECT;
1263
- break;
1264
- default:
1265
- break;
1266
- }
1267
- }
1268
-
1269
-
1270
- void setFillOpacity(String opacityText) {
1271
- fillOpacity = PApplet.parseFloat(opacityText);
1272
- fillColor = ((int) (fillOpacity * 255)) << 24 | fillColor & 0xFFFFFF;
1273
- }
1274
-
1275
-
1276
- void setColor(String colorText, boolean isFill) {
1277
- colorText = colorText.trim();
1278
- int opacityMask = fillColor & 0xFF000000;
1279
- boolean visible = true;
1280
- int color = 0;
1281
- String name = "";
1282
- // String lColorText = colorText.toLowerCase();
1283
- Gradient gradient = null;
1284
- // Object paint = null;
1285
- if (colorText.equals("none")) {
1286
- visible = false;
1287
- } else if (colorText.startsWith("url(#")) {
1288
- name = colorText.substring(5, colorText.length() - 1);
1289
- Object object = findChild(name);
1290
- if (object instanceof Gradient) {
1291
- gradient = (Gradient) object;
1292
- // in 3.0a11, do this on first draw inside PShapeJava2D
1293
- // paint = calcGradientPaint(gradient); //, opacity);
1294
- } else {
1295
- // visible = false;
1296
- System.err.println("url " + name + " refers to unexpected data: " + object);
1297
- }
1298
- } else {
1299
- // Prints errors itself.
1300
- color = opacityMask | parseSimpleColor(colorText);
1301
- }
1302
- if (isFill) {
1303
- fill = visible;
1304
- fillColor = color;
1305
- fillName = name;
1306
- fillGradient = gradient;
1307
- // fillGradientPaint = paint;
1308
- } else {
1309
- stroke = visible;
1310
- strokeColor = color;
1311
- strokeName = name;
1312
- strokeGradient = gradient;
1313
- // strokeGradientPaint = paint;
1314
- }
1315
- }
1316
-
1317
-
1318
- /**
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
1321
- * @return 0xRRGGBB (no alpha). Zero on error.
1322
- */
1323
- static protected int parseSimpleColor(String colorText) {
1324
- colorText = colorText.toLowerCase().trim();
1325
- //if (colorNames.containsKey(colorText)) {
1326
- if (colorNames.hasKey(colorText)) {
1327
- return colorNames.get(colorText);
1328
- } else if (colorText.startsWith("#")) {
1329
- if (colorText.length() == 4) {
1330
- // Short form: #ABC, transform to long form #AABBCC
1331
- colorText = colorText.replaceAll("^#(.)(.)(.)$", "#$1$1$2$2$3$3");
1332
- }
1333
- return (Integer.parseInt(colorText.substring(1), 16)) & 0xFFFFFF;
1334
- //System.out.println("hex for fill is " + PApplet.hex(fillColor));
1335
- } else if (colorText.startsWith("rgb")) {
1336
- return parseRGB(colorText);
1337
- } else {
1338
- System.err.println("Cannot parse \"" + colorText + "\".");
1339
- return 0;
1340
- }
1341
- }
1342
-
1343
-
1344
- /**
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.
1347
- */
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 }
1366
- });
1367
-
1368
- /*
1369
- static protected Map<String, Integer> colorNames;
1370
- static {
1371
- colorNames = new HashMap<String, Integer>();
1372
- colorNames.put("aqua", 0x00ffff);
1373
- colorNames.put("black", 0x000000);
1374
- colorNames.put("blue", 0x0000ff);
1375
- colorNames.put("fuchsia", 0xff00ff);
1376
- colorNames.put("gray", 0x808080);
1377
- colorNames.put("grey", 0x808080);
1378
- colorNames.put("green", 0x008000);
1379
- colorNames.put("lime", 0x00ff00);
1380
- colorNames.put("maroon", 0x800000);
1381
- colorNames.put("navy", 0x000080);
1382
- colorNames.put("olive", 0x808000);
1383
- colorNames.put("purple", 0x800080);
1384
- colorNames.put("red", 0xff0000);
1385
- colorNames.put("silver", 0xc0c0c0);
1386
- colorNames.put("teal", 0x008080);
1387
- colorNames.put("white", 0xffffff);
1388
- colorNames.put("yellow", 0xffff00);
1389
- }
1390
- */
1391
-
1392
- static protected int parseRGB(String what) {
1393
- int leftParen = what.indexOf('(') + 1;
1394
- int rightParen = what.indexOf(')');
1395
- String sub = what.substring(leftParen, rightParen);
1396
- String[] values = PApplet.splitTokens(sub, ", ");
1397
- int rgbValue = 0;
1398
- if (values.length == 3) {
1399
- // Color spec allows for rgb values to be percentages.
1400
- for (int i = 0; i < 3; i++) {
1401
- rgbValue <<= 8;
1402
- if (values[i].endsWith("%")) {
1403
- rgbValue |= (int)(PApplet.constrain(255*parseFloatOrPercent(values[i]), 0, 255));
1404
- } else {
1405
- rgbValue |= PApplet.constrain(PApplet.parseInt(values[i]), 0, 255);
1406
- }
1407
- }
1408
- } else System.err.println("Could not read color \"" + what + "\".");
1409
-
1410
- return rgbValue;
1411
- }
1412
-
1413
-
1414
- //static protected Map<String, String> parseStyleAttributes(String style) {
1415
- static protected StringDict parseStyleAttributes(String style) {
1416
- //Map<String, String> table = new HashMap<String, String>();
1417
- StringDict table = new StringDict();
1418
- // if (style == null) return table;
1419
- if (style != null) {
1420
- String[] pieces = style.split(";");
1421
- for (String piece : pieces) {
1422
- String[] parts = piece.split(":");
1423
- //table.put(parts[0], parts[1]);
1424
- table.set(parts[0], parts[1]);
1425
- }
1426
- }
1427
- return table;
1428
- }
1429
-
1430
-
1431
- /**
1432
- * Used in place of element.getFloatAttribute(a) because we can
1433
- * have a unit suffix (length or coordinate).
1434
- * @param element what to parse
1435
- * @param attribute name of the attribute to get
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.
1439
- * @return unit-parsed version of the data
1440
- */
1441
- static protected float getFloatWithUnit(XML element, String attribute, float relativeTo) {
1442
- String val = element.getString(attribute);
1443
- return (val == null) ? 0 : parseUnitSize(val, relativeTo);
1444
- }
1445
-
1446
-
1447
- /**
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
1462
- */
1463
- static protected float parseUnitSize(String text, float relativeTo) {
1464
- int len = text.length() - 2;
1465
-
1466
- if (text.endsWith("pt")) {
1467
- return PApplet.parseFloat(text.substring(0, len)) * 1.25f;
1468
- } else if (text.endsWith("pc")) {
1469
- return PApplet.parseFloat(text.substring(0, len)) * 15;
1470
- } else if (text.endsWith("mm")) {
1471
- return PApplet.parseFloat(text.substring(0, len)) * 3.543307f;
1472
- } else if (text.endsWith("cm")) {
1473
- return PApplet.parseFloat(text.substring(0, len)) * 35.43307f;
1474
- } else if (text.endsWith("in")) {
1475
- return PApplet.parseFloat(text.substring(0, len)) * 90;
1476
- } else if (text.endsWith("px")) {
1477
- return PApplet.parseFloat(text.substring(0, len));
1478
- } else if (text.endsWith("%")) {
1479
- return relativeTo * parseFloatOrPercent(text);
1480
- } else {
1481
- return PApplet.parseFloat(text);
1482
- }
1483
- }
1484
-
1485
-
1486
- static protected float parseFloatOrPercent(String text) {
1487
- text = text.trim();
1488
- if (text.endsWith("%")) {
1489
- return Float.parseFloat(text.substring(0, text.length() - 1)) / 100.0f;
1490
- } else {
1491
- return Float.parseFloat(text);
1492
- }
1493
- }
1494
-
1495
-
1496
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1497
-
1498
-
1499
- static public class Gradient extends PShapeSVG {
1500
- AffineTransform transform;
1501
-
1502
- public float[] offset;
1503
- public int[] color;
1504
- public int count;
1505
-
1506
- public Gradient(PShapeSVG parent, XML properties) {
1507
- super(parent, properties, true);
1508
-
1509
- XML[] elements = properties.getChildren();
1510
- offset = new float[elements.length];
1511
- color = new int[elements.length];
1512
-
1513
- // <stop offset="0" style="stop-color:#967348"/>
1514
- for (int i = 0; i < elements.length; i++) {
1515
- XML elem = elements[i];
1516
- String name = elem.getName();
1517
- if (name.equals("stop")) {
1518
- String offsetAttr = elem.getString("offset");
1519
- offset[count] = parseFloatOrPercent(offsetAttr);
1520
-
1521
- String style = elem.getString("style");
1522
- //Map<String, String> styles = parseStyleAttributes(style);
1523
- StringDict styles = parseStyleAttributes(style);
1524
-
1525
- String colorStr = styles.get("stop-color");
1526
- if (colorStr == null) {
1527
- colorStr = elem.getString("stop-color");
1528
- if (colorStr == null) colorStr = "#000000";
1529
- }
1530
- String opacityStr = styles.get("stop-opacity");
1531
- if (opacityStr == null) {
1532
- opacityStr = elem.getString("stop-opacity");
1533
- if (opacityStr == null) opacityStr = "1";
1534
- }
1535
- int tupacity = PApplet.constrain(
1536
- (int)(PApplet.parseFloat(opacityStr) * 255), 0, 255);
1537
- color[count] = (tupacity << 24) | parseSimpleColor(colorStr);
1538
- count++;
1539
- }
1540
- }
1541
- offset = PApplet.subset(offset, 0, count);
1542
- color = PApplet.subset(color, 0, count);
1543
- }
1544
- }
1545
-
1546
-
1547
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1548
-
1549
-
1550
- static public class LinearGradient extends Gradient {
1551
- public float x1, y1, x2, y2;
1552
-
1553
- public LinearGradient(PShapeSVG parent, XML properties) {
1554
- super(parent, properties);
1555
-
1556
- this.x1 = getFloatWithUnit(properties, "x1", svgWidth);
1557
- this.y1 = getFloatWithUnit(properties, "y1", svgHeight);
1558
- this.x2 = getFloatWithUnit(properties, "x2", svgWidth);
1559
- this.y2 = getFloatWithUnit(properties, "y2", svgHeight);
1560
-
1561
- String transformStr =
1562
- properties.getString("gradientTransform");
1563
-
1564
- if (transformStr != null) {
1565
- float[] t = parseTransform(transformStr).get(null);
1566
- this.transform = new AffineTransform(t[0], t[3], t[1], t[4], t[2], t[5]);
1567
-
1568
- Point2D t1 = transform.transform(new Point2D.Float(x1, y1), null);
1569
- Point2D t2 = transform.transform(new Point2D.Float(x2, y2), null);
1570
-
1571
- this.x1 = (float) t1.getX();
1572
- this.y1 = (float) t1.getY();
1573
- this.x2 = (float) t2.getX();
1574
- this.y2 = (float) t2.getY();
1575
- }
1576
- }
1577
- }
1578
-
1579
-
1580
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1581
-
1582
-
1583
- static public class RadialGradient extends Gradient {
1584
- public float cx, cy, r;
1585
-
1586
- public RadialGradient(PShapeSVG parent, XML properties) {
1587
- super(parent, properties);
1588
-
1589
- this.cx = getFloatWithUnit(properties, "cx", svgWidth);
1590
- this.cy = getFloatWithUnit(properties, "cy", svgHeight);
1591
- this.r = getFloatWithUnit(properties, "r", svgSizeXY);
1592
-
1593
- String transformStr =
1594
- properties.getString("gradientTransform");
1595
-
1596
- if (transformStr != null) {
1597
- float[] t = parseTransform(transformStr).get(null);
1598
- this.transform = new AffineTransform(t[0], t[3], t[1], t[4], t[2], t[5]);
1599
-
1600
- Point2D t1 = transform.transform(new Point2D.Float(cx, cy), null);
1601
- Point2D t2 = transform.transform(new Point2D.Float(cx + r, cy), null);
1602
-
1603
- this.cx = (float) t1.getX();
1604
- this.cy = (float) t1.getY();
1605
- this.r = (float) (t2.getX() - t1.getX());
1606
- }
1607
- }
1608
- }
1609
-
1610
-
1611
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1612
-
1613
-
1614
- // static private float TEXT_QUALITY = 1;
1615
-
1616
- static private PFont parseFont(XML properties) {
1617
- String fontFamily = null;
1618
- float size = 10;
1619
- int weight = PLAIN; // 0
1620
- int italic = 0;
1621
-
1622
- if (properties.hasAttribute("style")) {
1623
- String styleText = properties.getString("style");
1624
- String[] styleTokens = PApplet.splitTokens(styleText, ";");
1625
-
1626
- //PApplet.println(styleTokens);
1627
- for (int i = 0; i < styleTokens.length; i++) {
1628
- String[] tokens = PApplet.splitTokens(styleTokens[i], ":");
1629
- //PApplet.println(tokens);
1630
-
1631
- tokens[0] = PApplet.trim(tokens[0]);
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")) {
1639
- // PApplet.println("font-variant: " + tokens[1]);
1640
- // setFillOpacity(tokens[1]);
1641
-
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")) {
1652
- // not supported.
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")) {
1666
- // not supported
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")) {
1675
- // not supported
1676
-
1677
- } else if (tokens[0].equals("text-anchor")) {
1678
- // not supported
1679
-
1680
- } else {
1681
- // Other attributes are not yet implemented
1682
- }
1683
- }
1684
- }
1685
- if (fontFamily == null) {
1686
- return null;
1687
- }
1688
- // size = size * TEXT_QUALITY;
1689
-
1690
- return createFont(fontFamily, weight | italic, size, true);
1691
- }
1692
-
1693
-
1694
- static protected PFont createFont(String name, int weight,
1695
- float size, boolean smooth) {
1696
- //System.out.println("Try to create a font of " + name + " family, " + weight);
1697
- java.awt.Font baseFont = new java.awt.Font(name, weight, (int) size);
1698
-
1699
- //System.out.println("Resulting family : " + baseFont.getFamily() + " " + baseFont.getStyle());
1700
- return new PFont(baseFont.deriveFont(size), smooth, null);
1701
- }
1702
-
1703
-
1704
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1705
-
1706
-
1707
- static public class Text extends PShapeSVG {
1708
- protected PFont font;
1709
-
1710
- public Text(PShapeSVG parent, XML properties) {
1711
- super(parent, properties, true);
1712
-
1713
- // get location
1714
- float x = Float.parseFloat(properties.getString("x"));
1715
- float y = Float.parseFloat(properties.getString("y"));
1716
-
1717
- if (matrix == null) {
1718
- matrix = new PMatrix2D();
1719
- }
1720
- matrix.translate(x, y);
1721
-
1722
- family = GROUP;
1723
-
1724
- font = parseFont(properties);
1725
- }
1726
- }
1727
-
1728
-
1729
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1730
-
1731
-
1732
- static public class LineOfText extends PShapeSVG {
1733
- String textToDisplay;
1734
- PFont font;
1735
-
1736
- public LineOfText(PShapeSVG parent, XML properties) {
1737
- // TODO: child should ideally be parsed too for inline content.
1738
- super(parent, properties, false);
1739
-
1740
- //get location
1741
- float x = Float.parseFloat(properties.getString("x"));
1742
- float y = Float.parseFloat(properties.getString("y"));
1743
-
1744
- float parentX = Float.parseFloat(parent.element.getString("x"));
1745
- float parentY = Float.parseFloat(parent.element.getString("y"));
1746
-
1747
- if (matrix == null) matrix = new PMatrix2D();
1748
- matrix.translate(x - parentX, (y - parentY) / 2f);
1749
-
1750
- // get the first properties
1751
- parseColors(properties);
1752
- font = parseFont(properties);
1753
-
1754
- // cleaned up syntax but removing b/c unused [fry 190118]
1755
- //boolean isLine = properties.getString("role").equals("line");
1756
-
1757
- if (this.childCount > 0) {
1758
- // no inline content yet.
1759
- }
1760
-
1761
- String text = properties.getContent();
1762
- textToDisplay = text;
1763
- }
1764
-
1765
- @Override
1766
- public void drawImpl(PGraphics g) {
1767
- if (font == null) {
1768
- font = ((Text) parent).font;
1769
- if (font == null) {
1770
- return;
1771
- }
1772
- }
1773
-
1774
- pre(g);
1775
- // g.textFont(font, font.size / TEXT_QUALITY);
1776
- g.textFont(font, font.size);
1777
- g.text(textToDisplay, 0, 0);
1778
- post(g);
1779
- }
1780
- }
1781
-
1782
-
1783
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1784
-
1785
-
1786
- static public class Font extends PShapeSVG {
1787
- public FontFace face;
1788
-
1789
- public Map<String, FontGlyph> namedGlyphs;
1790
- public Map<Character, FontGlyph> unicodeGlyphs;
1791
-
1792
- public int glyphCount;
1793
- public FontGlyph[] glyphs;
1794
- public FontGlyph missingGlyph;
1795
-
1796
- int horizAdvX;
1797
-
1798
-
1799
- public Font(PShapeSVG parent, XML properties) {
1800
- super(parent, properties, false);
1801
- // handle(parent, properties);
1802
-
1803
- XML[] elements = properties.getChildren();
1804
-
1805
- horizAdvX = properties.getInt("horiz-adv-x", 0);
1806
-
1807
- namedGlyphs = new HashMap<>();
1808
- unicodeGlyphs = new HashMap<>();
1809
- glyphCount = 0;
1810
- glyphs = new FontGlyph[elements.length];
1811
-
1812
- for (XML element1 : elements) {
1813
- String name = element1.getName();
1814
- XML elem = element1;
1815
- if (null == name) {
1816
- // skip it
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);
1823
- }
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;
1839
- }
1840
- }
1841
- }
1842
-
1843
-
1844
- protected void drawShape() {
1845
- // does nothing for fonts
1846
- }
1847
-
1848
-
1849
- public void drawString(PGraphics g, String str, float x, float y, float size) {
1850
- // 1) scale by the 1.0/unitsPerEm
1851
- // 2) scale up by a font size
1852
- g.pushMatrix();
1853
- float s = size / face.unitsPerEm;
1854
- //System.out.println("scale is " + s);
1855
- // swap y coord at the same time, since fonts have y=0 at baseline
1856
- g.translate(x, y);
1857
- g.scale(s, -s);
1858
- char[] c = str.toCharArray();
1859
- for (int i = 0; i < c.length; i++) {
1860
- // call draw on each char (pulling it w/ the unicode table)
1861
- FontGlyph fg = unicodeGlyphs.get(c[i]);
1862
- if (fg != null) {
1863
- fg.draw(g);
1864
- // add horizAdvX/unitsPerEm to the x coordinate along the way
1865
- g.translate(fg.horizAdvX, 0);
1866
- } else {
1867
- System.err.println("'" + c[i] + "' not available.");
1868
- }
1869
- }
1870
- g.popMatrix();
1871
- }
1872
-
1873
-
1874
- public void drawChar(PGraphics g, char c, float x, float y, float size) {
1875
- g.pushMatrix();
1876
- float s = size / face.unitsPerEm;
1877
- g.translate(x, y);
1878
- g.scale(s, -s);
1879
- FontGlyph fg = unicodeGlyphs.get(c);
1880
- if (fg != null) g.shape(fg);
1881
- g.popMatrix();
1882
- }
1883
-
1884
-
1885
- public float textWidth(String str, float size) {
1886
- float w = 0;
1887
- char[] c = str.toCharArray();
1888
- for (int i = 0; i < c.length; i++) {
1889
- // call draw on each char (pulling it w/ the unicode table)
1890
- FontGlyph fg = unicodeGlyphs.get(c[i]);
1891
- if (fg != null) {
1892
- w += (float) fg.horizAdvX / face.unitsPerEm;
1893
- }
1894
- }
1895
- return w * size;
1896
- }
1897
- }
1898
-
1899
-
1900
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1901
-
1902
-
1903
- static class FontFace extends PShapeSVG {
1904
- int horizOriginX; // dflt 0
1905
- int horizOriginY; // dflt 0
1906
- // int horizAdvX; // no dflt?
1907
- int vertOriginX; // dflt horizAdvX/2
1908
- int vertOriginY; // dflt ascent
1909
- int vertAdvY; // dflt 1em (unitsPerEm value)
1910
-
1911
- String fontFamily;
1912
- int fontWeight; // can also be normal or bold (also comma separated)
1913
- String fontStretch;
1914
- int unitsPerEm; // dflt 1000
1915
- int[] panose1; // dflt "0 0 0 0 0 0 0 0 0 0"
1916
- int ascent;
1917
- int descent;
1918
- int[] bbox; // spec says comma separated, tho not w/ forge
1919
- int underlineThickness;
1920
- int underlinePosition;
1921
- //String unicodeRange; // gonna ignore for now
1922
-
1923
-
1924
- public FontFace(PShapeSVG parent, XML properties) {
1925
- super(parent, properties, true);
1926
-
1927
- unitsPerEm = properties.getInt("units-per-em", 1000);
1928
- }
1929
-
1930
-
1931
- protected void drawShape() {
1932
- // nothing to draw in the font face attribute
1933
- }
1934
- }
1935
-
1936
-
1937
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1938
-
1939
-
1940
- static public class FontGlyph extends PShapeSVG { // extends Path
1941
- public String name;
1942
- char unicode;
1943
- int horizAdvX;
1944
-
1945
- public FontGlyph(PShapeSVG parent, XML properties, Font font) {
1946
- super(parent, properties, true);
1947
- super.parsePath(); // ??
1948
-
1949
- name = properties.getString("glyph-name");
1950
- String u = properties.getString("unicode");
1951
- unicode = 0;
1952
- if (u != null) {
1953
- if (u.length() == 1) {
1954
- unicode = u.charAt(0);
1955
- //System.out.println("unicode for " + name + " is " + u);
1956
- } else {
1957
- System.err.println("unicode for " + name +
1958
- " is more than one char: " + u);
1959
- }
1960
- }
1961
- if (properties.hasAttribute("horiz-adv-x")) {
1962
- horizAdvX = properties.getInt("horiz-adv-x");
1963
- } else {
1964
- horizAdvX = font.horizAdvX;
1965
- }
1966
- }
1967
-
1968
-
1969
- protected boolean isLegit() { // TODO need a better way to handle this...
1970
- return vertexCount != 0;
1971
- }
1972
- }
1973
-
1974
-
1975
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1976
-
1977
-
1978
- /**
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>
1985
- * // This code grabs "Layer 3" and the shapes beneath it.
1986
- * PShape layer3 = svg.getChild("Layer 3");
1987
- * </PRE>
1988
- * @param name
1989
- * @return
1990
- */
1991
- @Override
1992
- public PShape getChild(String name) {
1993
- PShape found = super.getChild(name);
1994
- if (found == null) {
1995
- // Otherwise try with underscores instead of spaces
1996
- // (this is how Illustrator handles spaces in the layer names).
1997
- found = super.getChild(name.replace(' ', '_'));
1998
- }
1999
- // Set bounding box based on the parent bounding box
2000
- if (found != null) {
2001
- // found.x = this.x;
2002
- // found.y = this.y;
2003
- found.width = this.width;
2004
- found.height = this.height;
2005
- }
2006
- return found;
2007
- }
2008
-
2009
-
2010
- /**
2011
- * Prints out the SVG document. Useful for parsing.
2012
- */
2013
- public void print() {
2014
- PApplet.println(element.toString());
2015
- }
2016
- }