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,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
+ }