geomerative 0.1.0-java

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