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,1095 @@
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
+ * RPath is a reduced interface for creating, holding and drawing contours.
25
+ * Paths are ordered lists of commands (RCommand) which define the outlines of
26
+ * shapes. Paths can be self-intersecting.
27
+ *
28
+ * @eexample RPath
29
+ * @usage Geometry
30
+ * @related RCommand
31
+ * @related RPolygon
32
+ * @extended
33
+ *
34
+ */
35
+ public class RPath extends RGeomElem {
36
+
37
+ /**
38
+ * @invisible
39
+ */
40
+ public int type = RGeomElem.SUBSHAPE;
41
+
42
+ /**
43
+ * Array of RCommand objects holding the commands of the path.
44
+ *
45
+ * @eexample commands
46
+ * @related RCommand
47
+ * @related countCommands ( )
48
+ */
49
+ public RCommand[] commands;
50
+
51
+ /**
52
+ * Last point from where to add the next command. Initialized to (0, 0).
53
+ *
54
+ * @eexample lastPoint
55
+ * @related RPoint
56
+ * @invisible
57
+ */
58
+ public RPoint lastPoint;
59
+
60
+ boolean closed = false;
61
+
62
+ /**
63
+ * Create a new empty path.
64
+ *
65
+ * @eexample RPath
66
+ */
67
+ public RPath() {
68
+ this.lastPoint = new RPoint();
69
+ }
70
+
71
+ /**
72
+ * Create a new path, given an array of points.
73
+ *
74
+ * @eexample RPath
75
+ * @param points the points of the new path
76
+ */
77
+ public RPath(RPoint[] points) {
78
+ if (points == null) {
79
+ return;
80
+ }
81
+ this.lastPoint = points[0];
82
+
83
+ for (int i = 1; i < points.length; i++) {
84
+ this.addLineTo(points[i]);
85
+ }
86
+
87
+ }
88
+
89
+ /**
90
+ * Create a new path, given the coordinates of the first point.
91
+ *
92
+ * @eexample RPath
93
+ * @param x x coordinate of the first point of the new path
94
+ * @param y y coordinate of the first point of the new path
95
+ */
96
+ public RPath(float x, float y) {
97
+ this.lastPoint = new RPoint(x, y);
98
+ }
99
+
100
+ /**
101
+ * Create a new path, given the first point.
102
+ *
103
+ * @eexample RPath
104
+ * @param p first point of the new path
105
+ */
106
+ public RPath(RPoint p) {
107
+ this.lastPoint = p;
108
+ }
109
+
110
+ /**
111
+ * Copy a path.
112
+ *
113
+ * @eexample RPath
114
+ * @param s path to be copied
115
+ */
116
+ public RPath(RPath s) {
117
+ int numCommands = s.countCommands();
118
+ if (numCommands != 0) {
119
+ lastPoint = new RPoint(s.commands[0].startPoint);
120
+ for (int i = 0; i < numCommands; i++) {
121
+ this.append(new RCommand(s.commands[i], lastPoint));
122
+ lastPoint = commands[i].endPoint;
123
+ }
124
+ }
125
+
126
+ closed = s.closed;
127
+ setStyle(s);
128
+ }
129
+
130
+ public RPath(RCommand c) {
131
+ this();
132
+ this.addCommand(c);
133
+ }
134
+
135
+ /**
136
+ * Use this method to count the number of commands in the contour.
137
+ *
138
+ * @eexample countCommands
139
+ * @return int, the number commands in the contour
140
+ */
141
+ public int countCommands() {
142
+ if (this.commands == null) {
143
+ return 0;
144
+ }
145
+
146
+ return this.commands.length;
147
+ }
148
+
149
+ /**
150
+ * Use this to return the start, control and end points of the path. It
151
+ * returns the points in the way of an array of RPoint.
152
+ *
153
+ * @eexample getHandles
154
+ * @return RPoint[], the start, control and end points returned in an array.
155
+ *
156
+ */
157
+ @Override
158
+ public RPoint[] getHandles() {
159
+ int numCommands = countCommands();
160
+
161
+ RPoint[] result = null;
162
+ RPoint[] newresult = null;
163
+ for (int i = 0; i < numCommands; i++) {
164
+ RPoint[] newPoints = commands[i].getHandles();
165
+ if (newPoints != null) {
166
+ if (result == null) {
167
+ result = new RPoint[newPoints.length];
168
+ System.arraycopy(newPoints, 0, result, 0, newPoints.length);
169
+ } else {
170
+ int overlap = 0;
171
+ if (newPoints[0] == result[result.length - 1]) {
172
+ overlap = 1;
173
+ }
174
+ newresult = new RPoint[result.length + newPoints.length - overlap];
175
+ System.arraycopy(result, 0, newresult, 0, result.length);
176
+ System.arraycopy(newPoints, overlap, newresult, result.length, newPoints.length - overlap);
177
+ result = newresult;
178
+ }
179
+ }
180
+ }
181
+ return result;
182
+ }
183
+
184
+ /**
185
+ * Use this to return the points on the curve. It returns the points in the
186
+ * way of an array of RPoint.
187
+ *
188
+ * @eexample getPoints
189
+ * @return RPoint[], the vertices returned in an array.
190
+ *
191
+ */
192
+ @Override
193
+ public RPoint[] getPoints() {
194
+ int numCommands = countCommands();
195
+ if (numCommands == 0) {
196
+ return null;
197
+ }
198
+
199
+ // Add the curve points of each command
200
+ // First set the accumulated offset to the value of the inital offset
201
+ RCommand.segmentAccOffset = RCommand.segmentOffset;
202
+ RPoint[] result = null;
203
+ RPoint[] newresult = null;
204
+ for (int i = 0; i < numCommands; i++) {
205
+ RPoint[] newPoints = commands[i].getPoints(false);
206
+ if (newPoints != null) {
207
+ if (result == null) {
208
+ result = new RPoint[newPoints.length];
209
+ System.arraycopy(newPoints, 0, result, 0, newPoints.length);
210
+ } else {
211
+ // Check for overlapping
212
+ // Overlapping happens when the last point of the last command
213
+ // is the same as the first point of the current command
214
+ RPoint lastp = result[result.length - 1];
215
+ RPoint firstp = newPoints[0];
216
+ int overlap = 0;
217
+ if ((lastp.x == firstp.x) && (lastp.y == firstp.y)) {
218
+ overlap = 1;
219
+ }
220
+ newresult = new RPoint[result.length + newPoints.length - overlap];
221
+ System.arraycopy(result, 0, newresult, 0, result.length);
222
+ System.arraycopy(newPoints, overlap, newresult, result.length, newPoints.length - overlap);
223
+ result = newresult;
224
+ }
225
+ }
226
+ }
227
+
228
+ // Always add last point
229
+ newresult = new RPoint[result.length + 1];
230
+ System.arraycopy(result, 0, newresult, 0, result.length);
231
+ newresult[newresult.length - 1] = new RPoint(commands[numCommands - 1].endPoint);
232
+
233
+ return newresult;
234
+ }
235
+
236
+ /**
237
+ * Use this to return the points of each path of the path. It returns the
238
+ * points in the way of an array of array of RPoint.
239
+ *
240
+ * @eexample RGroup_getPoints
241
+ * @return RPoint[], the points returned in an array.
242
+ *
243
+ */
244
+ @Override
245
+ public RPoint[][] getPointsInPaths() {
246
+ RPoint[][] result = {this.getPoints()};
247
+ return result;
248
+ }
249
+
250
+ /**
251
+ * Use this to return the handles of each path of the path. It returns the
252
+ * handles in the way of an array of array of RPoint.
253
+ *
254
+ * @eexample RGroup_getHandles
255
+ * @return RPoint[], the handles returned in an array.
256
+ *
257
+ */
258
+ @Override
259
+ public RPoint[][] getHandlesInPaths() {
260
+ RPoint[][] result = {this.getHandles()};
261
+ return result;
262
+ }
263
+
264
+ /**
265
+ * Use this to return the tangents of each path of the path. It returns the
266
+ * tangents in the way of an array of array of RPoint.
267
+ *
268
+ * @eexample RGroup_getTangents
269
+ * @return RPoint[], the tangents returned in an array.
270
+ *
271
+ */
272
+ @Override
273
+ public RPoint[][] getTangentsInPaths() {
274
+ RPoint[][] result = {this.getTangents()};
275
+ return result;
276
+ }
277
+
278
+ @Override
279
+ protected void calculateCurveLengths() {
280
+ lenCurves = new float[countCommands()];
281
+ lenCurve = 0F;
282
+ for (int i = 0; i < countCommands(); i++) {
283
+ lenCurves[i] = commands[i].getCurveLength();
284
+ lenCurve += lenCurves[i];
285
+ }
286
+ }
287
+
288
+ /**
289
+ * Use this to return the tangents on the curve. It returns the vectors in
290
+ * the way of an array of RPoint.
291
+ *
292
+ * @eexample getTangents
293
+ * @return RPoint[], the tangent vectors returned in an array.
294
+ *
295
+ */
296
+ @Override
297
+ public RPoint[] getTangents() {
298
+ int numCommands = countCommands();
299
+ if (numCommands == 0) {
300
+ return null;
301
+ }
302
+
303
+ RPoint[] result = null;
304
+ RPoint[] newresult = null;
305
+ for (int i = 0; i < numCommands; i++) {
306
+ RPoint[] newTangents = commands[i].getTangents();
307
+ if (newTangents != null) {
308
+ if (newTangents.length != 1) {
309
+ int overlap = 1;
310
+ if (result == null) {
311
+ result = new RPoint[newTangents.length];
312
+ System.arraycopy(newTangents, 0, result, 0, newTangents.length);
313
+ } else {
314
+ newresult = new RPoint[result.length + newTangents.length - overlap];
315
+ System.arraycopy(result, 0, newresult, 0, result.length);
316
+ System.arraycopy(newTangents, overlap, newresult, result.length, newTangents.length - overlap);
317
+ result = newresult;
318
+ }
319
+ }
320
+ }
321
+ }
322
+ return result;
323
+ }
324
+
325
+ /**
326
+ * Use this to return the intersection points between this path and a
327
+ * command. Returns null if no intersection exists.
328
+ *
329
+ * @param other
330
+ * @return RPoint[], the intersection points returned in an array.
331
+ *
332
+ */
333
+ public RPoint[] intersectionPoints(RCommand other) {
334
+ int numCommands = countCommands();
335
+ if (numCommands == 0) {
336
+ return null;
337
+ }
338
+
339
+ RPoint[] result = null;
340
+ RPoint[] newresult = null;
341
+ for (int i = 0; i < numCommands; i++) {
342
+ RPoint[] newPoints = commands[i].intersectionPoints(other);
343
+ if (newPoints != null) {
344
+ if (result == null) {
345
+ result = new RPoint[newPoints.length];
346
+ System.arraycopy(newPoints, 0, result, 0, newPoints.length);
347
+ } else {
348
+ newresult = new RPoint[result.length + newPoints.length];
349
+ System.arraycopy(result, 0, newresult, 0, result.length);
350
+ System.arraycopy(newPoints, 0, newresult, result.length, newPoints.length);
351
+ result = newresult;
352
+ }
353
+ }
354
+ }
355
+ return result;
356
+ }
357
+
358
+ /**
359
+ * Use this to return the intersection points between two paths. Returns
360
+ * null if no intersection exists.
361
+ *
362
+ * @param other
363
+ * @return RPoint[], the intersection points returned in an array.
364
+ *
365
+ */
366
+ public RPoint[] intersectionPoints(RPath other) {
367
+ int numCommands = countCommands();
368
+ int numOtherCommands = other.countCommands();
369
+
370
+ if (numCommands == 0) {
371
+ return null;
372
+ }
373
+
374
+ RPoint[] result = null;
375
+ RPoint[] newresult = null;
376
+
377
+ for (int j = 0; j < numOtherCommands; j++) {
378
+ for (int i = 0; i < numCommands; i++) {
379
+ RPoint[] newPoints = commands[i].intersectionPoints(other.commands[j]);
380
+ if (newPoints != null) {
381
+ if (result == null) {
382
+ result = new RPoint[newPoints.length];
383
+ System.arraycopy(newPoints, 0, result, 0, newPoints.length);
384
+ } else {
385
+ newresult = new RPoint[result.length + newPoints.length];
386
+ System.arraycopy(result, 0, newresult, 0, result.length);
387
+ System.arraycopy(newPoints, 0, newresult, result.length, newPoints.length);
388
+ result = newresult;
389
+ }
390
+ }
391
+ }
392
+ }
393
+
394
+ return result;
395
+ }
396
+
397
+ /**
398
+ * Use this to find the closest or intersection points between this path and
399
+ * a command.
400
+ *
401
+ * @param other
402
+ * @return RPoint[], the intersection points returned in an array.
403
+ *
404
+ */
405
+ public RClosest closestPoints(RCommand other) {
406
+ int numCommands = countCommands();
407
+ if (numCommands == 0) {
408
+ return null;
409
+ }
410
+
411
+ // TODO: get here the max value of an integer
412
+ float minDist = 100000;
413
+
414
+ RClosest result = new RClosest();
415
+
416
+ for (int i = 0; i < numCommands; i++) {
417
+ RClosest currResult = commands[i].closestPoints(other);
418
+
419
+ result.update(currResult);
420
+ }
421
+
422
+ return result;
423
+ }
424
+
425
+ /**
426
+ * Use this to return the intersection points between two paths. Returns
427
+ * null if no intersection exists.
428
+ *
429
+ * @param other
430
+ * @return RPoint[], the intersection points returned in an array.
431
+ *
432
+ */
433
+ public RClosest closestPoints(RPath other) {
434
+ int numCommands = countCommands();
435
+ int numOtherCommands = other.countCommands();
436
+
437
+ if (numCommands == 0) {
438
+ return null;
439
+ }
440
+
441
+ // TODO: get here the max value of an integer
442
+ float minDist = 100000;
443
+
444
+ RClosest result = new RClosest();
445
+
446
+ for (int j = 0; j < numOtherCommands; j++) {
447
+ for (int i = 0; i < numCommands; i++) {
448
+ RClosest currResult = commands[i].closestPoints(other.commands[j]);
449
+ result.update(currResult);
450
+ }
451
+ }
452
+
453
+ return result;
454
+ }
455
+
456
+ /**
457
+ * Return a specific point on the curve. It returns the RPoint for a given
458
+ * advancement parameter t on the curve.
459
+ *
460
+ * @eexample getPoint
461
+ * @param t the parameter of advancement on the curve. t must have values
462
+ * between 0 and 1.
463
+ * @return RPoint, the vertice returned.
464
+ *
465
+ */
466
+ @Override
467
+ public RPoint getPoint(float t) {
468
+ int numCommands = countCommands();
469
+ if (numCommands == 0) {
470
+ return new RPoint();
471
+ }
472
+
473
+ if (t == 0.0F) {
474
+ return commands[0].getPoint(0F);
475
+ }
476
+ if (t == 1.0F) {
477
+ return commands[numCommands - 1].getPoint(1F);
478
+ }
479
+
480
+ float[] indAndAdv = indAndAdvAt(t);
481
+ int indOfElement = (int) (indAndAdv[0]);
482
+ float advOfElement = indAndAdv[1];
483
+
484
+ return commands[indOfElement].getPoint(advOfElement);
485
+ }
486
+
487
+ /**
488
+ * Use this to return a specific tangent on the curve. It returns the RPoint
489
+ * tangent for a given advancement parameter t on the curve.
490
+ *
491
+ * @eexample getPoint
492
+ * @param t float, the parameter of advancement on the curve. t must have
493
+ * values between 0 and 1.
494
+ * @return RPoint, the vertice returned.
495
+ *
496
+ */
497
+ @Override
498
+ public RPoint getTangent(float t) {
499
+ int numCommands = countCommands();
500
+ if (numCommands == 0) {
501
+ return new RPoint();
502
+ }
503
+
504
+ if (t == 0.0F) {
505
+ return commands[0].getTangent(0F);
506
+ }
507
+ if (t == 1.0F) {
508
+ return commands[numCommands - 1].getTangent(1F);
509
+ }
510
+
511
+ float[] indAndAdv = indAndAdvAt(t);
512
+ int indOfElement = (int) (indAndAdv[0]);
513
+ float advOfElement = indAndAdv[1];
514
+
515
+ /* This takes the medium between two intersecting commands, sometimes this is not wanted
516
+ if(advOfElement==1.0F){
517
+ int indNextCommand = (indOfElement + 1) % numCommands;
518
+ result = commands[indOfElement].getTangent(advOfElement);
519
+ RPoint tngNext = commands[indNextCommand].getTangent(0.0F);
520
+ result.add(tngNext);
521
+ result.scale(0.5F);
522
+ }else if (advOfElement==0.0F){
523
+ int indPrevCommand = (indOfElement - 1 + numCommands) % numCommands;
524
+ result = commands[indOfElement].getTangent(advOfElement);
525
+ RPoint tngPrev = commands[indPrevCommand].getTangent(1.0F);
526
+ result.add(tngPrev);
527
+ result.scale(0.5F);
528
+ }else{
529
+ result = commands[indOfElement].getTangent(advOfElement);
530
+ }
531
+ */
532
+ return commands[indOfElement].getTangent(advOfElement);
533
+ }
534
+
535
+ /**
536
+ * Use this to return a specific tangent on the curve. It returns true if
537
+ * the point passed as a parameter is inside the path. Implementation taken
538
+ * from:
539
+ * http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
540
+ *
541
+ * @param p the point for which to test containement..
542
+ * @return boolean, true if the point is in the path.
543
+ *
544
+ */
545
+ @Override
546
+ public boolean contains(RPoint p) {
547
+ float testx = p.x;
548
+ float testy = p.y;
549
+
550
+ // Test for containment in bounding box
551
+ RRectangle bbox = getBounds();
552
+ float xmin = bbox.getMinX();
553
+ float xmax = bbox.getMaxX();
554
+
555
+ float ymin = bbox.getMinY();
556
+ float ymax = bbox.getMaxY();
557
+
558
+ if ((testx < xmin) || (testx > xmax) || (testy < ymin) || (testy > ymax)) {
559
+ return false;
560
+ }
561
+
562
+ // Test for containment in path
563
+ RPoint[] verts = getPoints();
564
+
565
+ if (verts == null) {
566
+ return false;
567
+ }
568
+
569
+ int nvert = verts.length;
570
+ int i, j = 0;
571
+ boolean c = false;
572
+ for (i = 0, j = nvert - 1; i < nvert; j = i++) {
573
+ if (((verts[i].y > testy) != (verts[j].y > testy))
574
+ && (testx < (verts[j].x - verts[i].x) * (testy - verts[i].y) / (verts[j].y - verts[i].y) + verts[i].x)) {
575
+ c = !c;
576
+ }
577
+ }
578
+ return c;
579
+ }
580
+
581
+ /**
582
+ * Use this to insert a split point into the path.
583
+ *
584
+ * @eexample insertHandle
585
+ * @param t float, the parameter of advancement on the curve. t must have
586
+ * values between 0 and 1.
587
+ *
588
+ */
589
+ public void insertHandle(float t) {
590
+ if ((t == 0F) || (t == 1F)) {
591
+ return;
592
+ }
593
+
594
+ float[] indAndAdv = indAndAdvAt(t);
595
+ int indOfElement = (int) (indAndAdv[0]);
596
+ float advOfElement = indAndAdv[1];
597
+
598
+ // Split the affected command and reconstruct each of the shapes
599
+ RCommand[] splittedCommands = commands[indOfElement].split(advOfElement);
600
+
601
+ if (splittedCommands[0] == null || splittedCommands[1] == null) {
602
+ return;
603
+ }
604
+
605
+ // Extract the splitted command
606
+ extract(indOfElement);
607
+
608
+ // Insert the splittedCommands
609
+ insert(splittedCommands[1], indOfElement);
610
+ insert(splittedCommands[0], indOfElement);
611
+
612
+ // Clear the cache
613
+ lenCurves = null;
614
+ lenCurve = -1F;
615
+ }
616
+
617
+ /**
618
+ * Use this to insert a split point into each command of the path.
619
+ *
620
+ * @eexample insertHandleInPaths
621
+ * @param t float, the parameter of advancement on the curve. t must have
622
+ * values between 0 and 1.
623
+ *
624
+ */
625
+ public void insertHandleInPaths(float t) {
626
+ if ((t == 0F) || (t == 1F)) {
627
+ return;
628
+ }
629
+
630
+ int numCommands = countCommands();
631
+
632
+ for (int i = 0; i < numCommands * 2; i += 2) {
633
+ // Split the affected command and reconstruct each of the shapes
634
+ RCommand[] splittedCommands = commands[i].split(t);
635
+
636
+ if (splittedCommands[0] == null || splittedCommands[1] == null) {
637
+ return;
638
+ }
639
+
640
+ // Extract the splitted command
641
+ extract(i);
642
+
643
+ // Insert the splittedCommands
644
+ insert(splittedCommands[1], i);
645
+ insert(splittedCommands[0], i);
646
+ }
647
+
648
+ // Clear the cache
649
+ lenCurves = null;
650
+ lenCurve = -1F;
651
+ }
652
+
653
+ /**
654
+ * Use this to split a path into two separate new paths.
655
+ *
656
+ * @eexample split
657
+ * @param t float, the parameter of advancement on the curve. t must have
658
+ * values between 0 and 1.
659
+ * @return RPath[], an array of two RPath.
660
+ *
661
+ */
662
+ public RPath[] split(float t) {
663
+ RPath[] result = new RPath[2];
664
+
665
+ int numCommands = countCommands();
666
+ if (numCommands == 0) {
667
+ return null;
668
+ }
669
+
670
+ if (t == 0.0F) {
671
+ result[0] = new RPath();
672
+ result[1] = new RPath(this);
673
+ result[0].setStyle(this);
674
+ result[1].setStyle(this);
675
+
676
+ return result;
677
+ }
678
+
679
+ if (t == 1.0F) {
680
+ result[0] = new RPath(this);
681
+ result[1] = new RPath();
682
+ result[0].setStyle(this);
683
+ result[1].setStyle(this);
684
+
685
+ return result;
686
+ }
687
+
688
+ float[] indAndAdv = indAndAdvAt(t);
689
+ int indOfElement = (int) (indAndAdv[0]);
690
+ float advOfElement = indAndAdv[1];
691
+
692
+ // Split the affected command and reconstruct each of the shapes
693
+ RCommand[] splittedCommands = commands[indOfElement].split(advOfElement);
694
+
695
+ result[0] = new RPath();
696
+ for (int i = 0; i < indOfElement; i++) {
697
+ result[0].addCommand(new RCommand(commands[i]));
698
+ }
699
+ result[0].addCommand(new RCommand(splittedCommands[0]));
700
+ result[0].setStyle(this);
701
+
702
+ result[1] = new RPath();
703
+ for (int i = indOfElement + 1; i < countCommands(); i++) {
704
+ result[1].addCommand(new RCommand(commands[i]));
705
+ }
706
+ result[1].addCommand(new RCommand(splittedCommands[1]));
707
+ result[1].setStyle(this);
708
+
709
+ return result;
710
+ }
711
+
712
+ public void polygonize() {
713
+ RPoint[] points = getPoints();
714
+
715
+ if (points == null) {
716
+ this.commands = null;
717
+ } else {
718
+ RPath result = new RPath(points[0]);
719
+ for (int i = 1; i < points.length; i++) {
720
+ result.addLineTo(points[i]);
721
+ }
722
+ this.commands = result.commands;
723
+ }
724
+ }
725
+
726
+ /**
727
+ * Use this method to draw the path.
728
+ *
729
+ * @eexample drawPath
730
+ * @param g PGraphics, the graphics object on which to draw the path
731
+ */
732
+ @Override
733
+ public void draw(PGraphics g) {
734
+ countCommands();
735
+
736
+ // By default always draw with an adaptative segmentator
737
+ int lastSegmentator = RCommand.segmentType;
738
+ RCommand.setSegmentator(RCommand.ADAPTATIVE);
739
+
740
+ RPoint[] points = getPoints();
741
+
742
+ if (points == null) {
743
+ return;
744
+ }
745
+
746
+ g.beginShape();
747
+ for (RPoint point : points) {
748
+ g.vertex(point.x, point.y);
749
+ }
750
+ g.endShape(closed ? PConstants.CLOSE : PConstants.OPEN);
751
+
752
+ // Restore the user set segmentator
753
+ RCommand.setSegmentator(lastSegmentator);
754
+ }
755
+
756
+ /**
757
+ *
758
+ * @param g
759
+ */
760
+ @Override
761
+ public void draw(PApplet g) {
762
+ countCommands();
763
+
764
+ // By default always draw with an adaptative segmentator
765
+ int lastSegmentator = RCommand.segmentType;
766
+ RCommand.setSegmentator(RCommand.ADAPTATIVE);
767
+
768
+ RPoint[] points = getPoints();
769
+ RCommand.setSegmentator(lastSegmentator);
770
+ if (points == null) {
771
+ return;
772
+ }
773
+ g.beginShape();
774
+ for (RPoint point : points) {
775
+ g.vertex(point.x, point.y);
776
+ }
777
+ g.endShape(closed ? PConstants.CLOSE : PConstants.OPEN);
778
+
779
+ // Restore the user set segmentator
780
+ RCommand.setSegmentator(lastSegmentator);
781
+ }
782
+
783
+ /**
784
+ * Use this method to add new commands to the contour.
785
+ *
786
+ * @param p
787
+ * @eexample addCommand
788
+ * @invisible
789
+ */
790
+ public final void addCommand(RCommand p) {
791
+ this.append(p);
792
+
793
+ lastPoint = commands[commands.length - 1].endPoint;
794
+ }
795
+
796
+ /**
797
+ * Add a new cubic bezier to the path. The first point of the bezier will be
798
+ * the last point added to the path.
799
+ *
800
+ * @eexample addBezierTo
801
+ * @param cp1 first control point
802
+ * @param cp2 second control point
803
+ * @param end end point
804
+ */
805
+ public void addBezierTo(RPoint cp1, RPoint cp2, RPoint end) {
806
+ this.addCommand(RCommand.createBezier4(lastPoint, cp1, cp2, end));
807
+ }
808
+
809
+ /**
810
+ * Add a new cubic bezier to the path. The first point of the bezier will be
811
+ * the last point added to the path.
812
+ *
813
+ * @eexample addBezierTo
814
+ * @param cp1x the x coordinate of the first control point
815
+ * @param cp1y the y coordinate of the first control point
816
+ * @param cp2x the x coordinate of the second control point
817
+ * @param cp2y the y coordinate of the second control point
818
+ * @param endx the x coordinate of the end point
819
+ * @param endy the y coordinate of the end point
820
+ */
821
+ public void addBezierTo(float cp1x, float cp1y, float cp2x, float cp2y, float endx, float endy) {
822
+ RPoint cp1 = new RPoint(cp1x, cp1y);
823
+ RPoint cp2 = new RPoint(cp2x, cp2y);
824
+ RPoint end = new RPoint(endx, endy);
825
+
826
+ addBezierTo(cp1, cp2, end);
827
+ }
828
+
829
+ /**
830
+ * Add a new quadratic bezier to the path. The first point of the bezier
831
+ * will be the last point added to the path.
832
+ *
833
+ * @eexample addQuadTo
834
+ * @param cp1 first control point
835
+ * @param end end point
836
+ */
837
+ public void addQuadTo(RPoint cp1, RPoint end) {
838
+ this.addCommand(RCommand.createBezier3(lastPoint, cp1, end));
839
+ }
840
+
841
+ /**
842
+ * Add a new quadratic bezier to the path. The first point of the bezier
843
+ * will be the last point added to the path.
844
+ *
845
+ * @eexample addQuadTo
846
+ * @param cp1x the x coordinate of the first control point
847
+ * @param cp1y the y coordinate of the first control point
848
+ * @param endx the x coordinate of the end point
849
+ * @param endy the y coordinate of the end point
850
+ */
851
+ public void addQuadTo(float cp1x, float cp1y, float endx, float endy) {
852
+ RPoint cp1 = new RPoint(cp1x, cp1y);
853
+ RPoint end = new RPoint(endx, endy);
854
+
855
+ addQuadTo(cp1, end);
856
+ }
857
+
858
+ /**
859
+ * Add a new line to the path. The first point of the line will be the last
860
+ * point added to the path.
861
+ *
862
+ * @eexample addLineTo
863
+ * @param end end point
864
+ */
865
+ public final void addLineTo(RPoint end) {
866
+ this.addCommand(RCommand.createLine(lastPoint, end));
867
+ }
868
+
869
+ /**
870
+ * Add a new line to the path. The first point of the line will be the last
871
+ * point added to the path.
872
+ *
873
+ * @eexample addLineTo
874
+ * @param endx the x coordinate of the end point
875
+ * @param endy the y coordinate of the end point
876
+ */
877
+ public void addLineTo(float endx, float endy) {
878
+ RPoint end = new RPoint(endx, endy);
879
+ addLineTo(end);
880
+ }
881
+
882
+ public void addClose() {
883
+ if (commands == null) {
884
+ return;
885
+ }
886
+
887
+ if ((commands[commands.length - 1].endPoint.x == commands[0].startPoint.x) && (commands[commands.length - 1].endPoint.y == commands[0].startPoint.y)) {
888
+ commands[commands.length - 1].endPoint = new RPoint(commands[0].startPoint.x, commands[0].startPoint.y);
889
+ lastPoint = commands[commands.length - 1].endPoint;
890
+ } else {
891
+ addLineTo(new RPoint(commands[0].startPoint.x, commands[0].startPoint.y));
892
+ }
893
+
894
+ closed = true;
895
+ }
896
+
897
+ /**
898
+ * @return @invisible
899
+ */
900
+ @Override
901
+ public RPolygon toPolygon() {
902
+ return this.toShape().toPolygon();
903
+ }
904
+
905
+ /**
906
+ * @return @invisible
907
+ */
908
+ @Override
909
+ public RShape toShape() {
910
+ return new RShape(this);
911
+ }
912
+
913
+ /**
914
+ * @return @invisible
915
+ */
916
+ @Override
917
+ public RMesh toMesh() {
918
+ return this.toPolygon().toMesh();
919
+ }
920
+
921
+ /**
922
+ * Use this method to get the type of element this is.
923
+ *
924
+ * @eexample RPolygon_getType
925
+ * @return int, will allways return RGeomElem.POLYGON
926
+ */
927
+ @Override
928
+ public int getType() {
929
+ return type;
930
+ }
931
+
932
+ @Override
933
+ public void print() {
934
+ for (int i = 0; i < countCommands(); i++) {
935
+ String commandType = "";
936
+ switch (commands[i].commandType) {
937
+ case RCommand.LINETO:
938
+ commandType = "LINETO";
939
+ break;
940
+
941
+ case RCommand.CUBICBEZIERTO:
942
+ commandType = "BEZIERTO";
943
+ break;
944
+
945
+ case RCommand.QUADBEZIERTO:
946
+ commandType = "QUADBEZIERTO";
947
+ break;
948
+ }
949
+
950
+ System.out.println("cmd type: " + commandType);
951
+ System.out.print("start point: ");
952
+ commands[i].startPoint.print();
953
+ System.out.print("\n");
954
+ System.out.print("end point: ");
955
+ commands[i].endPoint.print();
956
+ System.out.print("\n");
957
+ if (commands[i].controlPoints != null) {
958
+ System.out.println("control points: ");
959
+ for (RPoint controlPoint : commands[i].controlPoints) {
960
+ controlPoint.print();
961
+ System.out.print(" ");
962
+ System.out.print("\n");
963
+ }
964
+ }
965
+ System.out.print("\n");
966
+ }
967
+ }
968
+
969
+ /**
970
+ * Use this method to transform the shape.
971
+ *
972
+ * @eexample RPath_transform
973
+ * @param m RMatrix, the matrix defining the affine transformation
974
+ * @related draw ( )
975
+ */
976
+ // OPT: not transform the EndPoint since it's equal to the next StartPoint
977
+ /*
978
+ public void transform(RMatrix m){
979
+ RPoint[] ps = getHandles();
980
+ if(ps!=null){
981
+ for(int i=0;i<ps.length;i++){
982
+ ps[i].transform(m);
983
+ }
984
+ }
985
+
986
+ int numCommands = countCommands();
987
+ if(numCommands!=0){
988
+ commands[0].startPoint.transform(m);
989
+ for(int i=0;i<numCommands-1;i++){
990
+ for(int j=0;j<commands[i].countControlPoints();j++){
991
+ commands[i].controlPoints[j].transform(m);
992
+ }
993
+ commands[i].endPoint.transform(m);
994
+ }
995
+ }
996
+
997
+ }
998
+ */
999
+ private float[] indAndAdvAt(float t) {
1000
+ int indOfElement = 0;
1001
+ float[] lengthsCurves = getCurveLengths();
1002
+ float lengthCurve = getCurveLength();
1003
+
1004
+ /* Calculate the amount of advancement t mapped to each command */
1005
+ /* We use a simple algorithm where we give to each command the same amount of advancement */
1006
+ /* A more useful way would be to give to each command an advancement proportional to the length of the command */
1007
+ /* Old method with uniform advancement per command
1008
+ float advPerCommand;
1009
+ advPerCommand = 1F / numPaths;
1010
+ indOfElement = (int)(Math.floor(t / advPerCommand)) % numPaths;
1011
+ advOfElement = (t*numPaths - indOfElement);
1012
+ */
1013
+ float accumulatedAdvancement = lengthsCurves[indOfElement] / lengthCurve;
1014
+ float prevAccumulatedAdvancement = 0F;
1015
+
1016
+ /* Find in what command the advancement point is */
1017
+ while (t > accumulatedAdvancement) {
1018
+ indOfElement++;
1019
+ prevAccumulatedAdvancement = accumulatedAdvancement;
1020
+ accumulatedAdvancement += (lengthsCurves[indOfElement] / lengthCurve);
1021
+ }
1022
+
1023
+ float advOfElement = (t - prevAccumulatedAdvancement) / (lengthsCurves[indOfElement] / lengthCurve);
1024
+
1025
+ float[] indAndAdv = new float[2];
1026
+
1027
+ indAndAdv[0] = indOfElement;
1028
+ indAndAdv[1] = advOfElement;
1029
+
1030
+ return indAndAdv;
1031
+ }
1032
+
1033
+ private void append(RCommand nextcommand) {
1034
+ RCommand[] newcommands;
1035
+ if (commands == null) {
1036
+ newcommands = new RCommand[1];
1037
+ newcommands[0] = nextcommand;
1038
+ } else {
1039
+ newcommands = new RCommand[this.commands.length + 1];
1040
+ System.arraycopy(this.commands, 0, newcommands, 0, this.commands.length);
1041
+ newcommands[this.commands.length] = nextcommand;
1042
+ }
1043
+ this.commands = newcommands;
1044
+ }
1045
+
1046
+ private void insert(RCommand newcommand, int i) throws RuntimeException {
1047
+ if (i < 0) {
1048
+ throw new RuntimeException("Negative values for indexes are not valid.");
1049
+ }
1050
+
1051
+ RCommand[] newcommands;
1052
+ if (commands == null) {
1053
+ newcommands = new RCommand[1];
1054
+ newcommands[0] = newcommand;
1055
+ } else {
1056
+ if (i > commands.length) {
1057
+ throw new RuntimeException("Index out of the bounds. You are trying to insert an element with an index higher than the number of commands in the group.");
1058
+ }
1059
+
1060
+ newcommands = new RCommand[this.commands.length + 1];
1061
+ System.arraycopy(this.commands, 0, newcommands, 0, i);
1062
+ newcommands[i] = newcommand;
1063
+ System.arraycopy(this.commands, i, newcommands, i + 1, this.commands.length - i);
1064
+ }
1065
+ this.commands = newcommands;
1066
+ }
1067
+
1068
+ private void extract(int i) throws RuntimeException {
1069
+ RCommand[] newcommands;
1070
+ if (commands == null) {
1071
+ throw new RuntimeException("The group is empty. No commands to remove.");
1072
+ } else {
1073
+ if (i < 0) {
1074
+ throw new RuntimeException("Negative values for indexes are not valid.");
1075
+ }
1076
+ if (i > commands.length - 1) {
1077
+ throw new RuntimeException("Index out of the bounds of the group. You are trying to erase an element with an index higher than the number of commands in the group.");
1078
+ }
1079
+ if (commands.length == 1) {
1080
+ newcommands = null;
1081
+ } else if (i == 0) {
1082
+ newcommands = new RCommand[this.commands.length - 1];
1083
+ System.arraycopy(this.commands, 1, newcommands, 0, this.commands.length - 1);
1084
+ } else if (i == commands.length - 1) {
1085
+ newcommands = new RCommand[this.commands.length - 1];
1086
+ System.arraycopy(this.commands, 0, newcommands, 0, this.commands.length - 1);
1087
+ } else {
1088
+ newcommands = new RCommand[this.commands.length - 1];
1089
+ System.arraycopy(this.commands, 0, newcommands, 0, i);
1090
+ System.arraycopy(this.commands, i + 1, newcommands, i, this.commands.length - i - 1);
1091
+ }
1092
+ }
1093
+ this.commands = newcommands;
1094
+ }
1095
+ }