geomerative 0.1.0-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +14 -0
  3. data/LICENSE +662 -0
  4. data/LICENSE.md +9 -0
  5. data/README.md +2 -0
  6. data/Rakefile +37 -0
  7. data/examples/README.md +7 -0
  8. data/examples/data/FreeSans.ttf +0 -0
  9. data/examples/data/ReplicaBold.ttf +0 -0
  10. data/examples/data/bot1.svg +160 -0
  11. data/examples/hello_svg_to_pdf.rb +26 -0
  12. data/examples/hello_world.rb +23 -0
  13. data/examples/physics_type.rb +77 -0
  14. data/examples/rotate_first_letter.rb +28 -0
  15. data/geomerative.gemspec +32 -0
  16. data/lib/geomerative.rb +12 -0
  17. data/lib/geomerative/version.rb +3 -0
  18. data/pom.xml +110 -0
  19. data/src/geomerative/FastRClip.java +2715 -0
  20. data/src/geomerative/RClip.java +2892 -0
  21. data/src/geomerative/RClosest.java +64 -0
  22. data/src/geomerative/RCommand.java +1941 -0
  23. data/src/geomerative/RContour.java +348 -0
  24. data/src/geomerative/RFont.java +583 -0
  25. data/src/geomerative/RG.java +753 -0
  26. data/src/geomerative/RGeomElem.java +1075 -0
  27. data/src/geomerative/RGroup.java +888 -0
  28. data/src/geomerative/RMatrix.java +401 -0
  29. data/src/geomerative/RMesh.java +420 -0
  30. data/src/geomerative/RPath.java +1095 -0
  31. data/src/geomerative/RPoint.java +419 -0
  32. data/src/geomerative/RPolygon.java +1110 -0
  33. data/src/geomerative/RRectangle.java +91 -0
  34. data/src/geomerative/RSVG.java +976 -0
  35. data/src/geomerative/RShape.java +2045 -0
  36. data/src/geomerative/RStrip.java +221 -0
  37. data/src/geomerative/RStyle.java +469 -0
  38. data/src/org/apache/batik/svggen/font/.SVGFont.java.swp +0 -0
  39. data/src/org/apache/batik/svggen/font/Font.java +188 -0
  40. data/src/org/apache/batik/svggen/font/Glyph.java +113 -0
  41. data/src/org/apache/batik/svggen/font/Messages.java.bak +72 -0
  42. data/src/org/apache/batik/svggen/font/Point.java +38 -0
  43. data/src/org/apache/batik/svggen/font/RandomAccessFileEmulator.java +15 -0
  44. data/src/org/apache/batik/svggen/font/table/ClassDef.java +42 -0
  45. data/src/org/apache/batik/svggen/font/table/ClassDefFormat1.java +55 -0
  46. data/src/org/apache/batik/svggen/font/table/ClassDefFormat2.java +49 -0
  47. data/src/org/apache/batik/svggen/font/table/CmapFormat.java +81 -0
  48. data/src/org/apache/batik/svggen/font/table/CmapFormat0.java +60 -0
  49. data/src/org/apache/batik/svggen/font/table/CmapFormat2.java +48 -0
  50. data/src/org/apache/batik/svggen/font/table/CmapFormat4.java +147 -0
  51. data/src/org/apache/batik/svggen/font/table/CmapFormat6.java +60 -0
  52. data/src/org/apache/batik/svggen/font/table/CmapIndexEntry.java +84 -0
  53. data/src/org/apache/batik/svggen/font/table/CmapTable.java +87 -0
  54. data/src/org/apache/batik/svggen/font/table/Coverage.java +50 -0
  55. data/src/org/apache/batik/svggen/font/table/CoverageFormat1.java +59 -0
  56. data/src/org/apache/batik/svggen/font/table/CoverageFormat2.java +56 -0
  57. data/src/org/apache/batik/svggen/font/table/CvtTable.java +48 -0
  58. data/src/org/apache/batik/svggen/font/table/Device.java +63 -0
  59. data/src/org/apache/batik/svggen/font/table/DirectoryEntry.java +73 -0
  60. data/src/org/apache/batik/svggen/font/table/Feature.java +56 -0
  61. data/src/org/apache/batik/svggen/font/table/FeatureList.java +70 -0
  62. data/src/org/apache/batik/svggen/font/table/FeatureRecord.java +52 -0
  63. data/src/org/apache/batik/svggen/font/table/FeatureTags.java +30 -0
  64. data/src/org/apache/batik/svggen/font/table/FpgmTable.java +38 -0
  65. data/src/org/apache/batik/svggen/font/table/GlyfCompositeComp.java +165 -0
  66. data/src/org/apache/batik/svggen/font/table/GlyfCompositeDescript.java +160 -0
  67. data/src/org/apache/batik/svggen/font/table/GlyfDescript.java +79 -0
  68. data/src/org/apache/batik/svggen/font/table/GlyfSimpleDescript.java +155 -0
  69. data/src/org/apache/batik/svggen/font/table/GlyfTable.java +111 -0
  70. data/src/org/apache/batik/svggen/font/table/GlyphDescription.java +39 -0
  71. data/src/org/apache/batik/svggen/font/table/GposTable.java +80 -0
  72. data/src/org/apache/batik/svggen/font/table/GsubTable.java +118 -0
  73. data/src/org/apache/batik/svggen/font/table/HeadTable.java +159 -0
  74. data/src/org/apache/batik/svggen/font/table/HheaTable.java +109 -0
  75. data/src/org/apache/batik/svggen/font/table/HmtxTable.java +99 -0
  76. data/src/org/apache/batik/svggen/font/table/KernSubtable.java +58 -0
  77. data/src/org/apache/batik/svggen/font/table/KernSubtableFormat0.java +65 -0
  78. data/src/org/apache/batik/svggen/font/table/KernSubtableFormat2.java +56 -0
  79. data/src/org/apache/batik/svggen/font/table/KernTable.java +64 -0
  80. data/src/org/apache/batik/svggen/font/table/KerningPair.java +53 -0
  81. data/src/org/apache/batik/svggen/font/table/LangSys.java +58 -0
  82. data/src/org/apache/batik/svggen/font/table/LangSysRecord.java +52 -0
  83. data/src/org/apache/batik/svggen/font/table/Ligature.java +57 -0
  84. data/src/org/apache/batik/svggen/font/table/LigatureSet.java +55 -0
  85. data/src/org/apache/batik/svggen/font/table/LigatureSubst.java +40 -0
  86. data/src/org/apache/batik/svggen/font/table/LigatureSubstFormat1.java +63 -0
  87. data/src/org/apache/batik/svggen/font/table/LocaTable.java +72 -0
  88. data/src/org/apache/batik/svggen/font/table/Lookup.java +77 -0
  89. data/src/org/apache/batik/svggen/font/table/LookupList.java +68 -0
  90. data/src/org/apache/batik/svggen/font/table/LookupSubtable.java +27 -0
  91. data/src/org/apache/batik/svggen/font/table/LookupSubtableFactory.java +31 -0
  92. data/src/org/apache/batik/svggen/font/table/MaxpTable.java +124 -0
  93. data/src/org/apache/batik/svggen/font/table/NameRecord.java +98 -0
  94. data/src/org/apache/batik/svggen/font/table/NameTable.java +67 -0
  95. data/src/org/apache/batik/svggen/font/table/Os2Table.java +232 -0
  96. data/src/org/apache/batik/svggen/font/table/Panose.java +108 -0
  97. data/src/org/apache/batik/svggen/font/table/PostTable.java +379 -0
  98. data/src/org/apache/batik/svggen/font/table/PrepTable.java +38 -0
  99. data/src/org/apache/batik/svggen/font/table/Program.java +49 -0
  100. data/src/org/apache/batik/svggen/font/table/RangeRecord.java +57 -0
  101. data/src/org/apache/batik/svggen/font/table/Script.java +72 -0
  102. data/src/org/apache/batik/svggen/font/table/ScriptList.java +78 -0
  103. data/src/org/apache/batik/svggen/font/table/ScriptRecord.java +52 -0
  104. data/src/org/apache/batik/svggen/font/table/ScriptTags.java +28 -0
  105. data/src/org/apache/batik/svggen/font/table/SingleSubst.java +47 -0
  106. data/src/org/apache/batik/svggen/font/table/SingleSubstFormat1.java +67 -0
  107. data/src/org/apache/batik/svggen/font/table/SingleSubstFormat2.java +67 -0
  108. data/src/org/apache/batik/svggen/font/table/Table.java +204 -0
  109. data/src/org/apache/batik/svggen/font/table/TableDirectory.java +94 -0
  110. data/src/org/apache/batik/svggen/font/table/TableFactory.java +121 -0
  111. metadata +206 -0
@@ -0,0 +1,2045 @@
1
+ /**
2
+ * Copyright 2004-2008 Ricard Marxer <email@ricardmarxer.com>
3
+ *
4
+ * This file is part of Geomerative.
5
+ *
6
+ * Geomerative is free software: you can redistribute it and/or modify it under
7
+ * the terms of the GNU General Public License as published by the Free Software
8
+ * Foundation, either version 3 of the License, or (at your option) any later
9
+ * version.
10
+ *
11
+ * Geomerative is distributed in the hope that it will be useful, but WITHOUT
12
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14
+ * details.
15
+ *
16
+ * You should have received a copy of the GNU General Public License along with
17
+ * Geomerative. If not, see <http://www.gnu.org/licenses/>.
18
+ */
19
+ package geomerative;
20
+
21
+ import processing.core.*;
22
+
23
+ /**
24
+ * RShape is a reduced interface for creating, holding and drawing complex
25
+ * shapes. Shapes are groups of one or more paths (RPath). Shapes can be
26
+ * selfintersecting and can contain holes. This interface also allows you to
27
+ * transform shapes into polygons by segmenting the curves forming the shape.
28
+ *
29
+ * @eexample RShape
30
+ * @usage Geometry
31
+ * @related RPath
32
+ */
33
+ public class RShape extends RGeomElem {
34
+
35
+ /**
36
+ * @invisible
37
+ */
38
+ public int type = RGeomElem.SHAPE;
39
+
40
+ /**
41
+ * Array of RPath objects holding the paths of the polygon.
42
+ *
43
+ * @eexample paths
44
+ * @related RPath
45
+ * @related countPaths ( )
46
+ * @related addPath ( )
47
+ */
48
+ public RPath[] paths = null;
49
+ protected int currentPath = 0;
50
+
51
+ public RShape[] children = null;
52
+ protected int currentChild;
53
+
54
+ // ----------------------
55
+ // --- Public Methods ---
56
+ // ----------------------
57
+ /**
58
+ * Use this method to create a new empty shape.
59
+ *
60
+ * @eexample RShape
61
+ */
62
+ public RShape() {
63
+ type = RGeomElem.SHAPE;
64
+ }
65
+
66
+ public RShape(RPath newpath) {
67
+ this.append(newpath);
68
+ type = RGeomElem.SHAPE;
69
+ }
70
+
71
+ public RShape(RPath[] newpaths) {
72
+ this.paths = newpaths;
73
+ type = RGeomElem.SHAPE;
74
+ }
75
+
76
+ public RShape(RPoint[][] points) {
77
+ if (points == null) {
78
+ return;
79
+ }
80
+
81
+ RPath[] newpaths = new RPath[points.length];
82
+ for (int i = 0; i < points.length; i++) {
83
+ newpaths[i] = new RPath(points[i]);
84
+ }
85
+
86
+ this.paths = newpaths;
87
+ type = RGeomElem.SHAPE;
88
+ }
89
+
90
+ public RShape(RShape s) {
91
+ for (int i = 0; i < s.countPaths(); i++) {
92
+ this.append(new RPath(s.paths[i]));
93
+ }
94
+
95
+ for (int i = 0; i < s.countChildren(); i++) {
96
+ this.appendChild(new RShape(s.children[i]));
97
+ }
98
+
99
+ type = RGeomElem.SHAPE;
100
+
101
+ setStyle(s);
102
+ }
103
+
104
+ /**
105
+ * Use this method to create a new line.
106
+ *
107
+ * @eexample createRing
108
+ * @param x1 x coordinate of the first point of the line
109
+ * @param y1 y coordinate of the first point of the line
110
+ * @param x2 x coordinate of the last point of the line
111
+ * @param y2 y coordinate of the last point of the line
112
+ * @return RShape, the ring polygon newly created
113
+ */
114
+ static public RShape createLine(float x1, float y1, float x2, float y2) {
115
+ RShape line = new RShape();
116
+ RPath path = new RPath();
117
+
118
+ RCommand lineCommand = new RCommand(x1, y1, x2, y2);
119
+ path.addCommand(lineCommand);
120
+ line.addPath(path);
121
+
122
+ return line;
123
+ }
124
+
125
+ /**
126
+ * Use this method to create a new ring polygon.
127
+ *
128
+ * @eexample createRing
129
+ * @param x x coordinate of the center of the shape
130
+ * @param y y coordinate of the center of the shape
131
+ * @param widthBig the outer width of the ring polygon
132
+ * @param widthSmall the inner width of the ring polygon
133
+ * @return RShape, the ring polygon newly created
134
+ */
135
+ static public RShape createRing(float x, float y, float widthBig, float widthSmall) {
136
+ RShape ring = new RShape();
137
+ RShape outer = RShape.createCircle(x, y, widthBig);
138
+ RShape inner = RShape.createCircle(x, y, -widthSmall);
139
+
140
+ ring.addPath(outer.paths[0]);
141
+ ring.addPath(inner.paths[0]);
142
+
143
+ return ring;
144
+ }
145
+
146
+ /**
147
+ * Use this method to create a new starform polygon.
148
+ *
149
+ * @param x
150
+ * @param y
151
+ * @eexample createStar
152
+ * @param widthBig the outer width of the star polygon
153
+ * @param widthSmall the inner width of the star polygon
154
+ * @param spikes the amount of spikes on the star polygon
155
+ * @return RShape, the starform polygon newly created
156
+ */
157
+ static public RShape createStar(float x, float y, float widthBig, float widthSmall, int spikes) {
158
+ float radiusBig = widthBig / 2F;
159
+ float radiusSmall = widthSmall / 2F;
160
+ RShape star = new RShape();
161
+ star.addMoveTo(x - radiusBig, y);
162
+ star.addLineTo(x - (float) (radiusSmall * Math.cos(Math.PI / spikes)), y - (float) (radiusSmall * Math.sin(Math.PI / spikes)));
163
+
164
+ for (int i = 2; i < 2 * spikes; i += 2) {
165
+ star.addLineTo(x - (float) (radiusBig * Math.cos(Math.PI * i / spikes)), y - (float) (radiusBig * Math.sin(Math.PI * i / spikes)));
166
+ star.addLineTo(x - (float) (radiusSmall * Math.cos(Math.PI * (i + 1) / spikes)), y - (float) (radiusSmall * Math.sin(Math.PI * (i + 1) / spikes)));
167
+ }
168
+
169
+ star.addClose();
170
+
171
+ return star;
172
+ }
173
+
174
+ /**
175
+ * Use this method to create a new circle shape.
176
+ *
177
+ * @eexample createRectangle
178
+ * @param x the x position of the rectangle
179
+ * @param y the y position of the rectangle
180
+ * @param w the width of the rectangle
181
+ * @param h the height of the rectangle
182
+ * @return RShape, the rectangular shape just created
183
+ */
184
+ static public RShape createRectangle(float x, float y, float w, float h) {
185
+ RShape rect = new RShape();
186
+ rect.addMoveTo(x, y);
187
+ rect.addLineTo(x + w, y);
188
+ rect.addLineTo(x + w, y + h);
189
+ rect.addLineTo(x, y + h);
190
+ rect.addLineTo(x, y);
191
+ return rect;
192
+ }
193
+
194
+ /**
195
+ * Use this method to create a new elliptical shape.
196
+ *
197
+ * @eexample createEllipse
198
+ * @param x the x position of the ellipse
199
+ * @param y the y position of the ellipse
200
+ * @param w the width of the ellipse
201
+ * @param h the height of the ellipse
202
+ * @return RShape, the elliptical shape just created
203
+ */
204
+ static public RShape createEllipse(float x, float y, float w, float h) {
205
+ float rx = w / 2F;
206
+ float ry = h / 2F;
207
+ RPoint center = new RPoint(x, y);
208
+ RShape circle = new RShape();
209
+ float kx = (((8F / (float) Math.sqrt(2F)) - 4F) / 3F) * rx;
210
+ float ky = (((8F / (float) Math.sqrt(2F)) - 4F) / 3F) * ry;
211
+ circle.addMoveTo(center.x, center.y - ry);
212
+ circle.addBezierTo(center.x + kx, center.y - ry, center.x + rx, center.y - ky, center.x + rx, center.y);
213
+ circle.addBezierTo(center.x + rx, center.y + ky, center.x + kx, center.y + ry, center.x, center.y + ry);
214
+ circle.addBezierTo(center.x - kx, center.y + ry, center.x - rx, center.y + ky, center.x - rx, center.y);
215
+ circle.addBezierTo(center.x - rx, center.y - ky, center.x - kx, center.y - ry, center.x, center.y - ry);
216
+ circle.addClose();
217
+ return circle;
218
+ }
219
+
220
+ static public RShape createCircle(float x, float y, float d) {
221
+ return createEllipse(x, y, d, d);
222
+ }
223
+
224
+ /**
225
+ *
226
+ * Extracts a shape by its name. The shape is returned as an RShape object,
227
+ * or null is returned if no shape with the name has been found.
228
+ *
229
+ * @param target
230
+ * @return RShape or null, the target shape or null if not found
231
+ *
232
+ */
233
+ public RShape getChild(String target) {
234
+ if (this.name.equals(target)) {
235
+ return this;
236
+ }
237
+
238
+ for (int i = 0; i < countChildren(); i++) {
239
+ RShape shp = children[i].getChild(target);
240
+ if (shp != null) {
241
+ return shp;
242
+ }
243
+ }
244
+
245
+ return null;
246
+ }
247
+
248
+ /**
249
+ * Use this method to get the centroid of the element.
250
+ *
251
+ * @eexample RGroup_getCentroid
252
+ * @return RPoint, the centroid point of the element
253
+ * @related getBounds ( )
254
+ * @related getCenter ( )
255
+ */
256
+ @Override
257
+ public RPoint getCentroid() {
258
+ RPoint bestCentroid = new RPoint();
259
+ float bestArea = Float.NEGATIVE_INFINITY;
260
+ if (paths != null) {
261
+ for (RPath path : paths) {
262
+ float area = Math.abs(path.getArea());
263
+ if (area > bestArea) {
264
+ bestArea = area;
265
+ bestCentroid = path.getCentroid();
266
+ }
267
+ }
268
+ return bestCentroid;
269
+ }
270
+ return null;
271
+ }
272
+
273
+ /**
274
+ * Use this method to count the number of paths in the shape.
275
+ *
276
+ * @eexample countPaths
277
+ * @return
278
+ * @related addPath ( )
279
+ */
280
+
281
+ public int countPaths() {
282
+ if (this.paths == null) {
283
+ return 0;
284
+ }
285
+
286
+ return this.paths.length;
287
+ }
288
+
289
+ public int countChildren() {
290
+ if (this.children == null) {
291
+ return 0;
292
+ }
293
+
294
+ return this.children.length;
295
+ }
296
+
297
+ /**
298
+ * Use this method to add a new shape. The paths of the shape we are adding
299
+ * will simply be added to the current shape.
300
+ *
301
+ * @eexample addShape
302
+ * @param s RShape, the shape to be added.
303
+ * @related setPath ( )
304
+ * @related addMoveTo ( )
305
+ * @invisible
306
+ */
307
+ public void addShape(RShape s) {
308
+ for (int i = 0; i < s.countPaths(); i++) {
309
+ this.append(s.paths[i]);
310
+ }
311
+ }
312
+
313
+ /**
314
+ * Use this method to create a new path. The first point of the new path
315
+ * will be set to (0,0). Use addMoveTo ( ) in order to add a new path with a
316
+ * different first point.
317
+ *
318
+ * @eexample addPath
319
+ * @param s the path to be added.
320
+ * @related setPath ( )
321
+ * @related addMoveTo ( )
322
+ */
323
+ public void addPath(RPath s) {
324
+ this.append(s);
325
+ }
326
+
327
+ public void addPath() {
328
+ this.append(new RPath());
329
+ }
330
+
331
+ public void addChild() {
332
+ this.appendChild(new RShape());
333
+ }
334
+
335
+ public void addChild(RShape s) {
336
+ this.appendChild(s);
337
+ }
338
+
339
+ /**
340
+ * Use this method to set the current path.
341
+ *
342
+ * @param indPath
343
+ * @eexample setPath
344
+ * @related addMoveTo ( )
345
+ * @related addLineTo ( )
346
+ * @related addQuadTo ( )
347
+ * @related addBezierTo ( )
348
+ * @related addPath ( )
349
+ */
350
+ public void setPath(int indPath) {
351
+ this.currentPath = indPath;
352
+ }
353
+
354
+ /**
355
+ * Use this method to add a new moveTo command to the shape. The command
356
+ * moveTo acts different to normal commands, in order to make a better
357
+ * analogy to its borthers classes Polygon and Mesh. MoveTo creates a new
358
+ * path in the shape. It's similar to adding a new contour to a polygon.
359
+ *
360
+ * @eexample addMoveTo
361
+ * @param endx the x coordinate of the first point for the new path.
362
+ * @param endy the y coordinate of the first point for the new path.
363
+ * @related addLineTo ( )
364
+ * @related addQuadTo ( )
365
+ * @related addBezierTo ( )
366
+ * @related addPath ( )
367
+ * @related setPath ( )
368
+ */
369
+ public void addMoveTo(float endx, float endy) {
370
+ if (paths == null) {
371
+ this.append(new RPath(endx, endy));
372
+ } else if (paths[currentPath].countCommands() == 0) {
373
+ this.paths[currentPath].lastPoint = new RPoint(endx, endy);
374
+ } else {
375
+ this.append(new RPath(endx, endy));
376
+ }
377
+ }
378
+
379
+ public void addMoveTo(RPoint p) {
380
+ addMoveTo(p.x, p.y);
381
+ }
382
+
383
+ /**
384
+ * Use this method to add a new lineTo command to the current path. This
385
+ * will add a line from the last point added to the point passed as
386
+ * argument.
387
+ *
388
+ * @eexample addLineTo
389
+ * @param endx the x coordinate of the ending point of the line.
390
+ * @param endy the y coordinate of the ending point of the line.
391
+ * @related addMoveTo ( )
392
+ * @related addQuadTo ( )
393
+ * @related addBezierTo ( )
394
+ * @related addPath ( )
395
+ * @related setPath ( )
396
+ */
397
+ public void addLineTo(float endx, float endy) {
398
+ if (paths == null) {
399
+ this.append(new RPath());
400
+ }
401
+ this.paths[currentPath].addLineTo(endx, endy);
402
+ }
403
+
404
+ public void addLineTo(RPoint p) {
405
+ addLineTo(p.x, p.y);
406
+ }
407
+
408
+ /**
409
+ * Use this method to add a new quadTo command to the current path. This
410
+ * will add a quadratic bezier from the last point added with the control
411
+ * and ending points passed as arguments.
412
+ *
413
+ * @eexample addQuadTo
414
+ * @param cp1x the x coordinate of the control point of the bezier.
415
+ * @param cp1y the y coordinate of the control point of the bezier.
416
+ * @param endx the x coordinate of the ending point of the bezier.
417
+ * @param endy the y coordinate of the ending point of the bezier.
418
+ * @related addMoveTo ( )
419
+ * @related addLineTo ( )
420
+ * @related addBezierTo ( )
421
+ * @related addPath ( )
422
+ * @related setPath ( )
423
+ */
424
+ public void addQuadTo(float cp1x, float cp1y, float endx, float endy) {
425
+ if (paths == null) {
426
+ this.append(new RPath());
427
+ }
428
+ this.paths[currentPath].addQuadTo(cp1x, cp1y, endx, endy);
429
+ }
430
+
431
+ public void addQuadTo(RPoint p1, RPoint p2) {
432
+ addQuadTo(p1.x, p1.y, p2.x, p2.y);
433
+ }
434
+
435
+ /**
436
+ * Use this method to add a new bezierTo command to the current path. This
437
+ * will add a cubic bezier from the last point added with the control and
438
+ * ending points passed as arguments.
439
+ *
440
+ * @eexample addArcTo
441
+ * @param cp1x the x coordinate of the first control point of the bezier.
442
+ * @param cp1y the y coordinate of the first control point of the bezier.
443
+ * @param cp2x the x coordinate of the second control point of the bezier.
444
+ * @param cp2y the y coordinate of the second control point of the bezier.
445
+ * @param endx the x coordinate of the ending point of the bezier.
446
+ * @param endy the y coordinate of the ending point of the bezier.
447
+ * @related addMoveTo ( )
448
+ * @related addLineTo ( )
449
+ * @related addQuadTo ( )
450
+ * @related addPath ( )
451
+ * @related setPath ( )
452
+ */
453
+ public void addBezierTo(float cp1x, float cp1y, float cp2x, float cp2y, float endx, float endy) {
454
+ if (paths == null) {
455
+ this.append(new RPath());
456
+ }
457
+ this.paths[currentPath].addBezierTo(cp1x, cp1y, cp2x, cp2y, endx, endy);
458
+ }
459
+
460
+ public void addBezierTo(RPoint p1, RPoint p2, RPoint p3) {
461
+ addBezierTo(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y);
462
+ }
463
+
464
+ public void addClose() {
465
+ if (paths == null) {
466
+ this.append(new RPath());
467
+ }
468
+ this.paths[currentPath].addClose();
469
+ }
470
+
471
+ /**
472
+ * Use this method to create a new mesh from a given polygon.
473
+ *
474
+ * @eexample toMesh
475
+ * @return RMesh, the mesh made of tristrips resulting of a tesselation of
476
+ * the polygonization followed by tesselation of the shape.
477
+ * @related draw ( )
478
+ */
479
+ @Override
480
+ public RMesh toMesh() {
481
+ return toPolygon().toMesh();
482
+ }
483
+
484
+ /**
485
+ * Use this method to create a new polygon from a given shape.
486
+ *
487
+ * @eexample toPolygon
488
+ * @return RPolygon, the polygon resulting of the segmentation of the
489
+ * commands in each path.
490
+ * @related draw ( )
491
+ */
492
+ @Override
493
+ public RPolygon toPolygon() {
494
+ int numPnts = this.countPaths();
495
+
496
+ RPolygon poly = new RPolygon();
497
+
498
+ if (this.children != null) {
499
+ for (RShape children1 : this.children) {
500
+ RPolygon childPoly = children1.toPolygon();
501
+ for (RContour contour : childPoly.contours) {
502
+ poly.addContour(contour);
503
+ }
504
+ }
505
+ }
506
+
507
+ for (int i = 0; i < numPnts; i++) {
508
+ RPoint[] pnts = this.paths[i].getPoints();
509
+ RContour c = new RContour(pnts);
510
+ c.closed = this.paths[i].closed;
511
+ c.setStyle(this.paths[i]);
512
+ poly.addContour(c);
513
+ }
514
+
515
+ return poly;
516
+ }
517
+
518
+ public void polygonize() {
519
+ int numPaths = countPaths();
520
+
521
+ for (int i = 0; i < numPaths; i++) {
522
+ this.paths[i].polygonize();
523
+ }
524
+
525
+ for (int i = 0; i < countChildren(); i++) {
526
+ this.children[i].polygonize();
527
+ }
528
+ }
529
+
530
+ /**
531
+ * @return
532
+ * @invisible
533
+ */
534
+ @Override
535
+ public RShape toShape() {
536
+ return this;
537
+ }
538
+
539
+ /**
540
+ * Use this method to get the intersection of this polygon with the polygon
541
+ * passed in as a parameter.
542
+ *
543
+ * @eexample intersection
544
+ * @param p RShape, the polygon with which to perform the intersection
545
+ * @return RShape, the intersection of the two polygons
546
+ * @related union ( )
547
+ * @related xor ( )
548
+ * @related diff ( )
549
+ */
550
+ public RShape intersection(RShape p) {
551
+ int numPaths = countPaths();
552
+ RPolygon ppoly = p.toPolygon();
553
+
554
+ RShape result = new RShape();
555
+
556
+ RShape temp = new RShape();
557
+ for (int i = 0; i < numPaths; i++) {
558
+ temp.addPath(this.paths[i]);
559
+ }
560
+
561
+ RPolygon resPolPaths = RClip.intersection(temp.toPolygon(), ppoly);
562
+ if (resPolPaths != null) {
563
+ RShape resPaths = resPolPaths.toShape();
564
+ for (int i = 0; i < resPaths.countPaths(); i++) {
565
+ result.addPath(resPaths.paths[i]);
566
+ }
567
+ }
568
+
569
+ for (int i = 0; i < countChildren(); i++) {
570
+ RShape resChildren = this.children[i].intersection(p);
571
+ if (resChildren != null) {
572
+ result.addChild(resChildren);
573
+ }
574
+ }
575
+
576
+
577
+ result.setStyle(this);
578
+
579
+
580
+ return result;
581
+
582
+ /*
583
+ RPolygon result = RClip.intersection( this.toPolygon(),p.toPolygon() );
584
+
585
+ if (result == null) return null;
586
+
587
+ return result.toShape();
588
+ */
589
+ }
590
+
591
+ /**
592
+ * Use this method to get the union of this polygon with the polygon passed
593
+ * in as a parameter.
594
+ *
595
+ * @eexample union
596
+ * @param p RShape, the polygon with which to perform the union
597
+ * @return RShape, the union of the two polygons
598
+ * @related intersection ( )
599
+ * @related xor ( )
600
+ * @related diff ( )
601
+ */
602
+ public RShape union(RShape p) {
603
+ int numPaths = countPaths();
604
+ RPolygon ppoly = p.toPolygon();
605
+
606
+ RShape result = new RShape();
607
+
608
+ RShape temp = new RShape();
609
+ for (int i = 0; i < numPaths; i++) {
610
+ temp.addPath(this.paths[i]);
611
+ }
612
+
613
+ RPolygon resPolPaths = RClip.union(temp.toPolygon(), ppoly);
614
+ if (resPolPaths != null) {
615
+ RShape resPaths = resPolPaths.toShape();
616
+ for (int i = 0; i < resPaths.countPaths(); i++) {
617
+ result.addPath(resPaths.paths[i]);
618
+ }
619
+ }
620
+
621
+ for (int i = 0; i < countChildren(); i++) {
622
+ RShape resChildren = this.children[i].union(p);
623
+ if (resChildren != null) {
624
+ result.addChild(resChildren);
625
+ }
626
+ }
627
+ result.setStyle(this);
628
+ return result;
629
+
630
+ /*
631
+ RPolygon result = RClip.union( this.toPolygon(), p.toPolygon() );
632
+
633
+ if (result == null) return null;
634
+
635
+ return result.toShape();
636
+ */
637
+ }
638
+
639
+ /**
640
+ * Use this method to get the xor of this polygon with the polygon passed in
641
+ * as a parameter.
642
+ *
643
+ * @eexample xor
644
+ * @param p RShape, the polygon with which to perform the xor
645
+ * @return RShape, the xor of the two polygons
646
+ * @related union ( )
647
+ * @related intersection ( )
648
+ * @related diff ( )
649
+ */
650
+ public RShape xor(RShape p) {
651
+ int numPaths = countPaths();
652
+ RPolygon ppoly = p.toPolygon();
653
+
654
+ RShape result = new RShape();
655
+
656
+ RShape temp = new RShape();
657
+ for (int i = 0; i < numPaths; i++) {
658
+ temp.addPath(this.paths[i]);
659
+ }
660
+
661
+ RPolygon resPolPaths = RClip.xor(temp.toPolygon(), ppoly);
662
+ if (resPolPaths != null) {
663
+ RShape resPaths = resPolPaths.toShape();
664
+ for (int i = 0; i < resPaths.countPaths(); i++) {
665
+ result.addPath(resPaths.paths[i]);
666
+ }
667
+ }
668
+
669
+ for (int i = 0; i < countChildren(); i++) {
670
+ RShape resChildren = this.children[i].xor(p);
671
+ if (resChildren != null) {
672
+ result.addChild(resChildren);
673
+ }
674
+ }
675
+
676
+ result.setStyle(this);
677
+
678
+
679
+ return result;
680
+
681
+ /*
682
+ RPolygon result = RClip.xor( this.toPolygon(), p.toPolygon() );
683
+
684
+ if (result == null) return null;
685
+
686
+ return result.toShape();
687
+ */
688
+ }
689
+
690
+ /**
691
+ * Use this method to get the difference between this polygon and the
692
+ * polygon passed in as a parameter.
693
+ *
694
+ * @eexample diff
695
+ * @param p RShape, the polygon with which to perform the difference
696
+ * @return RShape, the difference of the two polygons
697
+ * @related union ( )
698
+ * @related xor ( )
699
+ * @related intersection ( )
700
+ */
701
+ public RShape diff(RShape p) {
702
+ int numPaths = countPaths();
703
+ RPolygon ppoly = p.toPolygon();
704
+
705
+ RShape result = new RShape();
706
+
707
+ RShape temp = new RShape();
708
+ for (int i = 0; i < numPaths; i++) {
709
+ temp.addPath(this.paths[i]);
710
+ }
711
+
712
+ RPolygon resPolPaths = RClip.diff(temp.toPolygon(), ppoly);
713
+ if (resPolPaths != null) {
714
+ RShape resPaths = resPolPaths.toShape();
715
+ for (int i = 0; i < resPaths.countPaths(); i++) {
716
+ result.addPath(resPaths.paths[i]);
717
+ }
718
+ }
719
+
720
+ for (int i = 0; i < countChildren(); i++) {
721
+ RShape resChildren = this.children[i].diff(p);
722
+ if (resChildren != null) {
723
+ result.addChild(resChildren);
724
+ }
725
+ }
726
+
727
+ result.setStyle(this);
728
+ return result;
729
+
730
+ /*
731
+ RPolygon result = RClip.diff( this.toPolygon(), p.toPolygon() );
732
+
733
+ if (result == null) return null;
734
+
735
+ return result.toShape();
736
+ */
737
+ }
738
+
739
+ /**
740
+ * Use this to return the start, control and end points of the shape. It
741
+ * returns the points as an array of RPoint.
742
+ *
743
+ * @eexample RShape_getHandles
744
+ * @return RPoint[], the start, control and end points returned in an array.
745
+ *
746
+ */
747
+ @Override
748
+ public RPoint[] getHandles() {
749
+ int numPaths = countPaths();
750
+
751
+ RPoint[] result = null;
752
+ RPoint[] newresult = null;
753
+ for (int i = 0; i < numPaths; i++) {
754
+ RPoint[] newPoints = paths[i].getHandles();
755
+ if (newPoints != null) {
756
+ if (result == null) {
757
+ result = new RPoint[newPoints.length];
758
+ System.arraycopy(newPoints, 0, result, 0, newPoints.length);
759
+ } else {
760
+ newresult = new RPoint[result.length + newPoints.length];
761
+ System.arraycopy(result, 0, newresult, 0, result.length);
762
+ System.arraycopy(newPoints, 0, newresult, result.length, newPoints.length);
763
+ result = newresult;
764
+ }
765
+ }
766
+ }
767
+
768
+ for (int i = 0; i < countChildren(); i++) {
769
+ RPoint[] newPoints = children[i].getHandles();
770
+ if (newPoints != null) {
771
+ if (result == null) {
772
+ result = new RPoint[newPoints.length];
773
+ System.arraycopy(newPoints, 0, result, 0, newPoints.length);
774
+ } else {
775
+ newresult = new RPoint[result.length + newPoints.length];
776
+ System.arraycopy(result, 0, newresult, 0, result.length);
777
+ System.arraycopy(newPoints, 0, newresult, result.length, newPoints.length);
778
+ result = newresult;
779
+ }
780
+ }
781
+ }
782
+
783
+ return result;
784
+ }
785
+
786
+ /**
787
+ * Use this to return a point on the curve given a certain advancement. It
788
+ * returns the point as an RPoint.
789
+ *
790
+ * @param t
791
+ * @eexample RShape_getPoints
792
+ * @return RPoint[], the point on the curve.
793
+ *
794
+ */
795
+ @Override
796
+ public RPoint getPoint(float t) {
797
+ float[] indAndAdv = indAndAdvAt(t);
798
+ int indOfElement = (int) (indAndAdv[0]);
799
+ float advOfElement = indAndAdv[1];
800
+
801
+ if (indOfElement < countPaths()) {
802
+ return paths[indOfElement].getPoint(advOfElement);
803
+ } else {
804
+ return children[indOfElement - countPaths()].getPoint(advOfElement);
805
+ }
806
+ }
807
+
808
+ /**
809
+ * Use this to return the points on the curve of the shape. It returns the
810
+ * points as an array of RPoint.
811
+ *
812
+ * @eexample RShape_getPoints
813
+ * @return RPoint[], the points returned in an array.
814
+ *
815
+ */
816
+ @Override
817
+ public RPoint[] getPoints() {
818
+ int numPaths = countPaths();
819
+
820
+ RCommand.segmentAccOffset = RCommand.segmentOffset;
821
+ RPoint[] result = null;
822
+ RPoint[] newresult = null;
823
+ for (int i = 0; i < numPaths; i++) {
824
+ RPoint[] newPoints = paths[i].getPoints();
825
+ if (newPoints != null) {
826
+ if (result == null) {
827
+ result = new RPoint[newPoints.length];
828
+ System.arraycopy(newPoints, 0, result, 0, newPoints.length);
829
+ } else {
830
+ newresult = new RPoint[result.length + newPoints.length];
831
+ System.arraycopy(result, 0, newresult, 0, result.length);
832
+ System.arraycopy(newPoints, 0, newresult, result.length, newPoints.length);
833
+ result = newresult;
834
+ }
835
+ }
836
+ }
837
+
838
+ for (int i = 0; i < countChildren(); i++) {
839
+ RPoint[] newPoints = children[i].getPoints();
840
+ if (newPoints != null) {
841
+ if (result == null) {
842
+ result = new RPoint[newPoints.length];
843
+ System.arraycopy(newPoints, 0, result, 0, newPoints.length);
844
+ } else {
845
+ newresult = new RPoint[result.length + newPoints.length];
846
+ System.arraycopy(result, 0, newresult, 0, result.length);
847
+ System.arraycopy(newPoints, 0, newresult, result.length, newPoints.length);
848
+ result = newresult;
849
+ }
850
+ }
851
+ }
852
+
853
+ return result;
854
+ }
855
+
856
+ /**
857
+ * Use this to return a point on the curve given a certain advancement. It
858
+ * returns the point as an RPoint.
859
+ *
860
+ * @param t
861
+ * @eexample RShape_getTangents
862
+ * @return RPoint[], the point on the curve.
863
+ *
864
+ */
865
+ @Override
866
+ public RPoint getTangent(float t) {
867
+ float[] indAndAdv = indAndAdvAt(t);
868
+ int indOfElement = (int) (indAndAdv[0]);
869
+ float advOfElement = indAndAdv[1];
870
+
871
+ if (indOfElement < countPaths()) {
872
+ return paths[indOfElement].getTangent(advOfElement);
873
+ } else {
874
+ return children[indOfElement - countPaths()].getTangent(advOfElement);
875
+ }
876
+ }
877
+
878
+ /**
879
+ * Use this to return a specific tangent on the curve. It returns true if
880
+ * the point passed as a parameter is inside the shape. Implementation taken
881
+ * from:
882
+ * http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
883
+ *
884
+ * @param x the X coordinate of the point for which to test containment.
885
+ * @param y the Y coordinate of the point for which to test containment.
886
+ * @return boolean, true if the point is in the path.
887
+ *
888
+ */
889
+ public boolean contains(float x, float y) {
890
+ return contains(new RPoint(x, y));
891
+ }
892
+
893
+ /**
894
+ * Use this to return a specific tangent on the curve. It returns true if
895
+ * the point passed as a parameter is inside the shape. Implementation taken
896
+ * from:
897
+ * http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
898
+ *
899
+ * @param p the point for which to test containment.
900
+ * @return boolean, true if the point is in the path.
901
+ *
902
+ */
903
+ @Override
904
+ public boolean contains(RPoint p) {
905
+ float testx = p.x;
906
+ float testy = p.y;
907
+
908
+ // Test for containment in bounding box
909
+ RRectangle bbox = getBounds();
910
+ float xmin = bbox.getMinX();
911
+ float xmax = bbox.getMaxX();
912
+
913
+ float ymin = bbox.getMinY();
914
+ float ymax = bbox.getMaxY();
915
+
916
+ if ((testx < xmin) || (testx > xmax) || (testy < ymin) || (testy > ymax)) {
917
+ return false;
918
+ }
919
+ // Test for containment in shape
920
+ RPoint[][] pointpaths = getPointsInPaths();
921
+ if (pointpaths == null) {
922
+ return false;
923
+ }
924
+ RPoint[] verts = pointpaths[0];
925
+ for (int k = 1; k < pointpaths.length; k++) {
926
+ verts = (RPoint[]) PApplet.append(verts, new RPoint(0F, 0F));
927
+ verts = (RPoint[]) PApplet.concat(verts, pointpaths[k]);
928
+ }
929
+ verts = (RPoint[]) PApplet.append(verts, new RPoint(0F, 0F));
930
+ if (verts == null) {
931
+ return false;
932
+ }
933
+ int nvert = verts.length;
934
+ int i, j = 0;
935
+ boolean c = false;
936
+ for (i = 0, j = nvert - 1; i < nvert; j = i++) {
937
+ if (((verts[i].y > testy) != (verts[j].y > testy))
938
+ && (testx < (verts[j].x - verts[i].x) * (testy - verts[i].y) / (verts[j].y - verts[i].y) + verts[i].x)) {
939
+ c = !c;
940
+ }
941
+ }
942
+ return c;
943
+ }
944
+
945
+ /**
946
+ * Use this to return the points on the curve of the shape. It returns the
947
+ * point as an RPoint.
948
+ *
949
+ * @eexample RShape_getTangents
950
+ * @return RPoint[], the points returned in an array.
951
+ *
952
+ */
953
+ public RPoint[] getTangents() {
954
+ int numPaths = countPaths();
955
+
956
+ RPoint[] result = null;
957
+ RPoint[] newresult = null;
958
+ for (int i = 0; i < numPaths; i++) {
959
+ RPoint[] newPoints = paths[i].getTangents();
960
+ if (newPoints != null) {
961
+ if (result == null) {
962
+ result = new RPoint[newPoints.length];
963
+ System.arraycopy(newPoints, 0, result, 0, newPoints.length);
964
+ } else {
965
+ newresult = new RPoint[result.length + newPoints.length];
966
+ System.arraycopy(result, 0, newresult, 0, result.length);
967
+ System.arraycopy(newPoints, 0, newresult, result.length, newPoints.length);
968
+ result = newresult;
969
+ }
970
+ }
971
+ }
972
+
973
+ for (int i = 0; i < countChildren(); i++) {
974
+ RPoint[] newPoints = children[i].getTangents();
975
+ if (newPoints != null) {
976
+ if (result == null) {
977
+ result = new RPoint[newPoints.length];
978
+ System.arraycopy(newPoints, 0, result, 0, newPoints.length);
979
+ } else {
980
+ newresult = new RPoint[result.length + newPoints.length];
981
+ System.arraycopy(result, 0, newresult, 0, result.length);
982
+ System.arraycopy(newPoints, 0, newresult, result.length, newPoints.length);
983
+ result = newresult;
984
+ }
985
+ }
986
+ }
987
+ return result;
988
+ }
989
+
990
+ /**
991
+ * Use this to return the points of each path of the group. It returns the
992
+ * points as an array of arrays of RPoint.
993
+ *
994
+ * @eexample RGroup_getPoints
995
+ * @return RPoint[], the points returned in an array.
996
+ *
997
+ */
998
+ public RPoint[][] getPointsInPaths() {
999
+ int numPaths = countPaths();
1000
+
1001
+ RPoint[][] result = null;
1002
+ RPoint[][] newresult = null;
1003
+ for (int i = 0; i < numPaths; i++) {
1004
+ RPoint[][] newPointPaths = paths[i].getPointsInPaths();
1005
+ if (newPointPaths != null) {
1006
+ if (result == null) {
1007
+ result = new RPoint[newPointPaths.length][];
1008
+ System.arraycopy(newPointPaths, 0, result, 0, newPointPaths.length);
1009
+ } else {
1010
+ newresult = new RPoint[result.length + newPointPaths.length][];
1011
+ System.arraycopy(result, 0, newresult, 0, result.length);
1012
+ System.arraycopy(newPointPaths, 0, newresult, result.length, newPointPaths.length);
1013
+ result = newresult;
1014
+ }
1015
+ }
1016
+ }
1017
+
1018
+ for (int i = 0; i < countChildren(); i++) {
1019
+ RPoint[][] newPoints = children[i].getPointsInPaths();
1020
+ if (newPoints != null) {
1021
+ if (result == null) {
1022
+ result = new RPoint[newPoints.length][];
1023
+ System.arraycopy(newPoints, 0, result, 0, newPoints.length);
1024
+ } else {
1025
+ newresult = new RPoint[result.length + newPoints.length][];
1026
+ System.arraycopy(result, 0, newresult, 0, result.length);
1027
+ System.arraycopy(newPoints, 0, newresult, result.length, newPoints.length);
1028
+ result = newresult;
1029
+ }
1030
+ }
1031
+ }
1032
+
1033
+ return result;
1034
+ }
1035
+
1036
+ /**
1037
+ *
1038
+ * @return
1039
+ */
1040
+ @Override
1041
+ public RPoint[][] getHandlesInPaths() {
1042
+ int numPaths = countPaths();
1043
+
1044
+ RPoint[][] result = null;
1045
+ RPoint[][] newresult = null;
1046
+ for (int i = 0; i < numPaths; i++) {
1047
+ RPoint[][] newHandlePaths = paths[i].getHandlesInPaths();
1048
+ if (newHandlePaths != null) {
1049
+ if (result == null) {
1050
+ result = new RPoint[newHandlePaths.length][];
1051
+ System.arraycopy(newHandlePaths, 0, result, 0, newHandlePaths.length);
1052
+ } else {
1053
+ newresult = new RPoint[result.length + newHandlePaths.length][];
1054
+ System.arraycopy(result, 0, newresult, 0, result.length);
1055
+ System.arraycopy(newHandlePaths, 0, newresult, result.length, newHandlePaths.length);
1056
+ result = newresult;
1057
+ }
1058
+ }
1059
+ }
1060
+
1061
+ for (int i = 0; i < countChildren(); i++) {
1062
+ RPoint[][] newPoints = children[i].getHandlesInPaths();
1063
+ if (newPoints != null) {
1064
+ if (result == null) {
1065
+ result = new RPoint[newPoints.length][];
1066
+ System.arraycopy(newPoints, 0, result, 0, newPoints.length);
1067
+ } else {
1068
+ newresult = new RPoint[result.length + newPoints.length][];
1069
+ System.arraycopy(result, 0, newresult, 0, result.length);
1070
+ System.arraycopy(newPoints, 0, newresult, result.length, newPoints.length);
1071
+ result = newresult;
1072
+ }
1073
+ }
1074
+ }
1075
+
1076
+ return result;
1077
+ }
1078
+
1079
+ @Override
1080
+ public RPoint[][] getTangentsInPaths() {
1081
+ int numPaths = countPaths();
1082
+ if (numPaths == 0) {
1083
+ return null;
1084
+ }
1085
+
1086
+ RPoint[][] result = null;
1087
+ RPoint[][] newresult = null;
1088
+ for (int i = 0; i < numPaths; i++) {
1089
+ RPoint[][] newTangentPaths = paths[i].getTangentsInPaths();
1090
+ if (newTangentPaths != null) {
1091
+ if (result == null) {
1092
+ result = new RPoint[newTangentPaths.length][];
1093
+ System.arraycopy(newTangentPaths, 0, result, 0, newTangentPaths.length);
1094
+ } else {
1095
+ newresult = new RPoint[result.length + newTangentPaths.length][];
1096
+ System.arraycopy(result, 0, newresult, 0, result.length);
1097
+ System.arraycopy(newTangentPaths, 0, newresult, result.length, newTangentPaths.length);
1098
+ result = newresult;
1099
+ }
1100
+ }
1101
+ }
1102
+
1103
+ for (int i = 0; i < countChildren(); i++) {
1104
+ RPoint[][] newPoints = children[i].getTangentsInPaths();
1105
+ if (newPoints != null) {
1106
+ if (result == null) {
1107
+ result = new RPoint[newPoints.length][];
1108
+ System.arraycopy(newPoints, 0, result, 0, newPoints.length);
1109
+ } else {
1110
+ newresult = new RPoint[result.length + newPoints.length][];
1111
+ System.arraycopy(result, 0, newresult, 0, result.length);
1112
+ System.arraycopy(newPoints, 0, newresult, result.length, newPoints.length);
1113
+ result = newresult;
1114
+ }
1115
+ }
1116
+ }
1117
+
1118
+ return result;
1119
+ }
1120
+
1121
+ public RShape[] splitPaths(float t) {
1122
+ RShape[] result = new RShape[2];
1123
+ result[0] = new RShape();
1124
+ result[1] = new RShape();
1125
+
1126
+ for (int i = 0; i < countPaths(); i++) {
1127
+ RPath[] splittedPaths = paths[i].split(t);
1128
+ if (splittedPaths != null) {
1129
+ result[0].addPath(splittedPaths[0]);
1130
+ result[1].addPath(splittedPaths[1]);
1131
+ }
1132
+ }
1133
+
1134
+ for (int i = 0; i < countChildren(); i++) {
1135
+ RShape[] splittedPaths = children[i].splitPaths(t);
1136
+ if (splittedPaths != null) {
1137
+ result[0].addChild(splittedPaths[0]);
1138
+ result[1].addChild(splittedPaths[1]);
1139
+ }
1140
+ }
1141
+
1142
+ result[0].setStyle(this);
1143
+ result[1].setStyle(this);
1144
+ return result;
1145
+ }
1146
+
1147
+ /**
1148
+ * Use this to insert a split point into the shape.
1149
+ *
1150
+ * @eexample insertHandle
1151
+ * @param t the parameter of advancement on the curve. t must have values
1152
+ * between 0 and 1.
1153
+ *
1154
+ */
1155
+ public void insertHandle(float t) {
1156
+ if ((t == 0F) || (t == 1F)) {
1157
+ return;
1158
+ }
1159
+
1160
+ float[] indAndAdv = indAndAdvAt(t);
1161
+ int indOfElement = (int) (indAndAdv[0]);
1162
+ float advOfElement = indAndAdv[1];
1163
+
1164
+ if (indOfElement < countPaths()) {
1165
+ paths[indOfElement].insertHandle(advOfElement);
1166
+ } else {
1167
+ children[indOfElement - countPaths()].insertHandle(advOfElement);
1168
+ }
1169
+ // Clear the cache
1170
+ lenCurves = null;
1171
+ lenCurve = -1F;
1172
+ }
1173
+
1174
+ /**
1175
+ * Use this to insert a split point into each command of the shape.
1176
+ *
1177
+ * @eexample insertHandleInPaths
1178
+ * @param t the parameter of advancement on the curve. t must have values
1179
+ * between 0 and 1.
1180
+ *
1181
+ */
1182
+ public void insertHandleInPaths(float t) {
1183
+ if ((t == 0F) || (t == 1F)) {
1184
+ return;
1185
+ }
1186
+
1187
+ int numPaths = countPaths();
1188
+ if (numPaths == 0) {
1189
+ return;
1190
+ }
1191
+
1192
+ for (int i = 0; i < numPaths; i++) {
1193
+ paths[i].insertHandleInPaths(t);
1194
+ }
1195
+
1196
+ // Clear the cache
1197
+ lenCurves = null;
1198
+ lenCurve = -1F;
1199
+ }
1200
+
1201
+ public RShape[] split(float t) {
1202
+ RShape[] result = new RShape[2];
1203
+ result[0] = new RShape();
1204
+ result[1] = new RShape();
1205
+
1206
+ if (t == 0.0F) {
1207
+ result[0] = new RShape();
1208
+ result[0].setStyle(this);
1209
+
1210
+ result[1] = new RShape(this);
1211
+ result[1].setStyle(this);
1212
+
1213
+ return result;
1214
+ }
1215
+
1216
+ if (t == 1.0F) {
1217
+ result[0] = new RShape(this);
1218
+ result[0].setStyle(this);
1219
+
1220
+ result[1] = new RShape();
1221
+ result[1].setStyle(this);
1222
+
1223
+ return result;
1224
+ }
1225
+
1226
+ float[] indAndAdv = indAndAdvAt(t);
1227
+ int indOfElement = (int) (indAndAdv[0]);
1228
+ float advOfElement = indAndAdv[1];
1229
+
1230
+ if (indOfElement < countPaths()) {
1231
+ RPath[] splittedShapes = paths[indOfElement].split(advOfElement);
1232
+
1233
+ result[0] = new RShape();
1234
+ for (int i = 0; i < indOfElement; i++) {
1235
+ result[0].addPath(new RPath(paths[i]));
1236
+ }
1237
+ result[0].addPath(new RPath(splittedShapes[0]));
1238
+ result[0].setStyle(this);
1239
+
1240
+ result[1] = new RShape();
1241
+ result[1].addPath(new RPath(splittedShapes[1]));
1242
+ for (int i = indOfElement + 1; i < countPaths(); i++) {
1243
+ result[1].addPath(new RPath(paths[i]));
1244
+ }
1245
+
1246
+ for (int i = 0; i < countChildren(); i++) {
1247
+ result[1].appendChild(new RShape(this.children[i]));
1248
+ }
1249
+ result[1].setStyle(this);
1250
+
1251
+ return result;
1252
+ } else {
1253
+ indOfElement -= countPaths();
1254
+
1255
+ // Add the elements before the cut point
1256
+ for (int i = 0; i < indOfElement; i++) {
1257
+ result[0].addChild(new RShape(children[i]));
1258
+ }
1259
+
1260
+ // Add the cut point element cutted
1261
+ RShape[] splittedChild = children[indOfElement].split(advOfElement);
1262
+ result[0].addChild(new RShape(splittedChild[0]));
1263
+ result[1].addChild(new RShape(splittedChild[1]));
1264
+
1265
+ // Add the elements after the cut point
1266
+ for (int i = indOfElement + 1; i < countChildren(); i++) {
1267
+ result[1].addChild(new RShape(children[i]));
1268
+ }
1269
+
1270
+ result[0].setStyle(this);
1271
+ result[1].setStyle(this);
1272
+
1273
+ return result;
1274
+ }
1275
+ }
1276
+
1277
+ /**
1278
+ * Use this method to get the points of intersection between this shape and
1279
+ * another shape passed in as a parameter.
1280
+ *
1281
+ * @param other the path with which to check for intersections
1282
+ * @return
1283
+ */
1284
+ public RPoint[] getIntersections(RShape other) {
1285
+ // TODO: when we will be able to intersect between all
1286
+ // geometric elements the polygonization will not be necessary
1287
+ RShape shp = new RShape(this);
1288
+ shp.polygonize();
1289
+
1290
+ RShape otherPol = new RShape(other);
1291
+ otherPol.polygonize();
1292
+ return shp.polygonIntersectionPoints(otherPol);
1293
+ }
1294
+
1295
+ RPoint[] getIntersections(RCommand other) {
1296
+ // TODO: when we will be able to intersect between all
1297
+ // geometric elements the polygonization will not be necessary
1298
+ RShape shp = new RShape(this);
1299
+ shp.polygonize();
1300
+
1301
+ return shp.polygonIntersectionPoints(other);
1302
+ }
1303
+
1304
+ RPoint[] polygonIntersectionPoints(RCommand other) {
1305
+ int numPaths = countPaths();
1306
+
1307
+ RPoint[] result = null;
1308
+ RPoint[] newresult = null;
1309
+ for (int i = 0; i < numPaths; i++) {
1310
+ RPoint[] newPoints = paths[i].intersectionPoints(other);
1311
+ if (newPoints != null) {
1312
+ if (result == null) {
1313
+ result = new RPoint[newPoints.length];
1314
+ System.arraycopy(newPoints, 0, result, 0, newPoints.length);
1315
+ } else {
1316
+ newresult = new RPoint[result.length + newPoints.length];
1317
+ System.arraycopy(result, 0, newresult, 0, result.length);
1318
+ System.arraycopy(newPoints, 0, newresult, result.length, newPoints.length);
1319
+ result = newresult;
1320
+ }
1321
+ }
1322
+ }
1323
+
1324
+ for (int i = 0; i < countChildren(); i++) {
1325
+ RPoint[] newPoints = children[i].polygonIntersectionPoints(other);
1326
+ if (newPoints != null) {
1327
+ if (result == null) {
1328
+ result = new RPoint[newPoints.length];
1329
+ System.arraycopy(newPoints, 0, result, 0, newPoints.length);
1330
+ } else {
1331
+ newresult = new RPoint[result.length + newPoints.length];
1332
+ System.arraycopy(result, 0, newresult, 0, result.length);
1333
+ System.arraycopy(newPoints, 0, newresult, result.length, newPoints.length);
1334
+ result = newresult;
1335
+ }
1336
+ }
1337
+ }
1338
+
1339
+ return result;
1340
+ }
1341
+
1342
+ RPoint[] polygonIntersectionPoints(RPath other) {
1343
+ int numChildren = countChildren();
1344
+ int numPaths = countPaths();
1345
+
1346
+ RPoint[] result = null;
1347
+ RPoint[] newresult = null;
1348
+
1349
+ for (int i = 0; i < numPaths; i++) {
1350
+ RPoint[] newPoints = paths[i].intersectionPoints(other);
1351
+ if (newPoints != null) {
1352
+ if (result == null) {
1353
+ result = new RPoint[newPoints.length];
1354
+ System.arraycopy(newPoints, 0, result, 0, newPoints.length);
1355
+ } else {
1356
+ newresult = new RPoint[result.length + newPoints.length];
1357
+ System.arraycopy(result, 0, newresult, 0, result.length);
1358
+ System.arraycopy(newPoints, 0, newresult, result.length, newPoints.length);
1359
+ result = newresult;
1360
+ }
1361
+ }
1362
+ }
1363
+
1364
+ for (int i = 0; i < numChildren; i++) {
1365
+ RPoint[] newPoints = children[i].polygonIntersectionPoints(other);
1366
+ if (newPoints != null) {
1367
+ if (result == null) {
1368
+ result = new RPoint[newPoints.length];
1369
+ System.arraycopy(newPoints, 0, result, 0, newPoints.length);
1370
+ } else {
1371
+ newresult = new RPoint[result.length + newPoints.length];
1372
+ System.arraycopy(result, 0, newresult, 0, result.length);
1373
+ System.arraycopy(newPoints, 0, newresult, result.length, newPoints.length);
1374
+ result = newresult;
1375
+ }
1376
+ }
1377
+ }
1378
+
1379
+ return result;
1380
+ }
1381
+
1382
+ RPoint[] polygonIntersectionPoints(RShape other) {
1383
+ int numChildren = countChildren();
1384
+ int numPaths = countPaths();
1385
+
1386
+ RPoint[] result = null;
1387
+ RPoint[] newresult = null;
1388
+
1389
+ for (int i = 0; i < numPaths; i++) {
1390
+ RPoint[] newPoints = other.polygonIntersectionPoints(paths[i]);
1391
+ if (newPoints != null) {
1392
+ if (result == null) {
1393
+ result = new RPoint[newPoints.length];
1394
+ System.arraycopy(newPoints, 0, result, 0, newPoints.length);
1395
+ } else {
1396
+ newresult = new RPoint[result.length + newPoints.length];
1397
+ System.arraycopy(result, 0, newresult, 0, result.length);
1398
+ System.arraycopy(newPoints, 0, newresult, result.length, newPoints.length);
1399
+ result = newresult;
1400
+ }
1401
+ }
1402
+ }
1403
+
1404
+ for (int i = 0; i < numChildren; i++) {
1405
+ RPoint[] newPoints = other.polygonIntersectionPoints(children[i]);
1406
+ if (newPoints != null) {
1407
+ if (result == null) {
1408
+ result = new RPoint[newPoints.length];
1409
+ System.arraycopy(newPoints, 0, result, 0, newPoints.length);
1410
+ } else {
1411
+ newresult = new RPoint[result.length + newPoints.length];
1412
+ System.arraycopy(result, 0, newresult, 0, result.length);
1413
+ System.arraycopy(newPoints, 0, newresult, result.length, newPoints.length);
1414
+ result = newresult;
1415
+ }
1416
+ }
1417
+ }
1418
+
1419
+ return result;
1420
+ }
1421
+
1422
+ /**
1423
+ * Use this method to get the closest or intersection points of the shape
1424
+ * with another shape passed as argument.
1425
+ *
1426
+ * @param other the path with which to check for intersections
1427
+ * @return */
1428
+ public RClosest getClosest(RShape other) {
1429
+ // TODO: when we will be able to intersect between all
1430
+ // geometric elements the polygonization will not be necessary
1431
+ RShape shp = new RShape(this);
1432
+ shp.polygonize();
1433
+
1434
+ RShape otherPol = new RShape(other);
1435
+ otherPol.polygonize();
1436
+ return shp.polygonClosestPoints(otherPol);
1437
+ }
1438
+
1439
+ RClosest getClosest(RCommand other) {
1440
+ // TODO: when we will be able to intersect between all
1441
+ // geometric elements the polygonization will not be necessary
1442
+ RShape shp = new RShape(this);
1443
+ shp.polygonize();
1444
+
1445
+ return shp.polygonClosestPoints(other);
1446
+ }
1447
+
1448
+ RClosest polygonClosestPoints(RCommand other) {
1449
+ int numPaths = countPaths();
1450
+
1451
+ RClosest result = new RClosest();
1452
+
1453
+ for (int i = 0; i < numPaths; i++) {
1454
+ RClosest currResult = paths[i].closestPoints(other);
1455
+ result.update(currResult);
1456
+ }
1457
+
1458
+ for (int i = 0; i < countChildren(); i++) {
1459
+ RClosest currResult = children[i].polygonClosestPoints(other);
1460
+ result.update(currResult);
1461
+ }
1462
+
1463
+ return result;
1464
+ }
1465
+
1466
+ RClosest polygonClosestPoints(RPath other) {
1467
+ int numChildren = countChildren();
1468
+ int numPaths = countPaths();
1469
+
1470
+ RClosest result = new RClosest();
1471
+
1472
+ for (int i = 0; i < numPaths; i++) {
1473
+ RClosest currClosest = paths[i].closestPoints(other);
1474
+ result.update(currClosest);
1475
+ }
1476
+
1477
+ for (int i = 0; i < numChildren; i++) {
1478
+ RClosest currClosest = children[i].polygonClosestPoints(other);
1479
+ result.update(currClosest);
1480
+ }
1481
+
1482
+ return result;
1483
+ }
1484
+
1485
+ RClosest polygonClosestPoints(RShape other) {
1486
+ int numChildren = countChildren();
1487
+ int numPaths = countPaths();
1488
+
1489
+ RClosest result = new RClosest();
1490
+
1491
+ for (int i = 0; i < numPaths; i++) {
1492
+ RClosest currClosest = other.polygonClosestPoints(paths[i]);
1493
+ result.update(currClosest);
1494
+ }
1495
+
1496
+ for (int i = 0; i < numChildren; i++) {
1497
+ RClosest currClosest = other.polygonClosestPoints(children[i]);
1498
+ result.update(currClosest);
1499
+ }
1500
+
1501
+ return result;
1502
+ }
1503
+
1504
+ /**
1505
+ * Use this method to adapt a group of of figures to a shape.
1506
+ *
1507
+ * @param wght
1508
+ * @param lngthOffset
1509
+ * @eexample RGroup_adapt
1510
+ * @param shp the path to which to adapt
1511
+ */
1512
+ public void adapt(RShape shp, float wght, float lngthOffset) throws RuntimeException {
1513
+ RRectangle c = this.getBounds();
1514
+ float xmin = c.getMinX();
1515
+ float xmax = c.getMaxX();
1516
+
1517
+ int numChildren = countChildren();
1518
+
1519
+ switch (RG.adaptorType) {
1520
+ case RG.BYPOINT:
1521
+ RPoint[] ps = this.getHandles();
1522
+ if (ps != null) {
1523
+ for (RPoint p1 : ps) {
1524
+ float px = p1.x;
1525
+ float py = p1.y;
1526
+ float t = ((px - xmin) / (xmax - xmin) + lngthOffset) % 1.001F;
1527
+ float amp = (py);
1528
+ RPoint tg = shp.getTangent(t);
1529
+ RPoint p = shp.getPoint(t);
1530
+ float angle = (float) Math.atan2(tg.y, tg.x) - (float) Math.PI / 2F;
1531
+ p1.x = p.x + wght * amp * (float) Math.cos(angle);
1532
+ p1.y = p.y + wght * amp * (float) Math.sin(angle);
1533
+ }
1534
+ }
1535
+ break;
1536
+ case RG.BYELEMENTINDEX:
1537
+ for (int i = 0; i < numChildren; i++) {
1538
+ RShape elem = this.children[i];
1539
+ RRectangle elemc = elem.getBounds();
1540
+
1541
+ float px = (elemc.bottomRight.x + elemc.topLeft.x) / 2F;
1542
+ float py = (elemc.bottomRight.y - elemc.topLeft.y) / 2F;
1543
+ float t = ((float) i / (float) numChildren + lngthOffset) % 1F;
1544
+
1545
+ RPoint tg = shp.getTangent(t);
1546
+ RPoint p = shp.getPoint(t);
1547
+ float angle = (float) Math.atan2(tg.y, tg.x);
1548
+
1549
+ RPoint pletter = new RPoint(px, py);
1550
+ p.sub(pletter);
1551
+
1552
+ RMatrix mtx = new RMatrix();
1553
+ mtx.translate(p);
1554
+ mtx.rotate(angle, pletter);
1555
+ mtx.scale(wght, pletter);
1556
+
1557
+ elem.transform(mtx);
1558
+ }
1559
+ break;
1560
+
1561
+ case RG.BYELEMENTPOSITION:
1562
+ for (int i = 0; i < numChildren; i++) {
1563
+ RShape elem = this.children[i];
1564
+ RRectangle elemc = elem.getBounds();
1565
+
1566
+ float px = (elemc.bottomRight.x + elemc.topLeft.x) / 2F;
1567
+ float py = (elemc.bottomRight.y - elemc.topLeft.y) / 2F;
1568
+ float t = ((px - xmin) / (xmax - xmin) + lngthOffset) % 1F;
1569
+
1570
+ RPoint tg = shp.getTangent(t);
1571
+ RPoint p = shp.getPoint(t);
1572
+ float angle = (float) Math.atan2(tg.y, tg.x);
1573
+
1574
+ RPoint pletter = new RPoint(px, py);
1575
+ p.sub(pletter);
1576
+
1577
+ RMatrix mtx = new RMatrix();
1578
+ mtx.translate(p);
1579
+ mtx.rotate(angle, pletter);
1580
+ mtx.scale(wght, pletter);
1581
+
1582
+ elem.transform(mtx);
1583
+ }
1584
+ break;
1585
+
1586
+ default:
1587
+ throw new RuntimeException("Unknown adaptor type : " + RG.adaptorType + ". The method RG.setAdaptor() only accepts RG.BYPOINT or RG.BYELEMENT as parameter values.");
1588
+ }
1589
+ }
1590
+
1591
+ public void adapt(RShape shp) throws RuntimeException {
1592
+ adapt(shp, RG.adaptorScale, RG.adaptorLengthOffset);
1593
+ }
1594
+
1595
+ /**
1596
+ * Use this method to get the type of element this is.
1597
+ *
1598
+ * @eexample RShape_getType
1599
+ * @return int, will allways return RGeomElem.SHAPE
1600
+ */
1601
+ @Override
1602
+ public int getType() {
1603
+ return type;
1604
+ }
1605
+
1606
+ @Override
1607
+ public void print() {
1608
+ System.out.println("paths [count " + this.countPaths() + "]: ");
1609
+ for (int i = 0; i < countPaths(); i++) {
1610
+ System.out.println("--- path " + i + " ---");
1611
+ paths[i].print();
1612
+ System.out.println("---------------");
1613
+ }
1614
+ System.out.println("children [count " + this.countChildren() + "]: ");
1615
+ for (int i = 0; i < countChildren(); i++) {
1616
+ System.out.println("--- child " + i + " ---");
1617
+ children[i].print();
1618
+ System.out.println("---------------");
1619
+ }
1620
+
1621
+ }
1622
+
1623
+ /**
1624
+ *
1625
+ * @param g
1626
+ */
1627
+ @Override
1628
+ public void draw(PGraphics g) {
1629
+ if (!RG.ignoreStyles) {
1630
+ saveContext(g);
1631
+ setContext(g);
1632
+ }
1633
+
1634
+ this.drawPaths(g);
1635
+
1636
+ for (int i = 0; i < countChildren(); i++) {
1637
+ this.children[i].draw(g);
1638
+ }
1639
+
1640
+ if (!RG.ignoreStyles) {
1641
+ restoreContext(g);
1642
+ }
1643
+ }
1644
+
1645
+ @Override
1646
+ public void draw(PApplet g) {
1647
+ if (!RG.ignoreStyles) {
1648
+ saveContext(g);
1649
+ setContext(g);
1650
+ }
1651
+
1652
+ this.drawPaths(g);
1653
+
1654
+ for (int i = 0; i < countChildren(); i++) {
1655
+ this.children[i].draw(g);
1656
+ }
1657
+
1658
+ if (!RG.ignoreStyles) {
1659
+ restoreContext(g);
1660
+ }
1661
+ }
1662
+
1663
+ /**
1664
+ * Use this method to draw the shape.
1665
+ *
1666
+ * @eexample drawShape
1667
+ * @param g PGraphics, the graphics object on which to draw the shape
1668
+ */
1669
+ private void drawPaths(PGraphics g) {
1670
+ /*
1671
+ try{
1672
+ Class declaringClass = g.getClass().getMethod("breakShape", new Class[0]).getDeclaringClass();
1673
+ if(declaringClass == Class.forName("processing.core.PGraphics")){
1674
+
1675
+ // The backend does not implement breakShape
1676
+ // HACK: Drawing twice, so that it also works on backends that support breakShape
1677
+ // such as when recording to a PDF from a OPENGL backend
1678
+ //drawUsingBreakShape(g);
1679
+ drawUsingInternalTesselator(g);
1680
+
1681
+ }else{
1682
+
1683
+ // The backend does implement breakShape
1684
+ drawUsingBreakShape(g);
1685
+ }
1686
+ }catch(NoSuchMethodException e){
1687
+
1688
+ // The backend does implement breakShape
1689
+ drawUsingInternalTesselator(g);
1690
+
1691
+ }catch(ClassNotFoundException e){
1692
+
1693
+ // The backend does implement breakShape
1694
+ drawUsingInternalTesselator(g);
1695
+
1696
+ }
1697
+ */
1698
+ drawUsingBreakShape(g);
1699
+ }
1700
+
1701
+ private void drawPaths(PApplet g) {
1702
+ /*
1703
+ try{
1704
+ Class declaringClass = g.g.getClass().getMethod("breakShape", new Class[0]).getDeclaringClass();
1705
+ if(declaringClass == Class.forName("processing.core.PGraphics")){
1706
+
1707
+ // The backend does not implement breakShape
1708
+ // HACK: Drawing twice, so that it also works on backends that support breakShape
1709
+ // such as when recording to a PDF from a OPENGL backend
1710
+ //drawUsingBreakShape(g);
1711
+ drawUsingInternalTesselator(g);
1712
+
1713
+ }else{
1714
+
1715
+ // The backend does implement breakShape
1716
+ drawUsingBreakShape(g);
1717
+
1718
+ }
1719
+ }catch(NoSuchMethodException e){
1720
+
1721
+ // The backend does implement breakShape
1722
+ drawUsingInternalTesselator(g);
1723
+
1724
+ }catch(ClassNotFoundException e){
1725
+
1726
+ // The backend does implement breakShape
1727
+ drawUsingInternalTesselator(g);
1728
+
1729
+ }
1730
+ */
1731
+ drawUsingBreakShape(g);
1732
+ }
1733
+
1734
+ // ----------------------
1735
+ // --- Private Methods ---
1736
+ // ----------------------
1737
+ @Override
1738
+ protected void calculateCurveLengths() {
1739
+ lenCurves = new float[countPaths() + countChildren()];
1740
+ lenCurve = 0F;
1741
+ for (int i = 0; i < countPaths(); i++) {
1742
+ lenCurves[i] = paths[i].getCurveLength();
1743
+ lenCurve += lenCurves[i];
1744
+ }
1745
+
1746
+ for (int i = 0; i < countChildren(); i++) {
1747
+ lenCurves[i + countPaths()] = children[i].getCurveLength();
1748
+ lenCurve += lenCurves[i + countPaths()];
1749
+ }
1750
+ }
1751
+
1752
+ private float[] indAndAdvAt(float t) {
1753
+ int indOfElement = 0;
1754
+ float[] lengthsCurves = getCurveLengths();
1755
+ float lengthCurve = getCurveLength();
1756
+
1757
+ /* Calculate the amount of advancement t mapped to each command */
1758
+ /* We use a simple algorithm where we give to each command the same amount of advancement */
1759
+ /* A more useful way would be to give to each command an advancement proportional to the length of the command */
1760
+ float accumulatedAdvancement = lengthsCurves[indOfElement] / lengthCurve;
1761
+ float prevAccumulatedAdvancement = 0F;
1762
+
1763
+ /* Find in what command the advancement point is */
1764
+ while (t > accumulatedAdvancement) {
1765
+ indOfElement++;
1766
+ prevAccumulatedAdvancement = accumulatedAdvancement;
1767
+ accumulatedAdvancement += (lengthsCurves[indOfElement] / lengthCurve);
1768
+ }
1769
+
1770
+ float advOfElement = (t - prevAccumulatedAdvancement) / (lengthsCurves[indOfElement] / lengthCurve);
1771
+
1772
+ float[] indAndAdv = new float[2];
1773
+
1774
+ indAndAdv[0] = indOfElement;
1775
+ indAndAdv[1] = PApplet.constrain(advOfElement, 0.0f, 1.0f);
1776
+
1777
+ return indAndAdv;
1778
+ }
1779
+
1780
+ private void appendChild(RShape nextshape) {
1781
+ RShape[] newshapes;
1782
+ if (children == null) {
1783
+ newshapes = new RShape[1];
1784
+ newshapes[0] = nextshape;
1785
+ currentChild = 0;
1786
+ } else {
1787
+ newshapes = new RShape[this.children.length + 1];
1788
+ System.arraycopy(this.children, 0, newshapes, 0, this.children.length);
1789
+ newshapes[this.children.length] = nextshape;
1790
+ currentChild++;
1791
+ }
1792
+ this.children = newshapes;
1793
+ }
1794
+
1795
+ private void append(RPath nextpath) {
1796
+ RPath[] newpaths;
1797
+ if (paths == null) {
1798
+ newpaths = new RPath[1];
1799
+ newpaths[0] = nextpath;
1800
+ currentPath = 0;
1801
+ } else {
1802
+ newpaths = new RPath[this.paths.length + 1];
1803
+ System.arraycopy(this.paths, 0, newpaths, 0, this.paths.length);
1804
+ newpaths[this.paths.length] = nextpath;
1805
+ currentPath++;
1806
+ }
1807
+ this.paths = newpaths;
1808
+ }
1809
+
1810
+ private void drawUsingInternalTesselator(PGraphics g) {
1811
+ int numPaths = countPaths();
1812
+
1813
+ if (numPaths != 0) {
1814
+ if (isIn(g)) {
1815
+
1816
+ // Save the information about the current context
1817
+ boolean strokeBefore = g.stroke;
1818
+ int strokeColorBefore = g.strokeColor;
1819
+ float strokeWeightBefore = g.strokeWeight;
1820
+ boolean fillBefore = g.fill;
1821
+ int fillColorBefore = g.fillColor;
1822
+
1823
+ // By default always drawy with an ADAPTATIVE segmentator
1824
+ int lastSegmentator = RCommand.segmentType;
1825
+ RCommand.setSegmentator(RCommand.ADAPTATIVE);
1826
+
1827
+ // Check whether to draw the fill or not
1828
+ if (g.fill) {
1829
+ // Since we are drawing the different tristrips we must turn off the stroke or make it the same color as the fill
1830
+ // NOTE: there's currently no way of drawing the outline of a mesh, since no information is kept about what vertices are at the edge
1831
+
1832
+ // This is here because when rendering meshes we get unwanted lines between the triangles
1833
+ g.noStroke();
1834
+ try {
1835
+ g.noSmooth();
1836
+ } catch (Exception e) {
1837
+ }
1838
+
1839
+ RMesh tempMesh = this.toMesh();
1840
+ tempMesh.draw(g);
1841
+
1842
+ // Restore the old context
1843
+ g.stroke(strokeColorBefore);
1844
+ if (!strokeBefore) {
1845
+ g.noStroke();
1846
+ }
1847
+
1848
+ }
1849
+
1850
+ // Check whether to draw the stroke
1851
+ g.noFill();
1852
+ if (!strokeBefore) {
1853
+ // If there is no stroke to draw
1854
+ // we will still draw one the color of the fill in order to have antialiasing
1855
+ g.stroke(g.fillColor);
1856
+ g.strokeWeight(1F);
1857
+ }
1858
+
1859
+ for (int i = 0; i < numPaths; i++) {
1860
+ paths[i].draw(g);
1861
+ }
1862
+
1863
+ // Restore the fill state and stroke state and color
1864
+ if (fillBefore) {
1865
+ g.fill(fillColorBefore);
1866
+ } else {
1867
+ g.noFill();
1868
+ }
1869
+ g.strokeWeight(strokeWeightBefore);
1870
+ g.stroke(strokeColorBefore);
1871
+ if (!strokeBefore) {
1872
+ g.noStroke();
1873
+ }
1874
+
1875
+ // Restore the user set segmentator
1876
+ RCommand.setSegmentator(lastSegmentator);
1877
+ }
1878
+ }
1879
+ }
1880
+
1881
+ private void drawUsingInternalTesselator(PApplet p) {
1882
+ int numPaths = countPaths();
1883
+
1884
+ if (numPaths != 0) {
1885
+ if (isIn(p)) {
1886
+ // Save the information about the current context
1887
+ boolean strokeBefore = p.g.stroke;
1888
+ int strokeColorBefore = p.g.strokeColor;
1889
+ float strokeWeightBefore = p.g.strokeWeight;
1890
+ boolean fillBefore = p.g.fill;
1891
+ int fillColorBefore = p.g.fillColor;
1892
+
1893
+ // By default always drawy with an ADAPTATIVE segmentator
1894
+ int lastSegmentator = RCommand.segmentType;
1895
+ RCommand.setSegmentator(RCommand.ADAPTATIVE);
1896
+
1897
+ // Check whether to draw the fill or not
1898
+ if (p.g.fill) {
1899
+ // Since we are drawing the different tristrips we must turn off the stroke
1900
+ // or make it the same color as the fill
1901
+ // NOTE: there's currently no way of drawing the outline of a mesh,
1902
+ // since no information is kept about what vertices are at the edge
1903
+
1904
+ // This is here because when rendering meshes we get unwanted lines between the triangles
1905
+ p.noStroke();
1906
+ try {
1907
+ p.noSmooth();
1908
+ } catch (Exception e) {
1909
+ }
1910
+
1911
+ RMesh tempMesh = this.toMesh();
1912
+ if (tempMesh != null) {
1913
+ tempMesh.draw(p);
1914
+ }
1915
+
1916
+ // Restore the old context
1917
+ p.stroke(strokeColorBefore);
1918
+ p.strokeWeight(strokeWeightBefore);
1919
+ if (!strokeBefore) {
1920
+ p.noStroke();
1921
+ }
1922
+
1923
+ }
1924
+
1925
+ // Check whether to draw the stroke
1926
+ p.noFill();
1927
+ if ((fillBefore) || strokeBefore) {
1928
+ if (!strokeBefore) {
1929
+ // If there is no stroke to draw
1930
+ // we will still draw one the color
1931
+ // of the fill in order to have antialiasing
1932
+ p.stroke(fillColorBefore);
1933
+ p.strokeWeight(1F);
1934
+ }
1935
+
1936
+ for (int i = 0; i < numPaths; i++) {
1937
+ paths[i].draw(p);
1938
+ }
1939
+
1940
+ // Restore the old context
1941
+ if (fillBefore) {
1942
+ p.fill(fillColorBefore);
1943
+ }
1944
+ p.strokeWeight(strokeWeightBefore);
1945
+ p.stroke(strokeColorBefore);
1946
+ if (!strokeBefore) {
1947
+ p.noStroke();
1948
+ }
1949
+ }
1950
+
1951
+ // Restore the user set segmentator
1952
+ RCommand.setSegmentator(lastSegmentator);
1953
+ }
1954
+ }
1955
+ }
1956
+
1957
+ private void drawUsingBreakShape(PGraphics g) {
1958
+ int numPaths = countPaths();
1959
+ if (numPaths != 0) {
1960
+ if (isIn(g)) {
1961
+ boolean closed = false;
1962
+ boolean useContours = (numPaths > 1);
1963
+ g.beginShape();
1964
+ for (int i = 0; i < numPaths; i++) {
1965
+ if (useContours && i > 0) {
1966
+ g.beginContour();
1967
+ }
1968
+
1969
+ RPath path = paths[i];
1970
+ closed |= path.closed;
1971
+
1972
+ for (int j = 0; j < path.countCommands(); j++) {
1973
+ RPoint[] pnts = path.commands[j].getHandles();
1974
+ if (j == 0) {
1975
+ g.vertex(pnts[0].x, pnts[0].y);
1976
+ }
1977
+ switch (path.commands[j].getCommandType()) {
1978
+ case RCommand.LINETO:
1979
+ g.vertex(pnts[1].x, pnts[1].y);
1980
+ break;
1981
+ case RCommand.QUADBEZIERTO:
1982
+ g.bezierVertex(pnts[1].x, pnts[1].y, pnts[2].x, pnts[2].y, pnts[2].x, pnts[2].y);
1983
+ break;
1984
+ case RCommand.CUBICBEZIERTO:
1985
+ g.bezierVertex(pnts[1].x, pnts[1].y, pnts[2].x, pnts[2].y, pnts[3].x, pnts[3].y);
1986
+ break;
1987
+ }
1988
+ }
1989
+
1990
+ if (useContours && i > 0) {
1991
+ g.endContour();
1992
+ }
1993
+
1994
+ }
1995
+ g.endShape(closed ? PConstants.CLOSE : PConstants.OPEN);
1996
+
1997
+ }
1998
+ }
1999
+ }
2000
+
2001
+ private void drawUsingBreakShape(PApplet g) {
2002
+ int numPaths = countPaths();
2003
+ if (numPaths != 0) {
2004
+ if (isIn(g)) {
2005
+ boolean closed = false;
2006
+ boolean useContours = (numPaths > 1);
2007
+ g.beginShape();
2008
+ for (int i = 0; i < numPaths; i++) {
2009
+ if (useContours && i > 0) {
2010
+ g.beginContour();
2011
+ }
2012
+
2013
+ RPath path = paths[i];
2014
+ closed |= path.closed;
2015
+ float firstx = 0;
2016
+ float firsty = 0;
2017
+ for (int j = 0; j < path.countCommands(); j++) {
2018
+ RPoint[] pnts = path.commands[j].getHandles();
2019
+ if (j == 0) {
2020
+ g.vertex(pnts[0].x, pnts[0].y);
2021
+ }
2022
+ switch (path.commands[j].getCommandType()) {
2023
+ case RCommand.LINETO:
2024
+ g.vertex(pnts[1].x, pnts[1].y);
2025
+ break;
2026
+ case RCommand.QUADBEZIERTO:
2027
+ g.bezierVertex(pnts[1].x, pnts[1].y, pnts[2].x, pnts[2].y, pnts[2].x, pnts[2].y);
2028
+ break;
2029
+ case RCommand.CUBICBEZIERTO:
2030
+ g.bezierVertex(pnts[1].x, pnts[1].y, pnts[2].x, pnts[2].y, pnts[3].x, pnts[3].y);
2031
+ break;
2032
+ }
2033
+ }
2034
+ if (useContours && i > 0) {
2035
+ g.endContour();
2036
+ }
2037
+
2038
+ }
2039
+ g.endShape(closed ? PConstants.CLOSE : PConstants.OPEN);
2040
+
2041
+ }
2042
+ }
2043
+ }
2044
+
2045
+ }