geomerative 0.4.3-java → 2.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 (129) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +2 -0
  3. data/.mvn/extensions.xml +1 -1
  4. data/.mvn/wrapper/maven-wrapper.properties +1 -1
  5. data/CHANGELOG.md +19 -1
  6. data/COPYING.md +1 -1
  7. data/README.md +2 -2
  8. data/Rakefile +2 -15
  9. data/docs/_config.yml +8 -0
  10. data/docs/_includes/head.html +7 -6
  11. data/docs/_includes/header.html +6 -6
  12. data/docs/_includes/icon-github.svg +3 -1
  13. data/docs/_includes/icon-twitter.svg +3 -1
  14. data/docs/_includes/navigation.html +24 -0
  15. data/docs/_sass/_base.scss +79 -79
  16. data/docs/_sass/_layout.scss +137 -137
  17. data/docs/_sass/_syntax-highlighting.scss +64 -64
  18. data/docs/index.html +18 -18
  19. data/examples/README.md +1 -1
  20. data/examples/data/bot1.svg +1 -1
  21. data/examples/data/lion.svg +156 -156
  22. data/examples/data/ruby.svg +1 -1
  23. data/examples/jruby_merge.rb +1 -1
  24. data/examples/{f_agent.rb → library/f_agent/f_agent.rb} +0 -0
  25. data/examples/{font_agent.rb → library/font_agent/font_agent.rb} +2 -1
  26. data/examples/text_on_geomerative_path.rb +3 -2
  27. data/examples/typo_deform.rb +2 -2
  28. data/examples/typo_extra_bright.rb +1 -1
  29. data/geomerative.gemspec +3 -6
  30. data/lib/geomerative/version.rb +1 -1
  31. data/lib/geomerative.jar +0 -0
  32. data/lib/geomerative.rb +10 -10
  33. data/mvnw +234 -0
  34. data/mvnw.cmd +145 -0
  35. data/pom.rb +14 -16
  36. data/pom.xml +13 -19
  37. data/src/geomerative/FastRClip.java +2050 -2334
  38. data/src/geomerative/RClip.java +2237 -2539
  39. data/src/geomerative/RClosest.java +33 -31
  40. data/src/geomerative/RCommand.java +1750 -1758
  41. data/src/geomerative/RContour.java +290 -292
  42. data/src/geomerative/RFont.java +277 -246
  43. data/src/geomerative/RG.java +722 -727
  44. data/src/geomerative/RGeomElem.java +967 -962
  45. data/src/geomerative/RGroup.java +508 -467
  46. data/src/geomerative/RMatrix.java +304 -289
  47. data/src/geomerative/RMesh.java +241 -229
  48. data/src/geomerative/RPath.java +924 -926
  49. data/src/geomerative/RPoint.java +391 -391
  50. data/src/geomerative/RPolygon.java +1017 -1013
  51. data/src/geomerative/RRectangle.java +43 -52
  52. data/src/geomerative/RSVG.java +480 -516
  53. data/src/geomerative/RShape.java +1767 -1777
  54. data/src/geomerative/RStrip.java +173 -176
  55. data/src/geomerative/RStyle.java +197 -194
  56. data/src/module-info.java +4 -0
  57. data/src/org/apache/batik/svggen/font/Font.java +141 -142
  58. data/src/org/apache/batik/svggen/font/Glyph.java +102 -71
  59. data/src/org/apache/batik/svggen/font/Point.java +12 -12
  60. data/src/org/apache/batik/svggen/font/RandomAccessFileEmulator.java +14 -12
  61. data/src/org/apache/batik/svggen/font/table/ClassDef.java +12 -12
  62. data/src/org/apache/batik/svggen/font/table/ClassDefFormat1.java +27 -24
  63. data/src/org/apache/batik/svggen/font/table/ClassDefFormat2.java +20 -17
  64. data/src/org/apache/batik/svggen/font/table/CmapFormat.java +43 -43
  65. data/src/org/apache/batik/svggen/font/table/CmapFormat0.java +33 -26
  66. data/src/org/apache/batik/svggen/font/table/CmapFormat2.java +25 -20
  67. data/src/org/apache/batik/svggen/font/table/CmapFormat4.java +106 -96
  68. data/src/org/apache/batik/svggen/font/table/CmapFormat6.java +36 -32
  69. data/src/org/apache/batik/svggen/font/table/CmapIndexEntry.java +69 -49
  70. data/src/org/apache/batik/svggen/font/table/CmapTable.java +50 -50
  71. data/src/org/apache/batik/svggen/font/table/Coverage.java +19 -19
  72. data/src/org/apache/batik/svggen/font/table/CoverageFormat1.java +30 -27
  73. data/src/org/apache/batik/svggen/font/table/CoverageFormat2.java +26 -24
  74. data/src/org/apache/batik/svggen/font/table/CvtTable.java +16 -16
  75. data/src/org/apache/batik/svggen/font/table/Device.java +32 -32
  76. data/src/org/apache/batik/svggen/font/table/DirectoryEntry.java +39 -39
  77. data/src/org/apache/batik/svggen/font/table/Feature.java +26 -23
  78. data/src/org/apache/batik/svggen/font/table/FeatureList.java +37 -35
  79. data/src/org/apache/batik/svggen/font/table/FeatureRecord.java +22 -22
  80. data/src/org/apache/batik/svggen/font/table/FeatureTags.java +4 -3
  81. data/src/org/apache/batik/svggen/font/table/FpgmTable.java +9 -9
  82. data/src/org/apache/batik/svggen/font/table/GlyfCompositeComp.java +134 -132
  83. data/src/org/apache/batik/svggen/font/table/GlyfCompositeDescript.java +123 -122
  84. data/src/org/apache/batik/svggen/font/table/GlyfDescript.java +44 -44
  85. data/src/org/apache/batik/svggen/font/table/GlyfSimpleDescript.java +110 -109
  86. data/src/org/apache/batik/svggen/font/table/GlyfTable.java +46 -46
  87. data/src/org/apache/batik/svggen/font/table/GlyphDescription.java +25 -13
  88. data/src/org/apache/batik/svggen/font/table/GposTable.java +26 -23
  89. data/src/org/apache/batik/svggen/font/table/GsubTable.java +85 -82
  90. data/src/org/apache/batik/svggen/font/table/HeadTable.java +131 -131
  91. data/src/org/apache/batik/svggen/font/table/HheaTable.java +80 -80
  92. data/src/org/apache/batik/svggen/font/table/HmtxTable.java +50 -49
  93. data/src/org/apache/batik/svggen/font/table/KernSubtable.java +29 -27
  94. data/src/org/apache/batik/svggen/font/table/KernSubtableFormat0.java +35 -32
  95. data/src/org/apache/batik/svggen/font/table/KernSubtableFormat2.java +28 -26
  96. data/src/org/apache/batik/svggen/font/table/KernTable.java +36 -31
  97. data/src/org/apache/batik/svggen/font/table/KerningPair.java +27 -23
  98. data/src/org/apache/batik/svggen/font/table/LangSys.java +28 -26
  99. data/src/org/apache/batik/svggen/font/table/LangSysRecord.java +22 -22
  100. data/src/org/apache/batik/svggen/font/table/Ligature.java +24 -24
  101. data/src/org/apache/batik/svggen/font/table/LigatureSet.java +24 -24
  102. data/src/org/apache/batik/svggen/font/table/LigatureSubst.java +9 -9
  103. data/src/org/apache/batik/svggen/font/table/LigatureSubstFormat1.java +30 -30
  104. data/src/org/apache/batik/svggen/font/table/LocaTable.java +37 -37
  105. data/src/org/apache/batik/svggen/font/table/Lookup.java +41 -40
  106. data/src/org/apache/batik/svggen/font/table/LookupList.java +34 -34
  107. data/src/org/apache/batik/svggen/font/table/LookupSubtableFactory.java +7 -5
  108. data/src/org/apache/batik/svggen/font/table/MaxpTable.java +96 -96
  109. data/src/org/apache/batik/svggen/font/table/NameRecord.java +64 -65
  110. data/src/org/apache/batik/svggen/font/table/NameTable.java +33 -33
  111. data/src/org/apache/batik/svggen/font/table/Os2Table.java +196 -196
  112. data/src/org/apache/batik/svggen/font/table/Panose.java +14 -12
  113. data/src/org/apache/batik/svggen/font/table/PostTable.java +338 -338
  114. data/src/org/apache/batik/svggen/font/table/PrepTable.java +9 -9
  115. data/src/org/apache/batik/svggen/font/table/Program.java +15 -15
  116. data/src/org/apache/batik/svggen/font/table/RangeRecord.java +26 -25
  117. data/src/org/apache/batik/svggen/font/table/Script.java +38 -38
  118. data/src/org/apache/batik/svggen/font/table/ScriptList.java +42 -42
  119. data/src/org/apache/batik/svggen/font/table/ScriptRecord.java +22 -22
  120. data/src/org/apache/batik/svggen/font/table/ScriptTags.java +2 -1
  121. data/src/org/apache/batik/svggen/font/table/SingleSubst.java +15 -16
  122. data/src/org/apache/batik/svggen/font/table/SingleSubstFormat1.java +33 -33
  123. data/src/org/apache/batik/svggen/font/table/SingleSubstFormat2.java +32 -32
  124. data/src/org/apache/batik/svggen/font/table/Table.java +171 -170
  125. data/src/org/apache/batik/svggen/font/table/TableDirectory.java +55 -55
  126. data/src/org/apache/batik/svggen/font/table/TableFactory.java +92 -93
  127. metadata +18 -19
  128. data/.travis.yml +0 -10
  129. data/calculate_torsional_angle.rb +0 -17
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Copyright 2004-2008 Ricard Marxer <email@ricardmarxer.com>
3
3
  *
4
- This file is part of Geomerative.
4
+ * This file is part of Geomerative.
5
5
  *
6
6
  * Geomerative is free software: you can redistribute it and/or modify it under
7
7
  * the terms of the GNU General Public License as published by the Free Software
@@ -22,1684 +22,1676 @@ import processing.core.PApplet;
22
22
  import processing.core.PGraphics;
23
23
 
24
24
  /**
25
- * @extended
25
+
26
26
  */
27
27
  public class RCommand extends RGeomElem {
28
28
 
29
- /**
30
- * @invisible
31
- */
32
- public int type = RGeomElem.COMMAND;
29
+ /**
30
+ *
31
+ */
32
+ public int type = RGeomElem.COMMAND;
33
33
 
34
- public RPoint[] controlPoints;
35
- public RPoint startPoint;
36
- public RPoint endPoint;
37
- int commandType;
34
+ public RPoint[] controlPoints;
35
+ public RPoint startPoint;
36
+ public RPoint endPoint;
37
+ int commandType;
38
38
 
39
- RPoint[] curvePoints;
39
+ RPoint[] curvePoints;
40
40
 
41
- /**
42
- * @invisible
41
+ /**
43
42
  *
44
- */
45
- public static final int LINETO = 0;
46
- /**
47
- * @invisible
48
43
  *
49
- */
50
- public static final int QUADBEZIERTO = 1;
51
- /**
52
- * @invisible
44
+ */
45
+ public static final int LINETO = 0;
46
+ /**
53
47
  *
54
- */
55
- public static final int CUBICBEZIERTO = 2;
48
+ *
49
+ */
50
+ public static final int QUADBEZIERTO = 1;
51
+ /**
52
+ *
53
+ *
54
+ */
55
+ public static final int CUBICBEZIERTO = 2;
56
56
 
57
- /**
58
- * @invisible
57
+ /**
59
58
  *
60
- */
61
- public static final int ADAPTATIVE = 0;
62
- /**
63
- * @invisible
64
59
  *
65
- */
66
- public static final int UNIFORMLENGTH = 1;
67
- /**
68
- * @invisible
60
+ */
61
+ public static final int ADAPTATIVE = 0;
62
+ /**
69
63
  *
70
- */
71
- public static final int UNIFORMSTEP = 2;
64
+ *
65
+ */
66
+ public static final int UNIFORMLENGTH = 1;
67
+ /**
68
+ *
69
+ *
70
+ */
71
+ public static final int UNIFORMSTEP = 2;
72
+
73
+ public static int segmentType = UNIFORMLENGTH;
74
+
75
+ /* Parameters for ADAPTATIVE (dependent of the PGraphics on which drawing) */
76
+ static final int SEGMENT_RECURSION_LIMIT = 32;
77
+ static final float SEGMENT_DISTANCE_EPSILON = 1.192092896e-07F;
78
+ static final float SEGMENT_COLLINEARITY_EPSILON = 1.192092896e-07F;
79
+ static final float SEGMENT_ANGLE_TOL_EPSILON = 0.01F;
80
+
81
+ static float segmentGfxStrokeWeight = 1.0F;
82
+ static float segmentGfxScale = 1.0F;
83
+ static float segmentApproxScale = 1.0F;
84
+ static float segmentDistTolSqr = 0.25F;
85
+ static float segmentDistTolMnhttn = 4.0F;
86
+ public static float segmentAngleTol = 0.0F;
87
+ static float segmentCuspLimit = 0.0F;
88
+
89
+ /* Parameters for UNIFORMLENGTH (dependent of the PGraphics on which drawing) */
90
+ static float segmentLength = 4.0F;
91
+ static float segmentOffset = 0.0F;
92
+ static float segmentAccOffset = 0.0F;
93
+
94
+ /* Parameters for UNIFORMSTEP */
95
+ static int segmentSteps = 0;
96
+ static boolean segmentLines = false;
97
+
98
+ int oldSegmentType = UNIFORMLENGTH;
99
+
100
+ /* Parameters for ADAPTATIVE (dependent of the PGraphics on which drawing) */
101
+ float oldSegmentCollinearityEpsilon = 1.192092896e-07F;
102
+ float oldSegmentAngleTolEpsilon = 0.01F;
103
+
104
+ float oldSegmentGfxStrokeWeight = 1.0F;
105
+ float oldSegmentGfxScale = 1.0F;
106
+ float oldSegmentApproxScale = 1.0F;
107
+ float oldSegmentDistTolSqr = 0.25F;
108
+ float oldSegmentDistTolMnhttn = 4.0F;
109
+ float oldSegmentAngleTol = 0.0F;
110
+ float oldSegmentCuspLimit = 0.0F;
111
+
112
+ /* Parameters for UNIFORMLENGTH (dependent of the PGraphics on which drawing) */
113
+ float oldSegmentLength = 4.0F;
114
+ float oldSegmentOffset = 0.0F;
115
+ float oldSegmentAccOffset = 0.0F;
116
+
117
+ /* Parameters for UNIFORMSTEP */
118
+ int oldSegmentSteps = 0;
119
+ boolean oldSegmentLines = false;
120
+
121
+ static RCommand createLine(RPoint start, RPoint end) {
122
+ RCommand result = new RCommand();
123
+ result.startPoint = start;
124
+ result.endPoint = end;
125
+ result.commandType = LINETO;
126
+ return result;
127
+ }
128
+
129
+ static RCommand createLine(float startx, float starty, float endx, float endy) {
130
+ return createLine(new RPoint(startx, starty), new RPoint(endx, endy));
131
+ }
132
+
133
+ static RCommand createBezier3(RPoint start, RPoint cp1, RPoint end) {
134
+ RCommand result = new RCommand();
135
+ result.startPoint = start;
136
+ result.append(cp1);
137
+ result.endPoint = end;
138
+ result.commandType = QUADBEZIERTO;
139
+ return result;
140
+ }
141
+
142
+ static RCommand createBezier3(float startx, float starty, float cp1x, float cp1y, float endx, float endy) {
143
+ return createBezier3(new RPoint(startx, starty), new RPoint(cp1x, cp1y), new RPoint(endx, endy));
144
+ }
145
+
146
+ static RCommand createBezier4(RPoint start, RPoint cp1, RPoint cp2, RPoint end) {
147
+ RCommand result = new RCommand();
148
+ result.startPoint = start;
149
+ result.append(cp1);
150
+ result.append(cp2);
151
+ result.endPoint = end;
152
+ result.commandType = CUBICBEZIERTO;
153
+ return result;
154
+ }
155
+
156
+ static RCommand createBezier4(float startx, float starty, float cp1x, float cp1y, float cp2x, float cp2y, float endx, float endy) {
157
+ return createBezier4(new RPoint(startx, starty), new RPoint(cp1x, cp1y), new RPoint(cp2x, cp2y), new RPoint(endx, endy));
158
+ }
159
+
160
+ /**
161
+ * Create an empty command
162
+ *
163
+ *
164
+ */
165
+ public RCommand() {
166
+ controlPoints = null;
167
+ }
168
+
169
+ /**
170
+ * Make a copy of another RCommand object. This can be useful when wanting to
171
+ * transform one but at the same time keep the original.
172
+ *
173
+ * @param c the object of which to make the copy
174
+ *
175
+ */
176
+ public RCommand(RCommand c) {
177
+ this.startPoint = new RPoint(c.startPoint);
178
+ for (int i = 0; i < c.countControlPoints(); i++) {
179
+ this.append(new RPoint(c.controlPoints[i]));
180
+ }
181
+ this.endPoint = new RPoint(c.endPoint);
182
+ this.commandType = c.commandType;
183
+ }
184
+
185
+ /**
186
+ * Make a copy of another RCommand object with a specific start point.
187
+ *
188
+ * @param c the object of which to make the copy
189
+ * @param sp the start point of the command to be created
190
+ */
191
+ public RCommand(RCommand c, RPoint sp) {
192
+ this.startPoint = sp;
193
+ for (int i = 0; i < c.countControlPoints(); i++) {
194
+ this.append(new RPoint(c.controlPoints[i]));
195
+ }
196
+ this.endPoint = new RPoint(c.endPoint);
197
+ this.commandType = c.commandType;
198
+ }
199
+
200
+ /**
201
+ * Create a LINETO command object with specific start and end points.
202
+ *
203
+ * @param sp the start point of the command to be created
204
+ * @param ep the end point of the command to be created
205
+ */
206
+ public RCommand(RPoint sp, RPoint ep) {
207
+ this.startPoint = sp;
208
+ this.endPoint = ep;
209
+ this.commandType = LINETO;
210
+ }
211
+
212
+ /**
213
+ * Create a LINETO command object with specific start and end point
214
+ * coordinates.
215
+ *
216
+ * @param spx the x coordinate of the start point of the command to be created
217
+ * @param spy the y coordinate of the start point of the command to be created
218
+ * @param epx the x coordinate of the end point of the command to be created
219
+ * @param epy the y coordinate of the end point of the command to be created
220
+ */
221
+ public RCommand(float spx, float spy, float epx, float epy) {
222
+ this(new RPoint(spx, spy), new RPoint(epx, epy));
223
+ }
224
+
225
+ /**
226
+ * Create a QUADBEZIERTO command object with specific start, control and end
227
+ * point coordinates.
228
+ *
229
+ * @param sp the start point of the command to be created
230
+ * @param cp1 the first control point of the command to be created
231
+ * @param ep the end point of the command to be created
232
+ */
233
+ public RCommand(RPoint sp, RPoint cp1, RPoint ep) {
234
+ this.startPoint = sp;
235
+ this.append(cp1);
236
+ this.endPoint = ep;
237
+ this.commandType = QUADBEZIERTO;
238
+ }
239
+
240
+ /**
241
+ * Create a QUADBEZIERTO command object with specific start, control and end
242
+ * point coordinates.
243
+ *
244
+ * @param spx the x coordinate of the start point of the command to be created
245
+ * @param spy the y coordinate of the start point of the command to be created
246
+ * @param cp1x the x coordinate of the first control point of the command to
247
+ * be created
248
+ * @param cp1y the y coordinate of the first control point of the command to
249
+ * be created
250
+ * @param epx the x coordinate of the end point of the command to be created
251
+ * @param epy the y coordinate of the end point of the command to be created
252
+ */
253
+ public RCommand(float spx, float spy, float cp1x, float cp1y, float epx, float epy) {
254
+ this(new RPoint(spx, spy), new RPoint(cp1x, cp1y), new RPoint(epx, epy));
255
+ }
256
+
257
+ /**
258
+ * Create a CUBICBEZIERTO command object with specific start, control and end
259
+ * point coordinates.
260
+ *
261
+ * @param sp the start point of the command to be created
262
+ * @param cp1 the first control point of the command to be created
263
+ * @param cp2 the second control point of the command to be created
264
+ * @param ep the end point of the command to be created
265
+ */
266
+ public RCommand(RPoint sp, RPoint cp1, RPoint cp2, RPoint ep) {
267
+ this.startPoint = sp;
268
+ this.append(cp1);
269
+ this.append(cp2);
270
+ this.endPoint = ep;
271
+ this.commandType = CUBICBEZIERTO;
272
+ }
273
+
274
+ /**
275
+ * Create a CUBICBEZIERTO command object with specific start, control and end
276
+ * point coordinates.
277
+ *
278
+ * @param spx the x coordinate of the start point of the command to be created
279
+ * @param spy the y coordinate of the start point of the command to be created
280
+ * @param cp1x the x coordinate of the first control point of the command to
281
+ * be created
282
+ * @param cp1y the y coordinate of the first control point of the command to
283
+ * be created
284
+ * @param cp2x the x coordinate of the second control point of the command to
285
+ * be created
286
+ * @param cp2y the y coordinate of the second control point of the command to
287
+ * be created
288
+ * @param epx the x coordinate of the end point of the command to be created
289
+ * @param epy the y coordinate of the end point of the command to be created
290
+ */
291
+ public RCommand(float spx, float spy, float cp1x, float cp1y, float cp2x, float cp2y, float epx, float epy) {
292
+ this(new RPoint(spx, spy), new RPoint(cp1x, cp1y), new RPoint(cp2x, cp2y), new RPoint(epx, epy));
293
+ }
294
+
295
+ /**
296
+ * @return
297
+ */
298
+ @Override
299
+ public RShape toShape() {
300
+ return new RShape(new RPath(this));
301
+ }
302
+
303
+ @Override
304
+ public int getType() {
305
+ return this.type;
306
+ }
307
+
308
+ /**
309
+ * Use this to set the segmentator type. ADAPTATIVE segmentator minimizes the
310
+ * number of segments avoiding perceptual artifacts like angles or cusps. Use
311
+ * this in order to have Polygons and Meshes with the fewest possible
312
+ * vertices. This can be useful when using or drawing a lot the same Polygon
313
+ * or Mesh deriving from this Shape. UNIFORMLENGTH segmentator is the slowest
314
+ * segmentator and it segments the curve on segments of equal length. This can
315
+ * be useful for very specific applications when for example drawing
316
+ * incrementaly a shape with a uniform speed. UNIFORMSTEP segmentator is the
317
+ * fastest segmentator and it segments the curve based on a constant value of
318
+ * the step of the curve parameter, or on the number of segments wanted. This
319
+ * can be useful when segmpointsentating very often a Shape or when we know
320
+ * the amount of segments necessary for our specific application.
321
+ *
322
+ * @param segmentatorType
323
+ setSegment
324
+ *
325
+ */
326
+ public static void setSegmentator(int segmentatorType) {
327
+ segmentType = segmentatorType;
328
+ }
329
+
330
+ /**
331
+ * Use this to set the segmentator graphic context.
332
+ *
333
+ setSegmentGraphic
334
+ * @param g graphics object too which to adapt the segmentation of the
335
+ * command.
336
+ *
337
+ */
338
+ public static void setSegmentGraphic(PGraphics g) {
339
+ // Set the segmentApproxScale from the graphic context g
340
+ segmentApproxScale = 1.0F;
341
+
342
+ // Set all the gfx-context dependent parameters for all segmentators
343
+ segmentDistTolSqr = 0.5F / segmentApproxScale;
344
+ segmentDistTolSqr *= segmentDistTolSqr;
345
+ segmentDistTolMnhttn = 4.0F / segmentApproxScale;
346
+ segmentAngleTol = 0.0F;
347
+
348
+ if (g.stroke && (g.strokeWeight * segmentApproxScale > 1.0F)) {
349
+ segmentAngleTol = 0.1F;
350
+ }
351
+ }
352
+
353
+ /**
354
+ * Use this to set the segmentator angle tolerance for the ADAPTATIVE
355
+ * segmentator and set the segmentator to ADAPTATIVE.
356
+ *
357
+ setSegmentAngle
358
+ * @param segmentAngleTolerance an angle from 0 to PI/2 it defines the maximum
359
+ * angle between segments.
360
+ *
361
+ */
362
+ public static void setSegmentAngle(float segmentAngleTolerance) {
363
+ //segmentType = ADAPTATIVE;
364
+
365
+ segmentAngleTol = segmentAngleTolerance;
366
+ }
72
367
 
73
- public static int segmentType = UNIFORMLENGTH;
368
+ /**
369
+ * Use this to set the segmentator length for the UNIFORMLENGTH segmentator
370
+ * and set the segmentator to UNIFORMLENGTH.
371
+ *
372
+ setSegmentLength
373
+ * @param segmentLngth the length of each resulting segment.
374
+ *
375
+ */
376
+ public static void setSegmentLength(float segmentLngth) {
377
+ //segmentType = UNIFORMLENGTH;
378
+ if (segmentLngth >= 1) {
379
+ segmentLength = segmentLngth;
380
+ } else {
381
+ segmentLength = 4;
382
+ }
383
+ }
384
+
385
+ /**
386
+ * Use this to set the segmentator offset for the UNIFORMLENGTH segmentator
387
+ * and set the segmentator to UNIFORMLENGTH.
388
+ *
389
+ setSegmentOffset
390
+ * @param segmentOffst the offset of the first point on the path.
391
+ *
392
+ */
393
+ public static void setSegmentOffset(float segmentOffst) {
394
+ //segmentType = UNIFORMLENGTH;
395
+ if (segmentOffst >= 0) {
396
+ segmentOffset = segmentOffst;
397
+ } else {
398
+ segmentOffset = 0;
399
+ }
400
+ }
401
+
402
+ /**
403
+ * Use this to set the segmentator step for the UNIFORMSTEP segmentator and
404
+ * set the segmentator to UNIFORMSTEP.
405
+ *
406
+ setSegmentStep
407
+ * @param segmentStps if a float from +0.0 to 1.0 is passed it's considered as
408
+ * the step, else it's considered as the number of steps. When a value of 0.0
409
+ * is used the steps will be calculated automatically depending on an
410
+ * estimation of the length of the curve. The special value -1 is the same as
411
+ * 0.0 but also turning of the segmentation of lines (faster segmentation).
412
+ *
413
+ */
414
+ public static void setSegmentStep(float segmentStps) {
415
+ //segmentType = UNIFORMSTEP;
416
+ if (segmentStps == -1F) {
417
+ segmentLines = false;
418
+ segmentStps = 0F;
419
+ } else {
420
+ segmentLines = true;
421
+ }
422
+ // Set the parameters
423
+ segmentStps = Math.abs(segmentStps);
424
+ if (segmentStps > 0.0F && segmentStps < 1.0F) {
425
+ segmentSteps = (int) (1F / segmentStps);
426
+ } else {
427
+ segmentSteps = (int) segmentStps;
428
+ }
429
+ }
430
+
431
+ protected void saveSegmentatorContext() {
432
+ oldSegmentType = RCommand.segmentType;
74
433
 
75
434
  /* Parameters for ADAPTATIVE (dependent of the PGraphics on which drawing) */
76
- static final int SEGMENT_RECURSION_LIMIT = 32;
77
- static final float SEGMENT_DISTANCE_EPSILON = 1.192092896e-07F;
78
- static final float SEGMENT_COLLINEARITY_EPSILON = 1.192092896e-07F;
79
- static final float SEGMENT_ANGLE_TOL_EPSILON = 0.01F;
80
-
81
- static float segmentGfxStrokeWeight = 1.0F;
82
- static float segmentGfxScale = 1.0F;
83
- static float segmentApproxScale = 1.0F;
84
- static float segmentDistTolSqr = 0.25F;
85
- static float segmentDistTolMnhttn = 4.0F;
86
- public static float segmentAngleTol = 0.0F;
87
- static float segmentCuspLimit = 0.0F;
435
+ oldSegmentGfxStrokeWeight = RCommand.segmentGfxStrokeWeight;
436
+ oldSegmentGfxScale = RCommand.segmentGfxScale;
437
+ oldSegmentApproxScale = RCommand.segmentApproxScale;
438
+ oldSegmentDistTolSqr = RCommand.segmentDistTolSqr;
439
+ oldSegmentDistTolMnhttn = RCommand.segmentDistTolMnhttn;
440
+ oldSegmentAngleTol = RCommand.segmentAngleTol;
441
+ oldSegmentCuspLimit = RCommand.segmentCuspLimit;
88
442
 
89
443
  /* Parameters for UNIFORMLENGTH (dependent of the PGraphics on which drawing) */
90
- static float segmentLength = 4.0F;
91
- static float segmentOffset = 0.0F;
92
- static float segmentAccOffset = 0.0F;
444
+ oldSegmentLength = RCommand.segmentLength;
445
+ oldSegmentOffset = RCommand.segmentOffset;
446
+ oldSegmentAccOffset = RCommand.segmentAccOffset;
93
447
 
94
448
  /* Parameters for UNIFORMSTEP */
95
- static int segmentSteps = 0;
96
- static boolean segmentLines = false;
449
+ oldSegmentSteps = RCommand.segmentSteps;
450
+ oldSegmentLines = RCommand.segmentLines;
451
+ }
97
452
 
98
- int oldSegmentType = UNIFORMLENGTH;
453
+ protected void restoreSegmentatorContext() {
454
+ RCommand.segmentType = oldSegmentType;
99
455
 
100
456
  /* Parameters for ADAPTATIVE (dependent of the PGraphics on which drawing) */
101
- float oldSegmentCollinearityEpsilon = 1.192092896e-07F;
102
- float oldSegmentAngleTolEpsilon = 0.01F;
103
-
104
- float oldSegmentGfxStrokeWeight = 1.0F;
105
- float oldSegmentGfxScale = 1.0F;
106
- float oldSegmentApproxScale = 1.0F;
107
- float oldSegmentDistTolSqr = 0.25F;
108
- float oldSegmentDistTolMnhttn = 4.0F;
109
- float oldSegmentAngleTol = 0.0F;
110
- float oldSegmentCuspLimit = 0.0F;
457
+ RCommand.segmentGfxStrokeWeight = oldSegmentGfxStrokeWeight;
458
+ RCommand.segmentGfxScale = oldSegmentGfxScale;
459
+ RCommand.segmentApproxScale = oldSegmentApproxScale;
460
+ RCommand.segmentDistTolSqr = oldSegmentDistTolSqr;
461
+ RCommand.segmentDistTolMnhttn = oldSegmentDistTolMnhttn;
462
+ RCommand.segmentAngleTol = oldSegmentAngleTol;
463
+ RCommand.segmentCuspLimit = oldSegmentCuspLimit;
111
464
 
112
465
  /* Parameters for UNIFORMLENGTH (dependent of the PGraphics on which drawing) */
113
- float oldSegmentLength = 4.0F;
114
- float oldSegmentOffset = 0.0F;
115
- float oldSegmentAccOffset = 0.0F;
466
+ RCommand.segmentLength = oldSegmentLength;
467
+ RCommand.segmentOffset = oldSegmentOffset;
468
+ RCommand.segmentAccOffset = oldSegmentAccOffset;
116
469
 
117
470
  /* Parameters for UNIFORMSTEP */
118
- int oldSegmentSteps = 0;
119
- boolean oldSegmentLines = false;
120
-
121
- static RCommand createLine(RPoint start, RPoint end) {
122
- RCommand result = new RCommand();
123
- result.startPoint = start;
124
- result.endPoint = end;
125
- result.commandType = LINETO;
126
- return result;
127
- }
471
+ RCommand.segmentSteps = oldSegmentSteps;
472
+ RCommand.segmentLines = oldSegmentLines;
473
+ }
128
474
 
129
- static RCommand createLine(float startx, float starty, float endx, float endy) {
130
- return createLine(new RPoint(startx, starty), new RPoint(endx, endy));
475
+ /**
476
+ * Use this to return the number of control points of the curve.
477
+ *
478
+ countControlPoints
479
+ * @return int, the number of control points.
480
+ *
481
+ */
482
+ public int countControlPoints() {
483
+ if (controlPoints == null) {
484
+ return 0;
131
485
  }
486
+ return controlPoints.length;
487
+ }
132
488
 
133
- static RCommand createBezier3(RPoint start, RPoint cp1, RPoint end) {
134
- RCommand result = new RCommand();
135
- result.startPoint = start;
136
- result.append(cp1);
137
- result.endPoint = end;
138
- result.commandType = QUADBEZIERTO;
139
- return result;
140
- }
489
+ /**
490
+ * Use this to return the command type.
491
+ *
492
+ getCommandType
493
+ * @return int, an integer which can take the following values:
494
+ * RCommand.LINETO, RCommand.QUADBEZIERTO, RCommand.CUBICBEZIERTO.
495
+ *
496
+ */
497
+ public int getCommandType() {
498
+ return commandType;
499
+ }
141
500
 
142
- static RCommand createBezier3(float startx, float starty, float cp1x, float cp1y, float endx, float endy) {
143
- return createBezier3(new RPoint(startx, starty), new RPoint(cp1x, cp1y), new RPoint(endx, endy));
144
- }
501
+ /**
502
+ * Use this to return the start point of the curve.
503
+ *
504
+ getStartPoint
505
+ * @return RPoint, the start point of the curve.
506
+ *
507
+ *
508
+ */
509
+ RPoint getStartPoint() {
510
+ return startPoint;
511
+ }
145
512
 
146
- static RCommand createBezier4(RPoint start, RPoint cp1, RPoint cp2, RPoint end) {
147
- RCommand result = new RCommand();
148
- result.startPoint = start;
149
- result.append(cp1);
150
- result.append(cp2);
151
- result.endPoint = end;
152
- result.commandType = CUBICBEZIERTO;
153
- return result;
154
- }
513
+ /**
514
+ * Use this to return the end point of the curve.
515
+ *
516
+ getEndPoint
517
+ * @return RPoint, the end point of the curve.
518
+ *
519
+ *
520
+ */
521
+ RPoint getEndPoint() {
522
+ return endPoint;
523
+ }
524
+
525
+ /**
526
+ * Use this to return the control points of the curve. It returns the points
527
+ * in the way of an array of RPoint.
528
+ *
529
+ getControlPoints
530
+ * @return RPoint[], the control points returned in an array.
531
+ *
532
+ *
533
+ */
534
+ RPoint[] getControlPoints() {
535
+ return controlPoints;
536
+ }
537
+
538
+ /**
539
+ * Use this to return the points on the curve. It returns the points in the
540
+ * way of an array of RPoint.
541
+ *
542
+ getPoints
543
+ * @return RPoint[], the vertices returned in an array.
544
+ *
545
+ */
546
+ @Override
547
+ public RPoint[] getPoints() {
548
+ return getPoints(true);
549
+ }
155
550
 
156
- static RCommand createBezier4(float startx, float starty, float cp1x, float cp1y, float cp2x, float cp2y, float endx, float endy) {
157
- return createBezier4(new RPoint(startx, starty), new RPoint(cp1x, cp1y), new RPoint(cp2x, cp2y), new RPoint(endx, endy));
158
- }
551
+ protected RPoint[] getPoints(boolean resetSegmentator) {
159
552
 
160
- /**
161
- * Create an empty command
162
- *
163
- * @invisible
164
- */
165
- public RCommand() {
166
- controlPoints = null;
553
+ if (resetSegmentator) {
554
+ saveSegmentatorContext();
555
+ RCommand.segmentOffset = 0F;
556
+ RCommand.segmentAccOffset = 0F;
167
557
  }
168
558
 
169
- /**
170
- * Make a copy of another RCommand object. This can be useful when wanting
171
- * to transform one but at the same time keep the original.
172
- *
173
- * @param c the object of which to make the copy
174
- * @invisible
175
- */
176
- public RCommand(RCommand c) {
177
- this.startPoint = new RPoint(c.startPoint);
178
- for (int i = 0; i < c.countControlPoints(); i++) {
179
- this.append(new RPoint(c.controlPoints[i]));
559
+ RPoint[] result = null;
560
+ switch (segmentType) {
561
+ case ADAPTATIVE:
562
+ switch (commandType) {
563
+ case LINETO:
564
+ result = new RPoint[2];
565
+ result[0] = startPoint;
566
+ result[1] = endPoint;
567
+ break;
568
+
569
+ case QUADBEZIERTO:
570
+ quadBezierAdaptative();
571
+ result = curvePoints;
572
+ curvePoints = null;
573
+ break;
574
+
575
+ case CUBICBEZIERTO:
576
+ cubicBezierAdaptative();
577
+ result = curvePoints;
578
+ curvePoints = null;
579
+ break;
180
580
  }
181
- this.endPoint = new RPoint(c.endPoint);
182
- this.commandType = c.commandType;
183
- }
581
+ break;
184
582
 
185
- /**
186
- * Make a copy of another RCommand object with a specific start point.
187
- *
188
- * @param c the object of which to make the copy
189
- * @param sp the start point of the command to be created
190
- */
191
- public RCommand(RCommand c, RPoint sp) {
192
- this.startPoint = sp;
193
- for (int i = 0; i < c.countControlPoints(); i++) {
194
- this.append(new RPoint(c.controlPoints[i]));
583
+ case UNIFORMLENGTH:
584
+ switch (commandType) {
585
+ case LINETO:
586
+ lineUniformLength();
587
+ result = curvePoints;
588
+ curvePoints = null;
589
+ break;
590
+
591
+ case QUADBEZIERTO:
592
+ quadBezierUniformLength();
593
+ result = curvePoints;
594
+ curvePoints = null;
595
+ break;
596
+
597
+ case CUBICBEZIERTO:
598
+ cubicBezierUniformLength();
599
+ result = curvePoints;
600
+ curvePoints = null;
601
+ break;
195
602
  }
196
- this.endPoint = new RPoint(c.endPoint);
197
- this.commandType = c.commandType;
198
- }
199
-
200
- /**
201
- * Create a LINETO command object with specific start and end points.
202
- *
203
- * @param sp the start point of the command to be created
204
- * @param ep the end point of the command to be created
205
- */
206
- public RCommand(RPoint sp, RPoint ep) {
207
- this.startPoint = sp;
208
- this.endPoint = ep;
209
- this.commandType = LINETO;
210
- }
211
-
212
- /**
213
- * Create a LINETO command object with specific start and end point
214
- * coordinates.
215
- *
216
- * @param spx the x coordinate of the start point of the command to be
217
- * created
218
- * @param spy the y coordinate of the start point of the command to be
219
- * created
220
- * @param epx the x coordinate of the end point of the command to be created
221
- * @param epy the y coordinate of the end point of the command to be created
222
- */
223
- public RCommand(float spx, float spy, float epx, float epy) {
224
- this(new RPoint(spx, spy), new RPoint(epx, epy));
225
- }
603
+ break;
226
604
 
227
- /**
228
- * Create a QUADBEZIERTO command object with specific start, control and end
229
- * point coordinates.
230
- *
231
- * @param sp the start point of the command to be created
232
- * @param cp1 the first control point of the command to be created
233
- * @param ep the end point of the command to be created
234
- */
235
- public RCommand(RPoint sp, RPoint cp1, RPoint ep) {
236
- this.startPoint = sp;
237
- this.append(cp1);
238
- this.endPoint = ep;
239
- this.commandType = QUADBEZIERTO;
240
- }
241
-
242
- /**
243
- * Create a QUADBEZIERTO command object with specific start, control and end
244
- * point coordinates.
245
- *
246
- * @param spx the x coordinate of the start point of the command to be
247
- * created
248
- * @param spy the y coordinate of the start point of the command to be
249
- * created
250
- * @param cp1x the x coordinate of the first control point of the command to
251
- * be created
252
- * @param cp1y the y coordinate of the first control point of the command to
253
- * be created
254
- * @param epx the x coordinate of the end point of the command to be created
255
- * @param epy the y coordinate of the end point of the command to be created
256
- */
257
- public RCommand(float spx, float spy, float cp1x, float cp1y, float epx, float epy) {
258
- this(new RPoint(spx, spy), new RPoint(cp1x, cp1y), new RPoint(epx, epy));
259
- }
260
-
261
- /**
262
- * Create a CUBICBEZIERTO command object with specific start, control and
263
- * end point coordinates.
264
- *
265
- * @param sp the start point of the command to be created
266
- * @param cp1 the first control point of the command to be created
267
- * @param cp2 the second control point of the command to be created
268
- * @param ep the end point of the command to be created
269
- */
270
- public RCommand(RPoint sp, RPoint cp1, RPoint cp2, RPoint ep) {
271
- this.startPoint = sp;
272
- this.append(cp1);
273
- this.append(cp2);
274
- this.endPoint = ep;
275
- this.commandType = CUBICBEZIERTO;
276
- }
277
-
278
- /**
279
- * Create a CUBICBEZIERTO command object with specific start, control and
280
- * end point coordinates.
281
- *
282
- * @param spx the x coordinate of the start point of the command to be
283
- * created
284
- * @param spy the y coordinate of the start point of the command to be
285
- * created
286
- * @param cp1x the x coordinate of the first control point of the command to
287
- * be created
288
- * @param cp1y the y coordinate of the first control point of the command to
289
- * be created
290
- * @param cp2x the x coordinate of the second control point of the command
291
- * to be created
292
- * @param cp2y the y coordinate of the second control point of the command
293
- * to be created
294
- * @param epx the x coordinate of the end point of the command to be created
295
- * @param epy the y coordinate of the end point of the command to be created
296
- */
297
- public RCommand(float spx, float spy, float cp1x, float cp1y, float cp2x, float cp2y, float epx, float epy) {
298
- this(new RPoint(spx, spy), new RPoint(cp1x, cp1y), new RPoint(cp2x, cp2y), new RPoint(epx, epy));
605
+ case UNIFORMSTEP:
606
+ switch (commandType) {
607
+ case LINETO:
608
+ if (segmentLines) {
609
+ lineUniformStep();
610
+ result = curvePoints;
611
+ curvePoints = null;
612
+ } else {
613
+ result = new RPoint[2];
614
+ result[0] = startPoint;
615
+ result[1] = endPoint;
616
+ }
617
+ break;
618
+
619
+ case QUADBEZIERTO:
620
+ quadBezierUniformStep();
621
+ result = curvePoints;
622
+ curvePoints = null;
623
+ break;
624
+
625
+ case CUBICBEZIERTO:
626
+ cubicBezierUniformStep();
627
+ result = curvePoints;
628
+ curvePoints = null;
629
+ break;
630
+ }
631
+ break;
299
632
  }
300
633
 
301
- /**
302
- * @return @invisible
303
- */
304
- @Override
305
- public RShape toShape() {
306
- return new RShape(new RPath(this));
634
+ if (resetSegmentator) {
635
+ restoreSegmentatorContext();
307
636
  }
308
637
 
309
- @Override
310
- public int getType() {
311
- return this.type;
312
- }
638
+ return result;
639
+ }
313
640
 
314
- /**
315
- * Use this to set the segmentator type. ADAPTATIVE segmentator minimizes
316
- * the number of segments avoiding perceptual artifacts like angles or
317
- * cusps. Use this in order to have Polygons and Meshes with the fewest
318
- * possible vertices. This can be useful when using or drawing a lot the
319
- * same Polygon or Mesh deriving from this Shape. UNIFORMLENGTH segmentator
320
- * is the slowest segmentator and it segments the curve on segments of equal
321
- * length. This can be useful for very specific applications when for
322
- * example drawing incrementaly a shape with a uniform speed. UNIFORMSTEP
323
- * segmentator is the fastest segmentator and it segments the curve based on
324
- * a constant value of the step of the curve parameter, or on the number of
325
- * segments wanted. This can be useful when segmpointsentating very often a
326
- * Shape or when we know the amount of segments necessary for our specific
327
- * application.
328
- *
329
- * @param segmentatorType
330
- * @eexample setSegment
641
+ /**
642
+ * Use this to return a specific point on the curve. It returns the RPoint for
643
+ * a given advancement parameter t on the curve.
331
644
  *
332
- */
333
- public static void setSegmentator(int segmentatorType) {
334
- segmentType = segmentatorType;
335
- }
336
-
337
- /**
338
- * Use this to set the segmentator graphic context.
339
- *
340
- * @eexample setSegmentGraphic
341
- * @param g graphics object too which to adapt the segmentation of the
342
- * command.
645
+ getPoint
646
+ * @param t float, the parameter of advancement on the curve. t must have
647
+ * values between 0 and 1.
648
+ * @return RPoint, the vertice returned.
343
649
  *
344
- */
345
- public static void setSegmentGraphic(PGraphics g) {
346
- // Set the segmentApproxScale from the graphic context g
347
- segmentApproxScale = 1.0F;
348
-
349
- // Set all the gfx-context dependent parameters for all segmentators
350
- segmentDistTolSqr = 0.5F / segmentApproxScale;
351
- segmentDistTolSqr *= segmentDistTolSqr;
352
- segmentDistTolMnhttn = 4.0F / segmentApproxScale;
353
- segmentAngleTol = 0.0F;
354
-
355
- if (g.stroke && (g.strokeWeight * segmentApproxScale > 1.0F)) {
356
- segmentAngleTol = 0.1F;
650
+ */
651
+ @Override
652
+ public RPoint getPoint(float t) {
653
+ /* limit the value of t between 0 and 1 */
654
+ t = (t > 1F) ? 1F : t;
655
+ t = (t < 0F) ? 0F : t;
656
+ float ax, bx, cx;
657
+ float ay, by, cy;
658
+ float tSquared, tDoubled, tCubed;
659
+ float dx, dy;
660
+
661
+ switch (commandType) {
662
+ case LINETO:
663
+ dx = endPoint.x - startPoint.x;
664
+ dy = endPoint.y - startPoint.y;
665
+ return new RPoint(startPoint.x + dx * t, startPoint.y + dy * t);
666
+
667
+ case QUADBEZIERTO:
668
+ /* calculate the polynomial coefficients */
669
+ bx = controlPoints[0].x - startPoint.x;
670
+ ax = endPoint.x - controlPoints[0].x - bx;
671
+ by = controlPoints[0].y - startPoint.y;
672
+ ay = endPoint.y - controlPoints[0].y - by;
673
+
674
+ /* calculate the curve point at parameter value t */
675
+ tSquared = t * t;
676
+ tDoubled = 2F * t;
677
+ return new RPoint((ax * tSquared) + (bx * tDoubled) + startPoint.x, (ay * tSquared) + (by * tDoubled) + startPoint.y);
678
+
679
+ case CUBICBEZIERTO:
680
+ /* calculate the polynomial coefficients */
681
+ cx = 3F * (controlPoints[0].x - startPoint.x);
682
+ bx = 3F * (controlPoints[1].x - controlPoints[0].x) - cx;
683
+ ax = endPoint.x - startPoint.x - cx - bx;
684
+ cy = 3F * (controlPoints[0].y - startPoint.y);
685
+ by = 3F * (controlPoints[1].y - controlPoints[0].y) - cy;
686
+ ay = endPoint.y - startPoint.y - cy - by;
687
+
688
+ /* calculate the curve point at parameter value t */
689
+ tSquared = t * t;
690
+ tCubed = tSquared * t;
691
+ return new RPoint((ax * tCubed) + (bx * tSquared) + (cx * t) + startPoint.x, (ay * tCubed) + (by * tSquared) + (cy * t) + startPoint.y);
692
+ }
693
+
694
+ return new RPoint();
695
+ }
696
+
697
+ /**
698
+ * Use this to return the tangents on the curve. It returns the vectors in the
699
+ * form of an array of RPoint.
700
+ *
701
+ getTangents
702
+ * @param segments int, the number of segments in which to divide the curve.
703
+ * @return RPoint[], the tangent vectors returned in an array.
704
+ *
705
+ */
706
+ public RPoint[] getTangents(int segments) {
707
+ RPoint[] result;
708
+ float dt, t;
709
+ switch (commandType) {
710
+ case LINETO:
711
+ result = new RPoint[2];
712
+ result[0] = startPoint;
713
+ result[1] = endPoint;
714
+ return result;
715
+ case QUADBEZIERTO:
716
+ case CUBICBEZIERTO:
717
+ result = new RPoint[segments];
718
+ dt = 1F / segments;
719
+ t = 0F;
720
+ for (int i = 0; i < segments; i++) {
721
+ result[i] = getTangent(t);
722
+ t += dt;
357
723
  }
724
+ return result;
358
725
  }
726
+ return null;
727
+ }
359
728
 
360
- /**
361
- * Use this to set the segmentator angle tolerance for the ADAPTATIVE
362
- * segmentator and set the segmentator to ADAPTATIVE.
363
- *
364
- * @eexample setSegmentAngle
365
- * @param segmentAngleTolerance an angle from 0 to PI/2 it defines the
366
- * maximum angle between segments.
367
- *
368
- */
369
- public static void setSegmentAngle(float segmentAngleTolerance) {
370
- //segmentType = ADAPTATIVE;
729
+ @Override
730
+ public RPoint[] getTangents() {
371
731
 
372
- segmentAngleTol = segmentAngleTolerance;
373
- }
732
+ return getTangents(100);
733
+ }
374
734
 
375
- /**
376
- * Use this to set the segmentator length for the UNIFORMLENGTH segmentator
377
- * and set the segmentator to UNIFORMLENGTH.
378
- *
379
- * @eexample setSegmentLength
380
- * @param segmentLngth the length of each resulting segment.
735
+ /**
736
+ * Use this to return a specific tangent on the curve. It returns the RPoint
737
+ * representing the tangent vector for a given value of the advancement
738
+ * parameter t on the curve.
381
739
  *
382
- */
383
- public static void setSegmentLength(float segmentLngth) {
384
- //segmentType = UNIFORMLENGTH;
385
- if (segmentLngth >= 1) {
386
- segmentLength = segmentLngth;
387
- } else {
388
- segmentLength = 4;
389
- }
390
- }
391
-
392
- /**
393
- * Use this to set the segmentator offset for the UNIFORMLENGTH segmentator
394
- * and set the segmentator to UNIFORMLENGTH.
395
- *
396
- * @eexample setSegmentOffset
397
- * @param segmentOffst the offset of the first point on the path.
740
+ getTangent
741
+ * @param t float, the parameter of advancement on the curve. t must have
742
+ * values between 0 and 1.
743
+ * @return RPoint, the vertice returned.
398
744
  *
399
- */
400
- public static void setSegmentOffset(float segmentOffst) {
401
- //segmentType = UNIFORMLENGTH;
402
- if (segmentOffst >= 0) {
403
- segmentOffset = segmentOffst;
404
- } else {
405
- segmentOffset = 0;
406
- }
407
- }
408
-
409
- /**
410
- * Use this to set the segmentator step for the UNIFORMSTEP segmentator and
411
- * set the segmentator to UNIFORMSTEP.
412
- *
413
- * @eexample setSegmentStep
414
- * @param segmentStps if a float from +0.0 to 1.0 is passed it's considered
415
- * as the step, else it's considered as the number of steps. When a value of
416
- * 0.0 is used the steps will be calculated automatically depending on an
417
- * estimation of the length of the curve. The special value -1 is the same
418
- * as 0.0 but also turning of the segmentation of lines (faster
419
- * segmentation).
745
+ */
746
+ @Override
747
+ public RPoint getTangent(float t) {
748
+ /* limit the value of t between 0 and 1 */
749
+ t = (t > 1F) ? 1F : t;
750
+ t = (t < 0F) ? 0F : t;
751
+
752
+ float dx, dy, tx, ty, t2, t_1, t_12;
753
+
754
+ switch (commandType) {
755
+ case LINETO:
756
+ dx = endPoint.x - startPoint.x;
757
+ dy = endPoint.y - startPoint.y;
758
+ return new RPoint(dx, dy);
759
+
760
+ case QUADBEZIERTO:
761
+ /* calculate the curve point at parameter value t */
762
+ tx = 2F * ((startPoint.x - 2 * controlPoints[0].x + endPoint.x) * t + (controlPoints[0].x - startPoint.x));
763
+ ty = 2F * ((startPoint.y - 2 * controlPoints[0].y + endPoint.y) * t + (controlPoints[0].y - startPoint.y));
764
+ //float norm = (float)Math.sqrt(tx*tx + ty*ty);
765
+ //return new RPoint(tx/norm,ty/norm);
766
+ return new RPoint(tx, ty);
767
+
768
+ case CUBICBEZIERTO:
769
+ /* calculate the curve point at parameter value t */
770
+ t2 = t * t;
771
+ t_1 = 1 - t;
772
+ t_12 = t_1 * t_1;
773
+
774
+ return new RPoint(-3F * t_12 * startPoint.x + 3F * (3F * t2 - 4F * t + 1F) * controlPoints[0].x + 3F * t * (2F - 3F * t) * controlPoints[1].x + 3F * t2 * endPoint.x, -3F * t_12 * startPoint.y + 3F * (3F * t2 - 4F * t + 1F) * controlPoints[0].y + 3F * t * (2F - 3F * t) * controlPoints[1].y + 3F * t2 * endPoint.y);
775
+ }
776
+
777
+ return new RPoint();
778
+ }
779
+
780
+ /**
781
+ * Use this to return arc length of a curve. It returns the float representing
782
+ * the length given the value of the advancement parameter t on the curve. The
783
+ * current implementation of this function is very slow, not recommended for
784
+ * using during frame draw.
420
785
  *
421
- */
422
- public static void setSegmentStep(float segmentStps) {
423
- //segmentType = UNIFORMSTEP;
424
- if (segmentStps == -1F) {
425
- segmentLines = false;
426
- segmentStps = 0F;
427
- } else {
428
- segmentLines = true;
429
- }
430
- // Set the parameters
431
- segmentStps = Math.abs(segmentStps);
432
- if (segmentStps > 0.0F && segmentStps < 1.0F) {
433
- segmentSteps = (int) (1F / segmentStps);
434
- } else {
435
- segmentSteps = (int) segmentStps;
436
- }
437
- }
438
-
439
- protected void saveSegmentatorContext() {
440
- oldSegmentType = RCommand.segmentType;
441
-
442
- /* Parameters for ADAPTATIVE (dependent of the PGraphics on which drawing) */
443
- oldSegmentGfxStrokeWeight = RCommand.segmentGfxStrokeWeight;
444
- oldSegmentGfxScale = RCommand.segmentGfxScale;
445
- oldSegmentApproxScale = RCommand.segmentApproxScale;
446
- oldSegmentDistTolSqr = RCommand.segmentDistTolSqr;
447
- oldSegmentDistTolMnhttn = RCommand.segmentDistTolMnhttn;
448
- oldSegmentAngleTol = RCommand.segmentAngleTol;
449
- oldSegmentCuspLimit = RCommand.segmentCuspLimit;
450
-
451
- /* Parameters for UNIFORMLENGTH (dependent of the PGraphics on which drawing) */
452
- oldSegmentLength = RCommand.segmentLength;
453
- oldSegmentOffset = RCommand.segmentOffset;
454
- oldSegmentAccOffset = RCommand.segmentAccOffset;
455
-
456
- /* Parameters for UNIFORMSTEP */
457
- oldSegmentSteps = RCommand.segmentSteps;
458
- oldSegmentLines = RCommand.segmentLines;
459
- }
460
-
461
- protected void restoreSegmentatorContext() {
462
- RCommand.segmentType = oldSegmentType;
463
-
464
- /* Parameters for ADAPTATIVE (dependent of the PGraphics on which drawing) */
465
- RCommand.segmentGfxStrokeWeight = oldSegmentGfxStrokeWeight;
466
- RCommand.segmentGfxScale = oldSegmentGfxScale;
467
- RCommand.segmentApproxScale = oldSegmentApproxScale;
468
- RCommand.segmentDistTolSqr = oldSegmentDistTolSqr;
469
- RCommand.segmentDistTolMnhttn = oldSegmentDistTolMnhttn;
470
- RCommand.segmentAngleTol = oldSegmentAngleTol;
471
- RCommand.segmentCuspLimit = oldSegmentCuspLimit;
472
-
473
- /* Parameters for UNIFORMLENGTH (dependent of the PGraphics on which drawing) */
474
- RCommand.segmentLength = oldSegmentLength;
475
- RCommand.segmentOffset = oldSegmentOffset;
476
- RCommand.segmentAccOffset = oldSegmentAccOffset;
477
-
478
- /* Parameters for UNIFORMSTEP */
479
- RCommand.segmentSteps = oldSegmentSteps;
480
- RCommand.segmentLines = oldSegmentLines;
481
- }
482
-
483
- /**
484
- * Use this to return the number of control points of the curve.
485
- *
486
- * @eexample countControlPoints
487
- * @return int, the number of control points.
786
+ RCommand_getCurveLength
787
+ * @param t float, the parameter of advancement on the curve. t must have
788
+ * values between 0 and 1.
789
+ * @return float, the length returned.
488
790
  *
489
- */
490
- public int countControlPoints() {
491
- if (controlPoints == null) {
492
- return 0;
493
- }
494
- return controlPoints.length;
495
- }
496
-
497
- /**
498
- * Use this to return the command type.
499
- *
500
- * @eexample getCommandType
501
- * @return int, an integer which can take the following values:
502
- * RCommand.LINETO, RCommand.QUADBEZIERTO, RCommand.CUBICBEZIERTO.
503
791
  *
504
- */
505
- public int getCommandType() {
506
- return commandType;
507
- }
508
-
509
- /**
510
- * Use this to return the start point of the curve.
511
- *
512
- * @eexample getStartPoint
513
- * @return RPoint, the start point of the curve.
514
- * @invisible
792
+ */
793
+ public float getCurveLength(float t) {
794
+
795
+ /* limit the value of t between 0 and 1 */
796
+ t = (t > 1F) ? 1F : t;
797
+ t = (t < 0F) ? 0F : t;
798
+
799
+ float dx, dy, dx2, dy2, t2;
800
+
801
+ switch (commandType) {
802
+ case LINETO:
803
+ dx = endPoint.x - startPoint.x;
804
+ dy = endPoint.y - startPoint.y;
805
+ dx2 = dx * dx;
806
+ dy2 = dy * dy;
807
+ t2 = t * t;
808
+ //RG.parent().println("RCommand/LINETO::: getCurveLength: " + (float)Math.sqrt(dx2*t2 + dy2*t2));
809
+ return (float) Math.sqrt(dx2 * t2 + dy2 * t2);
810
+
811
+ case QUADBEZIERTO:
812
+ /* calculate the curve point at parameter value t */
813
+ return quadBezierLength();
814
+
815
+ case CUBICBEZIERTO:
816
+ /* calculate the curve point at parameter value t */
817
+ return cubicBezierLength();
818
+ }
819
+
820
+ return -1F;
821
+ }
822
+
823
+ /**
824
+ * Use this to return arc length of a curve. It returns the float representing
825
+ * the length given the value of the advancement parameter t on the curve. The
826
+ * current implementation of this function is very slow, not recommended for
827
+ * using during frame draw.
515
828
  *
516
- */
517
- RPoint getStartPoint() {
518
- return startPoint;
519
- }
520
-
521
- /**
522
- * Use this to return the end point of the curve.
523
- *
524
- * @eexample getEndPoint
525
- * @return RPoint, the end point of the curve.
526
- * @invisible
829
+ RCommand_getCurveLength
830
+ * @return float, the length returned.
527
831
  *
528
- */
529
- RPoint getEndPoint() {
530
- return endPoint;
531
- }
532
-
533
- /**
534
- * Use this to return the control points of the curve. It returns the points
535
- * in the way of an array of RPoint.
536
- *
537
- * @eexample getControlPoints
538
- * @return RPoint[], the control points returned in an array.
539
- * @invisible
540
832
  *
541
- */
542
- RPoint[] getControlPoints() {
543
- return controlPoints;
544
- }
545
-
546
- /**
547
- * Use this to return the points on the curve. It returns the points in the
548
- * way of an array of RPoint.
549
- *
550
- * @eexample getPoints
551
- * @return RPoint[], the vertices returned in an array.
833
+ */
834
+ @Override
835
+ public float getCurveLength() {
836
+ return getCurveLength(1F);
837
+ }
838
+
839
+ @Override
840
+ public RPoint[][] getPointsInPaths() {
841
+ PApplet.println("Feature not yet implemented for this class.");
842
+ return null;
843
+ }
844
+
845
+ @Override
846
+ public RPoint[][] getHandlesInPaths() {
847
+ PApplet.println("Feature not yet implemented for this class.");
848
+ return null;
849
+ }
850
+
851
+ @Override
852
+ public RPoint[][] getTangentsInPaths() {
853
+ PApplet.println("Feature not yet implemented for this class.");
854
+ return null;
855
+ }
856
+
857
+ @Override
858
+ public boolean contains(RPoint p) {
859
+ PApplet.println("Feature not yet implemented for this class.");
860
+ return false;
861
+ }
862
+
863
+ /**
864
+ * Use this method to draw the command.
552
865
  *
553
- */
554
- @Override
555
- public RPoint[] getPoints() {
556
- return getPoints(true);
557
- }
558
-
559
- protected RPoint[] getPoints(boolean resetSegmentator) {
866
+ drawCommand
867
+ * @param g PGraphics, the graphics object on which to draw the command
868
+ */
869
+ @Override
870
+ public void draw(PGraphics g) {
871
+ RPoint[] points = getPoints();
872
+ if (points == null) {
873
+ return;
874
+ }
875
+ g.beginShape();
876
+ for (RPoint point : points) {
877
+ g.vertex(point.x, point.y);
878
+ }
879
+ g.endShape();
880
+ }
881
+
882
+ /**
883
+ * Use this method to draw the command.
884
+ *
885
+ drawCommand
886
+ * @param a the applet object on which to draw the command
887
+ */
888
+ @Override
889
+ public void draw(PApplet a) {
890
+ RPoint[] points = getPoints();
891
+ if (points == null) {
892
+ return;
893
+ }
894
+
895
+ a.beginShape();
896
+ for (RPoint point : points) {
897
+ a.vertex(point.x, point.y);
898
+ }
899
+ a.endShape();
900
+ }
901
+
902
+ /**
903
+ * Use this to return the start, control and end points of the curve. It
904
+ * returns the points in the way of an array of RPoint.
905
+ *
906
+ getHandles
907
+ * @return RPoint[], the vertices returned in an array.
908
+ *
909
+ */
910
+ @Override
911
+ public RPoint[] getHandles() {
912
+ RPoint[] result;
913
+ if (controlPoints == null) {
914
+ result = new RPoint[2];
915
+ result[0] = startPoint;
916
+ result[1] = endPoint;
917
+ } else {
918
+ result = new RPoint[controlPoints.length + 2];
919
+ result[0] = startPoint;
920
+ System.arraycopy(controlPoints, 0, result, 1, controlPoints.length);
921
+ result[result.length - 1] = endPoint;
922
+ }
923
+ return result;
924
+ }
925
+
926
+ /**
927
+ * Returns two commands resulting of splitting the command.
928
+ *
929
+ split
930
+ * @param t the advancement on the curve where command should be split.
931
+ * @return RPoint[], the tangent vectors returned in an array.
932
+ *
933
+ */
934
+ public RCommand[] split(float t) {
560
935
 
561
- if (resetSegmentator) {
562
- saveSegmentatorContext();
563
- RCommand.segmentOffset = 0F;
564
- RCommand.segmentAccOffset = 0F;
565
- }
936
+ switch (commandType) {
937
+ case LINETO:
938
+ return splitLine(t);
566
939
 
567
- RPoint[] result = null;
568
- switch (segmentType) {
569
- case ADAPTATIVE:
570
- switch (commandType) {
571
- case LINETO:
572
- result = new RPoint[2];
573
- result[0] = startPoint;
574
- result[1] = endPoint;
575
- break;
576
-
577
- case QUADBEZIERTO:
578
- quadBezierAdaptative();
579
- result = curvePoints;
580
- curvePoints = null;
581
- break;
582
-
583
- case CUBICBEZIERTO:
584
- cubicBezierAdaptative();
585
- result = curvePoints;
586
- curvePoints = null;
587
- break;
588
- }
589
- break;
590
-
591
- case UNIFORMLENGTH:
592
- switch (commandType) {
593
- case LINETO:
594
- lineUniformLength();
595
- result = curvePoints;
596
- curvePoints = null;
597
- break;
598
-
599
- case QUADBEZIERTO:
600
- quadBezierUniformLength();
601
- result = curvePoints;
602
- curvePoints = null;
603
- break;
604
-
605
- case CUBICBEZIERTO:
606
- cubicBezierUniformLength();
607
- result = curvePoints;
608
- curvePoints = null;
609
- break;
610
- }
611
- break;
612
-
613
- case UNIFORMSTEP:
614
- switch (commandType) {
615
- case LINETO:
616
- if (segmentLines) {
617
- lineUniformStep();
618
- result = curvePoints;
619
- curvePoints = null;
620
- } else {
621
- result = new RPoint[2];
622
- result[0] = startPoint;
623
- result[1] = endPoint;
624
- }
625
- break;
626
-
627
- case QUADBEZIERTO:
628
- quadBezierUniformStep();
629
- result = curvePoints;
630
- curvePoints = null;
631
- break;
632
-
633
- case CUBICBEZIERTO:
634
- cubicBezierUniformStep();
635
- result = curvePoints;
636
- curvePoints = null;
637
- break;
638
- }
639
- break;
640
- }
940
+ case QUADBEZIERTO:
941
+ return splitQuadBezier(t);
641
942
 
642
- if (resetSegmentator) {
643
- restoreSegmentatorContext();
644
- }
943
+ case CUBICBEZIERTO:
944
+ return splitCubicBezier(t);
645
945
 
646
- return result;
647
946
  }
947
+ return null;
948
+ }
648
949
 
649
- /**
650
- * Use this to return a specific point on the curve. It returns the RPoint
651
- * for a given advancement parameter t on the curve.
652
- *
653
- * @eexample getPoint
654
- * @param t float, the parameter of advancement on the curve. t must have
655
- * values between 0 and 1.
656
- * @return RPoint, the vertice returned.
950
+ /**
951
+ * Taken from: http://steve.hollasch.net/cgindex/curves/cbezarclen.html
657
952
  *
658
- */
659
- @Override
660
- public RPoint getPoint(float t) {
661
- /* limit the value of t between 0 and 1 */
662
- t = (t > 1F) ? 1F : t;
663
- t = (t < 0F) ? 0F : t;
664
- float ax, bx, cx;
665
- float ay, by, cy;
666
- float tSquared, tDoubled, tCubed;
667
- float dx, dy;
668
-
669
- switch (commandType) {
670
- case LINETO:
671
- dx = endPoint.x - startPoint.x;
672
- dy = endPoint.y - startPoint.y;
673
- return new RPoint(startPoint.x + dx * t, startPoint.y + dy * t);
674
-
675
- case QUADBEZIERTO:
676
- /* calculate the polynomial coefficients */
677
- bx = controlPoints[0].x - startPoint.x;
678
- ax = endPoint.x - controlPoints[0].x - bx;
679
- by = controlPoints[0].y - startPoint.y;
680
- ay = endPoint.y - controlPoints[0].y - by;
681
-
682
- /* calculate the curve point at parameter value t */
683
- tSquared = t * t;
684
- tDoubled = 2F * t;
685
- return new RPoint((ax * tSquared) + (bx * tDoubled) + startPoint.x, (ay * tSquared) + (by * tDoubled) + startPoint.y);
686
-
687
- case CUBICBEZIERTO:
688
- /* calculate the polynomial coefficients */
689
- cx = 3F * (controlPoints[0].x - startPoint.x);
690
- bx = 3F * (controlPoints[1].x - controlPoints[0].x) - cx;
691
- ax = endPoint.x - startPoint.x - cx - bx;
692
- cy = 3F * (controlPoints[0].y - startPoint.y);
693
- by = 3F * (controlPoints[1].y - controlPoints[0].y) - cy;
694
- ay = endPoint.y - startPoint.y - cy - by;
695
-
696
- /* calculate the curve point at parameter value t */
697
- tSquared = t * t;
698
- tCubed = tSquared * t;
699
- return new RPoint((ax * tCubed) + (bx * tSquared) + (cx * t) + startPoint.x, (ay * tCubed) + (by * tSquared) + (cy * t) + startPoint.y);
700
- }
701
-
702
- return new RPoint();
703
- }
704
-
705
- /**
706
- * Use this to return the tangents on the curve. It returns the vectors in
707
- * the form of an array of RPoint.
708
- *
709
- * @eexample getTangents
710
- * @param segments int, the number of segments in which to divide the curve.
711
- * @return RPoint[], the tangent vectors returned in an array.
953
+ * who took it from: Schneider's Bezier curve-fitter
712
954
  *
713
- */
714
- public RPoint[] getTangents(int segments) {
715
- RPoint[] result;
716
- float dt, t;
717
- switch (commandType) {
718
- case LINETO:
719
- result = new RPoint[2];
720
- result[0] = startPoint;
721
- result[1] = endPoint;
722
- return result;
723
- case QUADBEZIERTO:
724
- case CUBICBEZIERTO:
725
- result = new RPoint[segments];
726
- dt = 1F / segments;
727
- t = 0F;
728
- for (int i = 0; i < segments; i++) {
729
- result[i] = getTangent(t);
730
- t += dt;
731
- }
732
- return result;
733
- }
734
- return null;
955
+ */
956
+ private RCommand[] splitCubicBezier(float t) {
957
+ RPoint[][] triangleMatrix = new RPoint[4][4];
958
+ for (int i = 0; i <= 3; i++) {
959
+ for (int j = 0; j <= 3; j++) {
960
+ triangleMatrix[i][j] = new RPoint();
961
+ }
735
962
  }
736
963
 
737
- @Override
738
- public RPoint[] getTangents() {
964
+ RPoint[] ctrlPoints = this.getHandles();
739
965
 
740
- return getTangents(100);
966
+ // Copy control points to triangle matrix
967
+ for (int i = 0; i <= 3; i++) {
968
+ triangleMatrix[0][i].x = ctrlPoints[i].x;
969
+ triangleMatrix[0][i].y = ctrlPoints[i].y;
741
970
  }
742
971
 
743
- /**
744
- * Use this to return a specific tangent on the curve. It returns the RPoint
745
- * representing the tangent vector for a given value of the advancement
746
- * parameter t on the curve.
747
- *
748
- * @eexample getTangent
749
- * @param t float, the parameter of advancement on the curve. t must have
750
- * values between 0 and 1.
751
- * @return RPoint, the vertice returned.
752
- *
753
- */
754
- @Override
755
- public RPoint getTangent(float t) {
756
- /* limit the value of t between 0 and 1 */
757
- t = (t > 1F) ? 1F : t;
758
- t = (t < 0F) ? 0F : t;
759
-
760
- float dx, dy, tx, ty, t2, t_1, t_12;
761
-
762
- switch (commandType) {
763
- case LINETO:
764
- dx = endPoint.x - startPoint.x;
765
- dy = endPoint.y - startPoint.y;
766
- return new RPoint(dx, dy);
767
-
768
- case QUADBEZIERTO:
769
- /* calculate the curve point at parameter value t */
770
- tx = 2F * ((startPoint.x - 2 * controlPoints[0].x + endPoint.x) * t + (controlPoints[0].x - startPoint.x));
771
- ty = 2F * ((startPoint.y - 2 * controlPoints[0].y + endPoint.y) * t + (controlPoints[0].y - startPoint.y));
772
- //float norm = (float)Math.sqrt(tx*tx + ty*ty);
773
- //return new RPoint(tx/norm,ty/norm);
774
- return new RPoint(tx, ty);
775
-
776
- case CUBICBEZIERTO:
777
- /* calculate the curve point at parameter value t */
778
- t2 = t * t;
779
- t_1 = 1 - t;
780
- t_12 = t_1 * t_1;
781
-
782
- return new RPoint(-3F * t_12 * startPoint.x + 3F * (3F * t2 - 4F * t + 1F) * controlPoints[0].x + 3F * t * (2F - 3F * t) * controlPoints[1].x + 3F * t2 * endPoint.x, -3F * t_12 * startPoint.y + 3F * (3F * t2 - 4F * t + 1F) * controlPoints[0].y + 3F * t * (2F - 3F * t) * controlPoints[1].y + 3F * t2 * endPoint.y);
783
- }
784
-
785
- return new RPoint();
972
+ // Triangle computation
973
+ for (int i = 1; i <= 3; i++) {
974
+ for (int j = 0; j <= 3 - i; j++) {
975
+ triangleMatrix[i][j].x = (1 - t) * triangleMatrix[i - 1][j].x + t * triangleMatrix[i - 1][j + 1].x;
976
+ triangleMatrix[i][j].y = (1 - t) * triangleMatrix[i - 1][j].y + t * triangleMatrix[i - 1][j + 1].y;
977
+ }
786
978
  }
787
979
 
788
- /**
789
- * Use this to return arc length of a curve. It returns the float
790
- * representing the length given the value of the advancement parameter t on
791
- * the curve. The current implementation of this function is very slow, not
792
- * recommended for using during frame draw.
793
- *
794
- * @eexample RCommand_getCurveLength
795
- * @param t float, the parameter of advancement on the curve. t must have
796
- * values between 0 and 1.
797
- * @return float, the length returned.
798
- * @invisible
799
- *
800
- */
801
- public float getCurveLength(float t) {
802
-
803
- /* limit the value of t between 0 and 1 */
804
- t = (t > 1F) ? 1F : t;
805
- t = (t < 0F) ? 0F : t;
806
-
807
- float dx, dy, dx2, dy2, t2;
808
-
809
- switch (commandType) {
810
- case LINETO:
811
- dx = endPoint.x - startPoint.x;
812
- dy = endPoint.y - startPoint.y;
813
- dx2 = dx * dx;
814
- dy2 = dy * dy;
815
- t2 = t * t;
816
- //RG.parent().println("RCommand/LINETO::: getCurveLength: " + (float)Math.sqrt(dx2*t2 + dy2*t2));
817
- return (float) Math.sqrt(dx2 * t2 + dy2 * t2);
818
-
819
- case QUADBEZIERTO:
820
- /* calculate the curve point at parameter value t */
821
- return quadBezierLength();
822
-
823
- case CUBICBEZIERTO:
824
- /* calculate the curve point at parameter value t */
825
- return cubicBezierLength();
826
- }
980
+ RCommand[] result = new RCommand[2];
981
+ result[0] = createBezier4(startPoint, triangleMatrix[1][0], triangleMatrix[2][0], triangleMatrix[3][0]);
982
+ result[1] = createBezier4(triangleMatrix[3][0], triangleMatrix[2][1], triangleMatrix[1][2], endPoint);
983
+ return result;
984
+ }
827
985
 
828
- return -1F;
986
+ private RCommand[] splitQuadBezier(float t) {
987
+ RPoint[][] triangleMatrix = new RPoint[3][3];
988
+ for (int i = 0; i <= 2; i++) {
989
+ for (int j = 0; j <= 2; j++) {
990
+ triangleMatrix[i][j] = new RPoint();
991
+ }
829
992
  }
830
993
 
831
- /**
832
- * Use this to return arc length of a curve. It returns the float
833
- * representing the length given the value of the advancement parameter t on
834
- * the curve. The current implementation of this function is very slow, not
835
- * recommended for using during frame draw.
836
- *
837
- * @eexample RCommand_getCurveLength
838
- * @return float, the length returned.
839
- * @invisible
840
- *
841
- */
842
- @Override
843
- public float getCurveLength() {
844
- return getCurveLength(1F);
845
- }
994
+ RPoint[] ctrlPoints = this.getHandles();
846
995
 
847
- @Override
848
- public RPoint[][] getPointsInPaths() {
849
- PApplet.println("Feature not yet implemented for this class.");
850
- return null;
996
+ // Copy control points to triangle matrix
997
+ for (int i = 0; i <= 2; i++) {
998
+ triangleMatrix[0][i] = ctrlPoints[i];
851
999
  }
852
1000
 
853
- @Override
854
- public RPoint[][] getHandlesInPaths() {
855
- PApplet.println("Feature not yet implemented for this class.");
856
- return null;
1001
+ // Triangle computation
1002
+ for (int i = 1; i <= 2; i++) {
1003
+ for (int j = 0; j <= 2 - i; j++) {
1004
+ triangleMatrix[i][j].x = (1 - t) * triangleMatrix[i - 1][j].x + t * triangleMatrix[i - 1][j + 1].x;
1005
+ triangleMatrix[i][j].y = (1 - t) * triangleMatrix[i - 1][j].y + t * triangleMatrix[i - 1][j + 1].y;
1006
+ }
857
1007
  }
858
1008
 
859
- @Override
860
- public RPoint[][] getTangentsInPaths() {
861
- PApplet.println("Feature not yet implemented for this class.");
862
- return null;
863
- }
1009
+ RCommand[] result = new RCommand[2];
1010
+ result[0] = createBezier3(startPoint, triangleMatrix[1][0], triangleMatrix[2][0]);
1011
+ result[1] = createBezier3(triangleMatrix[2][0], triangleMatrix[1][1], endPoint);
1012
+ return result;
1013
+ }
864
1014
 
865
- @Override
866
- public boolean contains(RPoint p) {
867
- PApplet.println("Feature not yet implemented for this class.");
868
- return false;
1015
+ private RCommand[] splitLine(float t) {
1016
+ RPoint[][] triangleMatrix = new RPoint[2][2];
1017
+ for (int i = 0; i <= 1; i++) {
1018
+ for (int j = 0; j <= 1; j++) {
1019
+ triangleMatrix[i][j] = new RPoint();
1020
+ }
869
1021
  }
870
1022
 
871
- /**
872
- * Use this method to draw the command.
873
- *
874
- * @eexample drawCommand
875
- * @param g PGraphics, the graphics object on which to draw the command
876
- */
877
- @Override
878
- public void draw(PGraphics g) {
879
- RPoint[] points = getPoints();
880
- if (points == null) {
881
- return;
882
- }
883
- g.beginShape();
884
- for (RPoint point : points) {
885
- g.vertex(point.x, point.y);
886
- }
887
- g.endShape();
888
- }
1023
+ RPoint[] ctrlPoints = this.getHandles();
889
1024
 
890
- /**
891
- * Use this method to draw the command.
892
- *
893
- * @eexample drawCommand
894
- * @param a the applet object on which to draw the command
895
- */
896
- @Override
897
- public void draw(PApplet a) {
898
- RPoint[] points = getPoints();
899
- if (points == null) {
900
- return;
901
- }
902
-
903
- a.beginShape();
904
- for (RPoint point : points) {
905
- a.vertex(point.x, point.y);
906
- }
907
- a.endShape();
1025
+ // Copy control points to triangle matrix
1026
+ for (int i = 0; i <= 1; i++) {
1027
+ triangleMatrix[0][i] = ctrlPoints[i];
908
1028
  }
909
1029
 
910
- /**
911
- * Use this to return the start, control and end points of the curve. It
912
- * returns the points in the way of an array of RPoint.
913
- *
914
- * @eexample getHandles
915
- * @return RPoint[], the vertices returned in an array.
916
- *
917
- */
918
- @Override
919
- public RPoint[] getHandles() {
920
- RPoint[] result;
921
- if (controlPoints == null) {
922
- result = new RPoint[2];
923
- result[0] = startPoint;
924
- result[1] = endPoint;
925
- } else {
926
- result = new RPoint[controlPoints.length + 2];
927
- result[0] = startPoint;
928
- System.arraycopy(controlPoints, 0, result, 1, controlPoints.length);
929
- result[result.length - 1] = endPoint;
930
- }
931
- return result;
1030
+ // Triangle computation
1031
+ for (int i = 1; i <= 1; i++) {
1032
+ for (int j = 0; j <= 1 - i; j++) {
1033
+ triangleMatrix[i][j].x = (1 - t) * triangleMatrix[i - 1][j].x + t * triangleMatrix[i - 1][j + 1].x;
1034
+ triangleMatrix[i][j].y = (1 - t) * triangleMatrix[i - 1][j].y + t * triangleMatrix[i - 1][j + 1].y;
1035
+ }
932
1036
  }
933
1037
 
934
- /**
935
- * Returns two commands resulting of splitting the command.
936
- *
937
- * @eexample split
938
- * @param t the advancement on the curve where command should be split.
939
- * @return RPoint[], the tangent vectors returned in an array.
940
- *
941
- */
942
- public RCommand[] split(float t) {
943
-
944
- switch (commandType) {
945
- case LINETO:
946
- return splitLine(t);
1038
+ RCommand[] result = new RCommand[2];
1039
+ result[0] = createLine(startPoint, triangleMatrix[1][0]);
1040
+ result[1] = createLine(triangleMatrix[1][0], endPoint);
1041
+ return result;
1042
+ }
947
1043
 
948
- case QUADBEZIERTO:
949
- return splitQuadBezier(t);
1044
+ private void quadBezierAdaptative() {
1045
+ addCurvePoint(new RPoint(startPoint));
1046
+ quadBezierAdaptativeRecursive(startPoint.x, startPoint.y, controlPoints[0].x, controlPoints[0].y, endPoint.x, endPoint.y, 0);
1047
+ addCurvePoint(new RPoint(endPoint));
1048
+ }
950
1049
 
951
- case CUBICBEZIERTO:
952
- return splitCubicBezier(t);
1050
+ private void quadBezierAdaptativeRecursive(float x1, float y1, float x2, float y2, float x3, float y3, int level) {
953
1051
 
954
- }
955
- return null;
1052
+ if (level > SEGMENT_RECURSION_LIMIT) {
1053
+ return;
956
1054
  }
957
1055
 
958
- /**
959
- * Taken from: http://steve.hollasch.net/cgindex/curves/cbezarclen.html
960
- *
961
- * who took it from: Schneider's Bezier curve-fitter
962
- *
963
- */
964
- private RCommand[] splitCubicBezier(float t) {
965
- RPoint[][] triangleMatrix = new RPoint[4][4];
966
- for (int i = 0; i <= 3; i++) {
967
- for (int j = 0; j <= 3; j++) {
968
- triangleMatrix[i][j] = new RPoint();
969
- }
1056
+ // Calculate all the mid-points of the line segments
1057
+ //----------------------
1058
+ float x12 = (x1 + x2) / 2;
1059
+ float y12 = (y1 + y2) / 2;
1060
+ float x23 = (x2 + x3) / 2;
1061
+ float y23 = (y2 + y3) / 2;
1062
+ float x123 = (x12 + x23) / 2;
1063
+ float y123 = (y12 + y23) / 2;
1064
+
1065
+ float dx = x3 - x1;
1066
+ float dy = y3 - y1;
1067
+ float d = Math.abs(((x2 - x3) * dy - (y2 - y3) * dx));
1068
+
1069
+ if (d > SEGMENT_COLLINEARITY_EPSILON) {
1070
+ // Regular care
1071
+ //-----------------
1072
+ if (d * d <= segmentDistTolSqr * (dx * dx + dy * dy)) {
1073
+ // If the curvature doesn't exceed the distance_tolerance value
1074
+ // we tend to finish subdivisions.
1075
+ //----------------------
1076
+ if (segmentAngleTol < SEGMENT_ANGLE_TOL_EPSILON) {
1077
+ addCurvePoint(new RPoint(x123, y123));
1078
+ return;
970
1079
  }
971
1080
 
972
- RPoint[] ctrlPoints = this.getHandles();
973
-
974
- // Copy control points to triangle matrix
975
- for (int i = 0; i <= 3; i++) {
976
- triangleMatrix[0][i].x = ctrlPoints[i].x;
977
- triangleMatrix[0][i].y = ctrlPoints[i].y;
1081
+ // Angle & Cusp Condition
1082
+ //----------------------
1083
+ float da = Math.abs((float) Math.atan2(y3 - y2, x3 - x2) - (float) Math.atan2(y2 - y1, x2 - x1));
1084
+ if (da >= Math.PI) {
1085
+ da = 2 * (float) Math.PI - da;
978
1086
  }
979
1087
 
980
- // Triangle computation
981
- for (int i = 1; i <= 3; i++) {
982
- for (int j = 0; j <= 3 - i; j++) {
983
- triangleMatrix[i][j].x = (1 - t) * triangleMatrix[i - 1][j].x + t * triangleMatrix[i - 1][j + 1].x;
984
- triangleMatrix[i][j].y = (1 - t) * triangleMatrix[i - 1][j].y + t * triangleMatrix[i - 1][j + 1].y;
985
- }
1088
+ if (da < segmentAngleTol) {
1089
+ // Finally we can stop the recursion
1090
+ //----------------------
1091
+ addCurvePoint(new RPoint(x123, y123));
1092
+ return;
986
1093
  }
987
-
988
- RCommand[] result = new RCommand[2];
989
- result[0] = createBezier4(startPoint, triangleMatrix[1][0], triangleMatrix[2][0], triangleMatrix[3][0]);
990
- result[1] = createBezier4(triangleMatrix[3][0], triangleMatrix[2][1], triangleMatrix[1][2], endPoint);
991
- return result;
1094
+ }
1095
+ } else {
1096
+ if (Math.abs(x1 + x3 - x2 - x2) + Math.abs(y1 + y3 - y2 - y2) <= segmentDistTolMnhttn) {
1097
+ addCurvePoint(new RPoint(x123, y123));
1098
+ return;
1099
+ }
992
1100
  }
993
1101
 
994
- private RCommand[] splitQuadBezier(float t) {
995
- RPoint[][] triangleMatrix = new RPoint[3][3];
996
- for (int i = 0; i <= 2; i++) {
997
- for (int j = 0; j <= 2; j++) {
998
- triangleMatrix[i][j] = new RPoint();
999
- }
1000
- }
1102
+ // Continue subdivision
1103
+ //----------------------
1104
+ quadBezierAdaptativeRecursive(x1, y1, x12, y12, x123, y123, level + 1);
1105
+ quadBezierAdaptativeRecursive(x123, y123, x23, y23, x3, y3, level + 1);
1106
+ }
1001
1107
 
1002
- RPoint[] ctrlPoints = this.getHandles();
1108
+ private void cubicBezierAdaptative() {
1109
+ addCurvePoint(new RPoint(startPoint));
1110
+ cubicBezierAdaptativeRecursive(startPoint.x, startPoint.y, controlPoints[0].x, controlPoints[0].y, controlPoints[1].x, controlPoints[1].y, endPoint.x, endPoint.y, 0);
1111
+ addCurvePoint(new RPoint(endPoint));
1112
+ }
1003
1113
 
1004
- // Copy control points to triangle matrix
1005
- for (int i = 0; i <= 2; i++) {
1006
- triangleMatrix[0][i] = ctrlPoints[i];
1007
- }
1114
+ private void cubicBezierAdaptativeRecursive(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, int level) {
1115
+ if (level > SEGMENT_RECURSION_LIMIT) {
1116
+ return;
1117
+ }
1008
1118
 
1009
- // Triangle computation
1010
- for (int i = 1; i <= 2; i++) {
1011
- for (int j = 0; j <= 2 - i; j++) {
1012
- triangleMatrix[i][j].x = (1 - t) * triangleMatrix[i - 1][j].x + t * triangleMatrix[i - 1][j + 1].x;
1013
- triangleMatrix[i][j].y = (1 - t) * triangleMatrix[i - 1][j].y + t * triangleMatrix[i - 1][j + 1].y;
1014
- }
1119
+ // Calculate all the mid-points of the line segments
1120
+ //----------------------
1121
+ float x12 = (x1 + x2) / 2;
1122
+ float y12 = (y1 + y2) / 2;
1123
+ float x23 = (x2 + x3) / 2;
1124
+ float y23 = (y2 + y3) / 2;
1125
+ float x34 = (x3 + x4) / 2;
1126
+ float y34 = (y3 + y4) / 2;
1127
+ float x123 = (x12 + x23) / 2;
1128
+ float y123 = (y12 + y23) / 2;
1129
+ float x234 = (x23 + x34) / 2;
1130
+ float y234 = (y23 + y34) / 2;
1131
+ float x1234 = (x123 + x234) / 2;
1132
+ float y1234 = (y123 + y234) / 2;
1133
+
1134
+ // Try to approximate the full cubic curve by a single straight line
1135
+ //------------------
1136
+ float dx = x4 - x1;
1137
+ float dy = y4 - y1;
1138
+
1139
+ float d2 = Math.abs(((x2 - x4) * dy - (y2 - y4) * dx));
1140
+ float d3 = Math.abs(((x3 - x4) * dy - (y3 - y4) * dx));
1141
+ float da1, da2;
1142
+
1143
+ int d2b = (d2 > SEGMENT_COLLINEARITY_EPSILON) ? 1 : 0;
1144
+ int d3b = (d3 > SEGMENT_COLLINEARITY_EPSILON) ? 1 : 0;
1145
+ switch ((d2b << 1) + d3b) {
1146
+ case 0:
1147
+ // All collinear OR p1==p4
1148
+ //----------------------
1149
+ if (Math.abs(x1 + x3 - x2 - x2)
1150
+ + Math.abs(y1 + y3 - y2 - y2)
1151
+ + Math.abs(x2 + x4 - x3 - x3)
1152
+ + Math.abs(y2 + y4 - y3 - y3) <= segmentDistTolMnhttn) {
1153
+ addCurvePoint(new RPoint(x1234, y1234));
1154
+ return;
1015
1155
  }
1156
+ break;
1016
1157
 
1017
- RCommand[] result = new RCommand[2];
1018
- result[0] = createBezier3(startPoint, triangleMatrix[1][0], triangleMatrix[2][0]);
1019
- result[1] = createBezier3(triangleMatrix[2][0], triangleMatrix[1][1], endPoint);
1020
- return result;
1021
- }
1158
+ case 1:
1159
+ // p1,p2,p4 are collinear, p3 is considerable
1160
+ //----------------------
1161
+ if (d3 * d3 <= segmentDistTolSqr * (dx * dx + dy * dy)) {
1162
+ if (segmentAngleTol < SEGMENT_ANGLE_TOL_EPSILON) {
1163
+ addCurvePoint(new RPoint(x23, y23));
1164
+ return;
1165
+ }
1166
+
1167
+ // Angle Condition
1168
+ //----------------------
1169
+ da1 = Math.abs((float) Math.atan2(y4 - y3, x4 - x3) - (float) Math.atan2(y3 - y2, x3 - x2));
1170
+ if (da1 >= (float) Math.PI) {
1171
+ da1 = 2 * (float) Math.PI - da1;
1172
+ }
1173
+
1174
+ if (da1 < segmentAngleTol) {
1175
+ addCurvePoint(new RPoint(x2, y2));
1176
+ addCurvePoint(new RPoint(x3, y3));
1177
+ return;
1178
+ }
1022
1179
 
1023
- private RCommand[] splitLine(float t) {
1024
- RPoint[][] triangleMatrix = new RPoint[2][2];
1025
- for (int i = 0; i <= 1; i++) {
1026
- for (int j = 0; j <= 1; j++) {
1027
- triangleMatrix[i][j] = new RPoint();
1180
+ if (segmentCuspLimit != 0.0) {
1181
+ if (da1 > segmentCuspLimit) {
1182
+ addCurvePoint(new RPoint(x3, y3));
1183
+ return;
1028
1184
  }
1185
+ }
1029
1186
  }
1187
+ break;
1030
1188
 
1031
- RPoint[] ctrlPoints = this.getHandles();
1189
+ case 2:
1190
+ // p1,p3,p4 are collinear, p2 is considerable
1191
+ //----------------------
1192
+ if (d2 * d2 <= segmentDistTolSqr * (dx * dx + dy * dy)) {
1193
+ if (segmentAngleTol < SEGMENT_ANGLE_TOL_EPSILON) {
1194
+ addCurvePoint(new RPoint(x23, y23));
1195
+ return;
1196
+ }
1032
1197
 
1033
- // Copy control points to triangle matrix
1034
- for (int i = 0; i <= 1; i++) {
1035
- triangleMatrix[0][i] = ctrlPoints[i];
1036
- }
1198
+ // Angle Condition
1199
+ //----------------------
1200
+ da1 = Math.abs((float) Math.atan2(y3 - y2, x3 - x2) - (float) Math.atan2(y2 - y1, x2 - x1));
1201
+ if (da1 >= (float) Math.PI) {
1202
+ da1 = 2 * (float) Math.PI - da1;
1203
+ }
1204
+
1205
+ if (da1 < segmentAngleTol) {
1206
+ addCurvePoint(new RPoint(x2, y2));
1207
+ addCurvePoint(new RPoint(x3, y3));
1208
+ return;
1209
+ }
1037
1210
 
1038
- // Triangle computation
1039
- for (int i = 1; i <= 1; i++) {
1040
- for (int j = 0; j <= 1 - i; j++) {
1041
- triangleMatrix[i][j].x = (1 - t) * triangleMatrix[i - 1][j].x + t * triangleMatrix[i - 1][j + 1].x;
1042
- triangleMatrix[i][j].y = (1 - t) * triangleMatrix[i - 1][j].y + t * triangleMatrix[i - 1][j + 1].y;
1211
+ if (segmentCuspLimit != 0.0) {
1212
+ if (da1 > segmentCuspLimit) {
1213
+ addCurvePoint(new RPoint(x2, y2));
1214
+ return;
1043
1215
  }
1216
+ }
1044
1217
  }
1218
+ break;
1045
1219
 
1046
- RCommand[] result = new RCommand[2];
1047
- result[0] = createLine(startPoint, triangleMatrix[1][0]);
1048
- result[1] = createLine(triangleMatrix[1][0], endPoint);
1049
- return result;
1050
- }
1051
-
1052
- private void quadBezierAdaptative() {
1053
- addCurvePoint(new RPoint(startPoint));
1054
- quadBezierAdaptativeRecursive(startPoint.x, startPoint.y, controlPoints[0].x, controlPoints[0].y, endPoint.x, endPoint.y, 0);
1055
- addCurvePoint(new RPoint(endPoint));
1056
- }
1057
-
1058
- private void quadBezierAdaptativeRecursive(float x1, float y1, float x2, float y2, float x3, float y3, int level) {
1220
+ case 3:
1221
+ // Regular care
1222
+ //-----------------
1223
+ if ((d2 + d3) * (d2 + d3) <= segmentDistTolSqr * (dx * dx + dy * dy)) {
1224
+ // If the curvature doesn't exceed the distance_tolerance value
1225
+ // we tend to finish subdivisions.
1226
+ //----------------------
1227
+ if (segmentAngleTol < SEGMENT_ANGLE_TOL_EPSILON) {
1228
+ addCurvePoint(new RPoint(x23, y23));
1229
+ return;
1230
+ }
1059
1231
 
1060
- if (level > SEGMENT_RECURSION_LIMIT) {
1232
+ // Angle & Cusp Condition
1233
+ //----------------------
1234
+ float a23 = (float) Math.atan2(y3 - y2, x3 - x2);
1235
+ da1 = Math.abs(a23 - (float) Math.atan2(y2 - y1, x2 - x1));
1236
+ da2 = Math.abs((float) Math.atan2(y4 - y3, x4 - x3) - a23);
1237
+ if (da1 >= (float) Math.PI) {
1238
+ da1 = 2 * (float) Math.PI - da1;
1239
+ }
1240
+ if (da2 >= (float) Math.PI) {
1241
+ da2 = 2 * (float) Math.PI - da2;
1242
+ }
1243
+
1244
+ if (da1 + da2 < segmentAngleTol) {
1245
+ // Finally we can stop the recursion
1246
+ //----------------------
1247
+ addCurvePoint(new RPoint(x23, y23));
1061
1248
  return;
1062
- }
1249
+ }
1063
1250
 
1064
- // Calculate all the mid-points of the line segments
1065
- //----------------------
1066
- float x12 = (x1 + x2) / 2;
1067
- float y12 = (y1 + y2) / 2;
1068
- float x23 = (x2 + x3) / 2;
1069
- float y23 = (y2 + y3) / 2;
1070
- float x123 = (x12 + x23) / 2;
1071
- float y123 = (y12 + y23) / 2;
1072
-
1073
- float dx = x3 - x1;
1074
- float dy = y3 - y1;
1075
- float d = Math.abs(((x2 - x3) * dy - (y2 - y3) * dx));
1076
-
1077
- if (d > SEGMENT_COLLINEARITY_EPSILON) {
1078
- // Regular care
1079
- //-----------------
1080
- if (d * d <= segmentDistTolSqr * (dx * dx + dy * dy)) {
1081
- // If the curvature doesn't exceed the distance_tolerance value
1082
- // we tend to finish subdivisions.
1083
- //----------------------
1084
- if (segmentAngleTol < SEGMENT_ANGLE_TOL_EPSILON) {
1085
- addCurvePoint(new RPoint(x123, y123));
1086
- return;
1087
- }
1088
-
1089
- // Angle & Cusp Condition
1090
- //----------------------
1091
- float da = Math.abs((float) Math.atan2(y3 - y2, x3 - x2) - (float) Math.atan2(y2 - y1, x2 - x1));
1092
- if (da >= Math.PI) {
1093
- da = 2 * (float) Math.PI - da;
1094
- }
1095
-
1096
- if (da < segmentAngleTol) {
1097
- // Finally we can stop the recursion
1098
- //----------------------
1099
- addCurvePoint(new RPoint(x123, y123));
1100
- return;
1101
- }
1251
+ if (segmentCuspLimit != 0.0) {
1252
+ if (da1 > segmentCuspLimit) {
1253
+ addCurvePoint(new RPoint(x2, y2));
1254
+ return;
1102
1255
  }
1103
- } else {
1104
- if (Math.abs(x1 + x3 - x2 - x2) + Math.abs(y1 + y3 - y2 - y2) <= segmentDistTolMnhttn) {
1105
- addCurvePoint(new RPoint(x123, y123));
1106
- return;
1256
+
1257
+ if (da2 > segmentCuspLimit) {
1258
+ addCurvePoint(new RPoint(x3, y3));
1259
+ return;
1107
1260
  }
1261
+ }
1108
1262
  }
1109
-
1110
- // Continue subdivision
1111
- //----------------------
1112
- quadBezierAdaptativeRecursive(x1, y1, x12, y12, x123, y123, level + 1);
1113
- quadBezierAdaptativeRecursive(x123, y123, x23, y23, x3, y3, level + 1);
1263
+ break;
1114
1264
  }
1115
1265
 
1116
- private void cubicBezierAdaptative() {
1117
- addCurvePoint(new RPoint(startPoint));
1118
- cubicBezierAdaptativeRecursive(startPoint.x, startPoint.y, controlPoints[0].x, controlPoints[0].y, controlPoints[1].x, controlPoints[1].y, endPoint.x, endPoint.y, 0);
1119
- addCurvePoint(new RPoint(endPoint));
1120
- }
1121
-
1122
- private void cubicBezierAdaptativeRecursive(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, int level) {
1123
- if (level > SEGMENT_RECURSION_LIMIT) {
1124
- return;
1125
- }
1126
-
1127
- // Calculate all the mid-points of the line segments
1128
- //----------------------
1129
- float x12 = (x1 + x2) / 2;
1130
- float y12 = (y1 + y2) / 2;
1131
- float x23 = (x2 + x3) / 2;
1132
- float y23 = (y2 + y3) / 2;
1133
- float x34 = (x3 + x4) / 2;
1134
- float y34 = (y3 + y4) / 2;
1135
- float x123 = (x12 + x23) / 2;
1136
- float y123 = (y12 + y23) / 2;
1137
- float x234 = (x23 + x34) / 2;
1138
- float y234 = (y23 + y34) / 2;
1139
- float x1234 = (x123 + x234) / 2;
1140
- float y1234 = (y123 + y234) / 2;
1266
+ // Continue subdivision
1267
+ //----------------------
1268
+ cubicBezierAdaptativeRecursive(x1, y1, x12, y12, x123, y123, x1234, y1234, level + 1);
1269
+ cubicBezierAdaptativeRecursive(x1234, y1234, x234, y234, x34, y34, x4, y4, level + 1);
1270
+ }
1141
1271
 
1142
- // Try to approximate the full cubic curve by a single straight line
1143
- //------------------
1144
- float dx = x4 - x1;
1145
- float dy = y4 - y1;
1146
-
1147
- float d2 = Math.abs(((x2 - x4) * dy - (y2 - y4) * dx));
1148
- float d3 = Math.abs(((x3 - x4) * dy - (y3 - y4) * dx));
1149
- float da1, da2;
1150
-
1151
- int d2b = (d2 > SEGMENT_COLLINEARITY_EPSILON) ? 1 : 0;
1152
- int d3b = (d3 > SEGMENT_COLLINEARITY_EPSILON) ? 1 : 0;
1153
- switch ((d2b << 1) + d3b) {
1154
- case 0:
1155
- // All collinear OR p1==p4
1156
- //----------------------
1157
- if (Math.abs(x1 + x3 - x2 - x2)
1158
- + Math.abs(y1 + y3 - y2 - y2)
1159
- + Math.abs(x2 + x4 - x3 - x3)
1160
- + Math.abs(y2 + y4 - y3 - y3) <= segmentDistTolMnhttn) {
1161
- addCurvePoint(new RPoint(x1234, y1234));
1162
- return;
1163
- }
1164
- break;
1165
-
1166
- case 1:
1167
- // p1,p2,p4 are collinear, p3 is considerable
1168
- //----------------------
1169
- if (d3 * d3 <= segmentDistTolSqr * (dx * dx + dy * dy)) {
1170
- if (segmentAngleTol < SEGMENT_ANGLE_TOL_EPSILON) {
1171
- addCurvePoint(new RPoint(x23, y23));
1172
- return;
1173
- }
1272
+ private void lineUniformStep() {
1273
+ // If the number of steps is equal to 0 then choose a number of steps adapted to the curve
1274
+ int steps = segmentSteps;
1275
+ if (segmentSteps == 0.0F) {
1276
+ float dx = endPoint.x - startPoint.x;
1277
+ float dy = endPoint.y - startPoint.y;
1174
1278
 
1175
- // Angle Condition
1176
- //----------------------
1177
- da1 = Math.abs((float) Math.atan2(y4 - y3, x4 - x3) - (float) Math.atan2(y3 - y2, x3 - x2));
1178
- if (da1 >= (float) Math.PI) {
1179
- da1 = 2 * (float) Math.PI - da1;
1180
- }
1181
-
1182
- if (da1 < segmentAngleTol) {
1183
- addCurvePoint(new RPoint(x2, y2));
1184
- addCurvePoint(new RPoint(x3, y3));
1185
- return;
1186
- }
1187
-
1188
- if (segmentCuspLimit != 0.0) {
1189
- if (da1 > segmentCuspLimit) {
1190
- addCurvePoint(new RPoint(x3, y3));
1191
- return;
1192
- }
1193
- }
1194
- }
1195
- break;
1196
-
1197
- case 2:
1198
- // p1,p3,p4 are collinear, p2 is considerable
1199
- //----------------------
1200
- if (d2 * d2 <= segmentDistTolSqr * (dx * dx + dy * dy)) {
1201
- if (segmentAngleTol < SEGMENT_ANGLE_TOL_EPSILON) {
1202
- addCurvePoint(new RPoint(x23, y23));
1203
- return;
1204
- }
1279
+ float len = (float) Math.sqrt(dx * dx + dy * dy);
1280
+ steps = (int) (len * 0.25);
1205
1281
 
1206
- // Angle Condition
1207
- //----------------------
1208
- da1 = Math.abs((float) Math.atan2(y3 - y2, x3 - x2) - (float) Math.atan2(y2 - y1, x2 - x1));
1209
- if (da1 >= (float) Math.PI) {
1210
- da1 = 2 * (float) Math.PI - da1;
1211
- }
1212
-
1213
- if (da1 < segmentAngleTol) {
1214
- addCurvePoint(new RPoint(x2, y2));
1215
- addCurvePoint(new RPoint(x3, y3));
1216
- return;
1217
- }
1218
-
1219
- if (segmentCuspLimit != 0.0) {
1220
- if (da1 > segmentCuspLimit) {
1221
- addCurvePoint(new RPoint(x2, y2));
1222
- return;
1223
- }
1224
- }
1225
- }
1226
- break;
1227
-
1228
- case 3:
1229
- // Regular care
1230
- //-----------------
1231
- if ((d2 + d3) * (d2 + d3) <= segmentDistTolSqr * (dx * dx + dy * dy)) {
1232
- // If the curvature doesn't exceed the distance_tolerance value
1233
- // we tend to finish subdivisions.
1234
- //----------------------
1235
- if (segmentAngleTol < SEGMENT_ANGLE_TOL_EPSILON) {
1236
- addCurvePoint(new RPoint(x23, y23));
1237
- return;
1238
- }
1282
+ if (steps < 4) {
1283
+ steps = 4;
1284
+ }
1285
+ }
1239
1286
 
1240
- // Angle & Cusp Condition
1241
- //----------------------
1242
- float a23 = (float) Math.atan2(y3 - y2, x3 - x2);
1243
- da1 = Math.abs(a23 - (float) Math.atan2(y2 - y1, x2 - x1));
1244
- da2 = Math.abs((float) Math.atan2(y4 - y3, x4 - x3) - a23);
1245
- if (da1 >= (float) Math.PI) {
1246
- da1 = 2 * (float) Math.PI - da1;
1247
- }
1248
- if (da2 >= (float) Math.PI) {
1249
- da2 = 2 * (float) Math.PI - da2;
1250
- }
1251
-
1252
- if (da1 + da2 < segmentAngleTol) {
1253
- // Finally we can stop the recursion
1254
- //----------------------
1255
- addCurvePoint(new RPoint(x23, y23));
1256
- return;
1257
- }
1258
-
1259
- if (segmentCuspLimit != 0.0) {
1260
- if (da1 > segmentCuspLimit) {
1261
- addCurvePoint(new RPoint(x2, y2));
1262
- return;
1263
- }
1264
-
1265
- if (da2 > segmentCuspLimit) {
1266
- addCurvePoint(new RPoint(x3, y3));
1267
- return;
1268
- }
1269
- }
1270
- }
1271
- break;
1272
- }
1287
+ float dt = 1F / steps;
1273
1288
 
1274
- // Continue subdivision
1275
- //----------------------
1276
- cubicBezierAdaptativeRecursive(x1, y1, x12, y12, x123, y123, x1234, y1234, level + 1);
1277
- cubicBezierAdaptativeRecursive(x1234, y1234, x234, y234, x34, y34, x4, y4, level + 1);
1278
- }
1289
+ float fx, fy, fdx, fdy;
1279
1290
 
1280
- private void lineUniformStep() {
1281
- // If the number of steps is equal to 0 then choose a number of steps adapted to the curve
1282
- int steps = segmentSteps;
1283
- if (segmentSteps == 0.0F) {
1284
- float dx = endPoint.x - startPoint.x;
1285
- float dy = endPoint.y - startPoint.y;
1291
+ fx = startPoint.x;
1292
+ fdx = (endPoint.x - startPoint.x) * dt;
1286
1293
 
1287
- float len = (float) Math.sqrt(dx * dx + dy * dy);
1288
- steps = (int) (len * 0.25);
1294
+ fy = startPoint.y;
1295
+ fdy = (endPoint.y - startPoint.y) * dt;
1289
1296
 
1290
- if (steps < 4) {
1291
- steps = 4;
1292
- }
1293
- }
1297
+ for (int loop = 0; loop < steps; loop++) {
1298
+ addCurvePoint(new RPoint(fx, fy));
1294
1299
 
1295
- float dt = 1F / steps;
1300
+ fx = fx + fdx;
1296
1301
 
1297
- float fx, fy, fdx, fdy;
1302
+ fy = fy + fdy;
1303
+ }
1304
+ addCurvePoint(new RPoint(endPoint));
1305
+ }
1298
1306
 
1299
- fx = startPoint.x;
1300
- fdx = (endPoint.x - startPoint.x) * dt;
1307
+ private void cubicBezierUniformStep() {
1301
1308
 
1302
- fy = startPoint.y;
1303
- fdy = (endPoint.y - startPoint.y) * dt;
1309
+ // If the number of steps is equal to 0 then choose a number of steps adapted to the curve
1310
+ int steps = segmentSteps;
1311
+ if (segmentSteps == 0.0F) {
1312
+ float dx1 = controlPoints[0].x - startPoint.x;
1313
+ float dy1 = controlPoints[0].y - startPoint.y;
1314
+ float dx2 = controlPoints[1].x - controlPoints[0].x;
1315
+ float dy2 = controlPoints[1].y - controlPoints[0].y;
1316
+ float dx3 = endPoint.x - controlPoints[1].x;
1317
+ float dy3 = endPoint.y - controlPoints[1].y;
1304
1318
 
1305
- for (int loop = 0; loop < steps; loop++) {
1306
- addCurvePoint(new RPoint(fx, fy));
1319
+ float len = (float) Math.sqrt(dx1 * dx1 + dy1 * dy1)
1320
+ + (float) Math.sqrt(dx2 * dx2 + dy2 * dy2)
1321
+ + (float) Math.sqrt(dx3 * dx3 + dy3 * dy3);
1307
1322
 
1308
- fx = fx + fdx;
1323
+ steps = (int) (len * 0.25);
1309
1324
 
1310
- fy = fy + fdy;
1311
- }
1312
- addCurvePoint(new RPoint(endPoint));
1325
+ if (steps < 4) {
1326
+ steps = 4;
1327
+ }
1313
1328
  }
1314
1329
 
1315
- private void cubicBezierUniformStep() {
1330
+ float dt = 1F / steps;
1316
1331
 
1317
- // If the number of steps is equal to 0 then choose a number of steps adapted to the curve
1318
- int steps = segmentSteps;
1319
- if (segmentSteps == 0.0F) {
1320
- float dx1 = controlPoints[0].x - startPoint.x;
1321
- float dy1 = controlPoints[0].y - startPoint.y;
1322
- float dx2 = controlPoints[1].x - controlPoints[0].x;
1323
- float dy2 = controlPoints[1].y - controlPoints[0].y;
1324
- float dx3 = endPoint.x - controlPoints[1].x;
1325
- float dy3 = endPoint.y - controlPoints[1].y;
1332
+ float fx, fy, fdx, fdy, fddx, fddy, fdddx, fdddy, fdd_per_2x, fdd_per_2y, fddd_per_2x, fddd_per_2y, fddd_per_6x, fddd_per_6y;
1333
+ float temp = dt * dt;
1326
1334
 
1327
- float len = (float) Math.sqrt(dx1 * dx1 + dy1 * dy1)
1328
- + (float) Math.sqrt(dx2 * dx2 + dy2 * dy2)
1329
- + (float) Math.sqrt(dx3 * dx3 + dy3 * dy3);
1335
+ fx = startPoint.x;
1336
+ fdx = 3F * (controlPoints[0].x - startPoint.x) * dt;
1337
+ fdd_per_2x = 3F * (startPoint.x - 2F * controlPoints[0].x + controlPoints[1].x) * temp;
1338
+ fddd_per_2x = 3F * (3F * (controlPoints[0].x - controlPoints[1].x) + endPoint.x - startPoint.x) * temp * dt;
1339
+ fdddx = fddd_per_2x + fddd_per_2x;
1340
+ fddx = fdd_per_2x + fdd_per_2x;
1341
+ fddd_per_6x = fddd_per_2x * (1.0F / 3F);
1330
1342
 
1331
- steps = (int) (len * 0.25);
1343
+ fy = startPoint.y;
1344
+ fdy = 3F * (controlPoints[0].y - startPoint.y) * dt;
1345
+ fdd_per_2y = 3F * (startPoint.y - 2F * controlPoints[0].y + controlPoints[1].y) * temp;
1346
+ fddd_per_2y = 3F * (3F * (controlPoints[0].y - controlPoints[1].y) + endPoint.y - startPoint.y) * temp * dt;
1347
+ fdddy = fddd_per_2y + fddd_per_2y;
1348
+ fddy = fdd_per_2y + fdd_per_2y;
1349
+ fddd_per_6y = fddd_per_2y * (1.0F / 3F);
1332
1350
 
1333
- if (steps < 4) {
1334
- steps = 4;
1335
- }
1336
- }
1351
+ for (int loop = 0; loop < steps; loop++) {
1352
+ addCurvePoint(new RPoint(fx, fy));
1337
1353
 
1338
- float dt = 1F / steps;
1339
-
1340
- float fx, fy, fdx, fdy, fddx, fddy, fdddx, fdddy, fdd_per_2x, fdd_per_2y, fddd_per_2x, fddd_per_2y, fddd_per_6x, fddd_per_6y;
1341
- float temp = dt * dt;
1342
-
1343
- fx = startPoint.x;
1344
- fdx = 3F * (controlPoints[0].x - startPoint.x) * dt;
1345
- fdd_per_2x = 3F * (startPoint.x - 2F * controlPoints[0].x + controlPoints[1].x) * temp;
1346
- fddd_per_2x = 3F * (3F * (controlPoints[0].x - controlPoints[1].x) + endPoint.x - startPoint.x) * temp * dt;
1347
- fdddx = fddd_per_2x + fddd_per_2x;
1348
- fddx = fdd_per_2x + fdd_per_2x;
1349
- fddd_per_6x = fddd_per_2x * (1.0F / 3F);
1350
-
1351
- fy = startPoint.y;
1352
- fdy = 3F * (controlPoints[0].y - startPoint.y) * dt;
1353
- fdd_per_2y = 3F * (startPoint.y - 2F * controlPoints[0].y + controlPoints[1].y) * temp;
1354
- fddd_per_2y = 3F * (3F * (controlPoints[0].y - controlPoints[1].y) + endPoint.y - startPoint.y) * temp * dt;
1355
- fdddy = fddd_per_2y + fddd_per_2y;
1356
- fddy = fdd_per_2y + fdd_per_2y;
1357
- fddd_per_6y = fddd_per_2y * (1.0F / 3F);
1358
-
1359
- for (int loop = 0; loop < steps; loop++) {
1360
- addCurvePoint(new RPoint(fx, fy));
1361
-
1362
- fx = fx + fdx + fdd_per_2x + fddd_per_6x;
1363
- fdx = fdx + fddx + fddd_per_2x;
1364
- fddx = fddx + fdddx;
1365
- fdd_per_2x = fdd_per_2x + fddd_per_2x;
1366
-
1367
- fy = fy + fdy + fdd_per_2y + fddd_per_6y;
1368
- fdy = fdy + fddy + fddd_per_2y;
1369
- fddy = fddy + fdddy;
1370
- fdd_per_2y = fdd_per_2y + fddd_per_2y;
1371
- }
1372
- addCurvePoint(new RPoint(endPoint));
1354
+ fx = fx + fdx + fdd_per_2x + fddd_per_6x;
1355
+ fdx = fdx + fddx + fddd_per_2x;
1356
+ fddx = fddx + fdddx;
1357
+ fdd_per_2x = fdd_per_2x + fddd_per_2x;
1358
+
1359
+ fy = fy + fdy + fdd_per_2y + fddd_per_6y;
1360
+ fdy = fdy + fddy + fddd_per_2y;
1361
+ fddy = fddy + fdddy;
1362
+ fdd_per_2y = fdd_per_2y + fddd_per_2y;
1373
1363
  }
1364
+ addCurvePoint(new RPoint(endPoint));
1365
+ }
1374
1366
 
1375
- private void quadBezierUniformStep() {
1376
- // If the number of steps is equal to 0 then choose a number of steps adapted to the curve
1377
- int steps = segmentSteps;
1378
- if (segmentSteps == 0.0F) {
1379
- float dx1 = controlPoints[0].x - startPoint.x;
1380
- float dy1 = controlPoints[0].y - startPoint.y;
1381
- float dx2 = endPoint.x - controlPoints[0].x;
1382
- float dy2 = endPoint.y - controlPoints[0].y;
1367
+ private void quadBezierUniformStep() {
1368
+ // If the number of steps is equal to 0 then choose a number of steps adapted to the curve
1369
+ int steps = segmentSteps;
1370
+ if (segmentSteps == 0.0F) {
1371
+ float dx1 = controlPoints[0].x - startPoint.x;
1372
+ float dy1 = controlPoints[0].y - startPoint.y;
1373
+ float dx2 = endPoint.x - controlPoints[0].x;
1374
+ float dy2 = endPoint.y - controlPoints[0].y;
1383
1375
 
1384
- float len = (float) Math.sqrt(dx1 * dx1 + dy1 * dy1) + (float) Math.sqrt(dx2 * dx2 + dy2 * dy2);
1385
- steps = (int) (len * 0.25);
1376
+ float len = (float) Math.sqrt(dx1 * dx1 + dy1 * dy1) + (float) Math.sqrt(dx2 * dx2 + dy2 * dy2);
1377
+ steps = (int) (len * 0.25);
1386
1378
 
1387
- if (steps < 4) {
1388
- steps = 4;
1389
- }
1390
- }
1379
+ if (steps < 4) {
1380
+ steps = 4;
1381
+ }
1382
+ }
1391
1383
 
1392
- float dt = 1F / steps;
1384
+ float dt = 1F / steps;
1393
1385
 
1394
- float fx, fy, fdx, fdy, fddx, fddy, fdd_per_2x, fdd_per_2y;
1395
- float temp = dt * dt;
1386
+ float fx, fy, fdx, fdy, fddx, fddy, fdd_per_2x, fdd_per_2y;
1387
+ float temp = dt * dt;
1396
1388
 
1397
- fx = startPoint.x;
1398
- fdx = 2F * (controlPoints[0].x - startPoint.x) * dt;
1399
- fdd_per_2x = (startPoint.x - 2F * controlPoints[0].x + endPoint.x) * temp;
1400
- fddx = fdd_per_2x + fdd_per_2x;
1389
+ fx = startPoint.x;
1390
+ fdx = 2F * (controlPoints[0].x - startPoint.x) * dt;
1391
+ fdd_per_2x = (startPoint.x - 2F * controlPoints[0].x + endPoint.x) * temp;
1392
+ fddx = fdd_per_2x + fdd_per_2x;
1401
1393
 
1402
- fy = startPoint.y;
1403
- fdy = 2F * (controlPoints[0].y - startPoint.y) * dt;
1404
- fdd_per_2y = (startPoint.y - 2F * controlPoints[0].y + endPoint.y) * temp;
1405
- fddy = fdd_per_2y + fdd_per_2y;
1394
+ fy = startPoint.y;
1395
+ fdy = 2F * (controlPoints[0].y - startPoint.y) * dt;
1396
+ fdd_per_2y = (startPoint.y - 2F * controlPoints[0].y + endPoint.y) * temp;
1397
+ fddy = fdd_per_2y + fdd_per_2y;
1406
1398
 
1407
- for (int loop = 0; loop < steps; loop++) {
1408
- addCurvePoint(new RPoint(fx, fy));
1399
+ for (int loop = 0; loop < steps; loop++) {
1400
+ addCurvePoint(new RPoint(fx, fy));
1409
1401
 
1410
- fx = fx + fdx + fdd_per_2x;
1411
- fdx = fdx + fddx;
1402
+ fx = fx + fdx + fdd_per_2x;
1403
+ fdx = fdx + fddx;
1412
1404
 
1413
- fy = fy + fdy + fdd_per_2y;
1414
- fdy = fdy + fddy;
1415
- }
1416
- addCurvePoint(new RPoint(endPoint));
1405
+ fy = fy + fdy + fdd_per_2y;
1406
+ fdy = fdy + fddy;
1417
1407
  }
1408
+ addCurvePoint(new RPoint(endPoint));
1409
+ }
1418
1410
 
1419
1411
  // Use Horner's method to advance
1420
- //----------------------
1421
- private void lineUniformLength() {
1412
+ //----------------------
1413
+ private void lineUniformLength() {
1422
1414
 
1423
- // If the number of steps is equal to 0 then choose a number of steps adapted to the curve
1424
- float dx1 = endPoint.x - startPoint.x;
1425
- float dy1 = endPoint.y - startPoint.y;
1415
+ // If the number of steps is equal to 0 then choose a number of steps adapted to the curve
1416
+ float dx1 = endPoint.x - startPoint.x;
1417
+ float dy1 = endPoint.y - startPoint.y;
1426
1418
 
1427
- float len = (float) Math.sqrt(dx1 * dx1 + dy1 * dy1);
1428
- float steps = (int) (len * 2);
1419
+ float len = (float) Math.sqrt(dx1 * dx1 + dy1 * dy1);
1420
+ float steps = (int) (len * 2);
1429
1421
 
1430
- if (steps < 4) {
1431
- steps = 4;
1432
- }
1433
-
1434
- // This holds the amount of steps used to calculate segment lengths
1435
- float dt = 1F / steps;
1422
+ if (steps < 4) {
1423
+ steps = 4;
1424
+ }
1436
1425
 
1437
- // This holds how much length has to bee advanced until adding a point
1438
- float untilPoint = RCommand.segmentAccOffset;
1426
+ // This holds the amount of steps used to calculate segment lengths
1427
+ float dt = 1F / steps;
1439
1428
 
1440
- float fx, fy, fdx, fdy;
1429
+ // This holds how much length has to bee advanced until adding a point
1430
+ float untilPoint = RCommand.segmentAccOffset;
1441
1431
 
1442
- fx = startPoint.x;
1443
- fdx = (endPoint.x - startPoint.x) * dt;
1432
+ float fx, fy, fdx, fdy;
1444
1433
 
1445
- fy = startPoint.y;
1446
- fdy = (endPoint.y - startPoint.y) * dt;
1434
+ fx = startPoint.x;
1435
+ fdx = (endPoint.x - startPoint.x) * dt;
1447
1436
 
1448
- for (int loop = 0; loop <= steps; loop++) {
1449
- /* Add point to curve if segment length is reached */
1450
- if (untilPoint <= 0) {
1451
- addCurvePoint(new RPoint(fx, fy));
1452
- untilPoint += RCommand.segmentLength;
1453
- }
1437
+ fy = startPoint.y;
1438
+ fdy = (endPoint.y - startPoint.y) * dt;
1454
1439
 
1455
- /* Add segment differential to segment length */
1456
- untilPoint -= (float) Math.sqrt(fdx * fdx + fdy * fdy); // Eventually try other distance measures
1440
+ for (int loop = 0; loop <= steps; loop++) {
1441
+ /* Add point to curve if segment length is reached */
1442
+ if (untilPoint <= 0) {
1443
+ addCurvePoint(new RPoint(fx, fy));
1444
+ untilPoint += RCommand.segmentLength;
1445
+ }
1457
1446
 
1458
- fx = fx + fdx;
1459
- fy = fy + fdy;
1460
- }
1447
+ /* Add segment differential to segment length */
1448
+ untilPoint -= (float) Math.sqrt(fdx * fdx + fdy * fdy); // Eventually try other distance measures
1461
1449
 
1462
- //addCurvePoint(new RPoint(endPoint));
1463
- RCommand.segmentAccOffset = untilPoint;
1450
+ fx = fx + fdx;
1451
+ fy = fy + fdy;
1464
1452
  }
1465
1453
 
1466
- // Use Horner's method to advance
1467
- //----------------------
1468
- private void quadBezierUniformLength() {
1454
+ //addCurvePoint(new RPoint(endPoint));
1455
+ RCommand.segmentAccOffset = untilPoint;
1456
+ }
1469
1457
 
1470
- float dx1 = controlPoints[0].x - startPoint.x;
1471
- float dy1 = controlPoints[0].y - startPoint.y;
1472
- float dx2 = endPoint.x - controlPoints[0].x;
1473
- float dy2 = endPoint.y - controlPoints[0].y;
1474
- float len = (float) Math.sqrt(dx1 * dx1 + dy1 * dy1) + (float) Math.sqrt(dx2 * dx2 + dy2 * dy2);
1475
- float steps = (int) (len * 2);
1458
+ // Use Horner's method to advance
1459
+ //----------------------
1460
+ private void quadBezierUniformLength() {
1476
1461
 
1477
- if (steps < 4) {
1478
- steps = 4;
1479
- }
1462
+ float dx1 = controlPoints[0].x - startPoint.x;
1463
+ float dy1 = controlPoints[0].y - startPoint.y;
1464
+ float dx2 = endPoint.x - controlPoints[0].x;
1465
+ float dy2 = endPoint.y - controlPoints[0].y;
1466
+ float len = (float) Math.sqrt(dx1 * dx1 + dy1 * dy1) + (float) Math.sqrt(dx2 * dx2 + dy2 * dy2);
1467
+ float steps = (int) (len * 2);
1480
1468
 
1481
- float dt = 1F / steps;
1482
- float untilPoint = RCommand.segmentAccOffset;
1469
+ if (steps < 4) {
1470
+ steps = 4;
1471
+ }
1483
1472
 
1484
- float fx, fy, fdx, fdy, fddx, fddy, fdd_per_2x, fdd_per_2y, fix, fiy;
1485
- float temp = dt * dt;
1473
+ float dt = 1F / steps;
1474
+ float untilPoint = RCommand.segmentAccOffset;
1486
1475
 
1487
- fx = startPoint.x;
1488
- fdx = 2F * (controlPoints[0].x - startPoint.x) * dt;
1489
- fdd_per_2x = (startPoint.x - 2F * controlPoints[0].x + endPoint.x) * temp;
1490
- fddx = fdd_per_2x + fdd_per_2x;
1476
+ float fx, fy, fdx, fdy, fddx, fddy, fdd_per_2x, fdd_per_2y, fix, fiy;
1477
+ float temp = dt * dt;
1491
1478
 
1492
- fy = startPoint.y;
1493
- fdy = 2F * (controlPoints[0].y - startPoint.y) * dt;
1494
- fdd_per_2y = (startPoint.y - 2F * controlPoints[0].y + endPoint.y) * temp;
1495
- fddy = fdd_per_2y + fdd_per_2y;
1479
+ fx = startPoint.x;
1480
+ fdx = 2F * (controlPoints[0].x - startPoint.x) * dt;
1481
+ fdd_per_2x = (startPoint.x - 2F * controlPoints[0].x + endPoint.x) * temp;
1482
+ fddx = fdd_per_2x + fdd_per_2x;
1496
1483
 
1497
- for (int loop = 0; loop <= steps; loop++) {
1498
- /* Add point to curve if segment length is reached */
1499
- if (untilPoint <= 0) {
1500
- addCurvePoint(new RPoint(fx, fy));
1501
- untilPoint += RCommand.segmentLength;
1502
- }
1484
+ fy = startPoint.y;
1485
+ fdy = 2F * (controlPoints[0].y - startPoint.y) * dt;
1486
+ fdd_per_2y = (startPoint.y - 2F * controlPoints[0].y + endPoint.y) * temp;
1487
+ fddy = fdd_per_2y + fdd_per_2y;
1503
1488
 
1504
- /* Add segment differential to segment length */
1505
- fix = fdx + fdd_per_2x;
1506
- fiy = fdy + fdd_per_2y;
1507
- untilPoint -= (float) Math.sqrt(fix * fix + fiy * fiy); // Eventually try other distance measures
1489
+ for (int loop = 0; loop <= steps; loop++) {
1490
+ /* Add point to curve if segment length is reached */
1491
+ if (untilPoint <= 0) {
1492
+ addCurvePoint(new RPoint(fx, fy));
1493
+ untilPoint += RCommand.segmentLength;
1494
+ }
1508
1495
 
1509
- fx = fx + fix;
1510
- fdx = fdx + fddx;
1496
+ /* Add segment differential to segment length */
1497
+ fix = fdx + fdd_per_2x;
1498
+ fiy = fdy + fdd_per_2y;
1499
+ untilPoint -= (float) Math.sqrt(fix * fix + fiy * fiy); // Eventually try other distance measures
1511
1500
 
1512
- fy = fy + fiy;
1513
- fdy = fdy + fddy;
1514
- }
1501
+ fx = fx + fix;
1502
+ fdx = fdx + fddx;
1515
1503
 
1516
- //addCurvePoint(new RPoint(endPoint));
1517
- RCommand.segmentAccOffset = untilPoint;
1504
+ fy = fy + fiy;
1505
+ fdy = fdy + fddy;
1518
1506
  }
1519
1507
 
1520
- // Use Horner's method to advance
1521
- //----------------------
1522
- private void cubicBezierUniformLength() {
1523
-
1524
- float dx1 = controlPoints[0].x - startPoint.x;
1525
- float dy1 = controlPoints[0].y - startPoint.y;
1526
- float dx2 = controlPoints[1].x - controlPoints[0].x;
1527
- float dy2 = controlPoints[1].y - controlPoints[0].y;
1528
- float dx3 = endPoint.x - controlPoints[1].x;
1529
- float dy3 = endPoint.y - controlPoints[1].y;
1530
-
1531
- float len = (float) Math.sqrt(dx1 * dx1 + dy1 * dy1)
1532
- + (float) Math.sqrt(dx2 * dx2 + dy2 * dy2)
1533
- + (float) Math.sqrt(dx3 * dx3 + dy3 * dy3);
1534
- float steps = (int) (len * 2);
1535
-
1536
- if (steps < 4) {
1537
- steps = 4;
1538
- }
1539
-
1540
- float dt = 1F / steps;
1541
- float untilPoint = RCommand.segmentAccOffset;
1542
-
1543
- float fx, fy, fdx, fdy, fddx, fddy, fdddx, fdddy, fdd_per_2x, fdd_per_2y, fddd_per_2x, fddd_per_2y, fddd_per_6x, fddd_per_6y, fix, fiy;
1544
- float temp = dt * dt;
1545
-
1546
- fx = startPoint.x;
1547
- fdx = 3F * (controlPoints[0].x - startPoint.x) * dt;
1548
- fdd_per_2x = 3F * (startPoint.x - 2F * controlPoints[0].x + controlPoints[1].x) * temp;
1549
- fddd_per_2x = 3F * (3F * (controlPoints[0].x - controlPoints[1].x) + endPoint.x - startPoint.x) * temp * dt;
1550
- fdddx = fddd_per_2x + fddd_per_2x;
1551
- fddx = fdd_per_2x + fdd_per_2x;
1552
- fddd_per_6x = fddd_per_2x * (1.0F / 3F);
1553
-
1554
- fy = startPoint.y;
1555
- fdy = 3F * (controlPoints[0].y - startPoint.y) * dt;
1556
- fdd_per_2y = 3F * (startPoint.y - 2F * controlPoints[0].y + controlPoints[1].y) * temp;
1557
- fddd_per_2y = 3F * (3F * (controlPoints[0].y - controlPoints[1].y) + endPoint.y - startPoint.y) * temp * dt;
1558
- fdddy = fddd_per_2y + fddd_per_2y;
1559
- fddy = fdd_per_2y + fdd_per_2y;
1560
- fddd_per_6y = fddd_per_2y * (1.0F / 3F);
1561
-
1562
- for (int loop = 0; loop < steps; loop++) {
1563
- /* Add point to curve if segment length is reached */
1564
- if (untilPoint <= 0) {
1565
- addCurvePoint(new RPoint(fx, fy));
1566
- untilPoint += RCommand.segmentLength;
1567
- }
1568
-
1569
- /* Add segment differential to segment length */
1570
- fix = fdx + fdd_per_2x + fddd_per_6x;
1571
- fiy = fdy + fdd_per_2y + fddd_per_6y;
1572
- untilPoint -= (float) Math.sqrt(fix * fix + fiy * fiy); // Eventually try other distance measures
1508
+ //addCurvePoint(new RPoint(endPoint));
1509
+ RCommand.segmentAccOffset = untilPoint;
1510
+ }
1573
1511
 
1574
- fx = fx + fix;
1575
- fdx = fdx + fddx + fddd_per_2x;
1576
- fddx = fddx + fdddx;
1577
- fdd_per_2x = fdd_per_2x + fddd_per_2x;
1512
+ // Use Horner's method to advance
1513
+ //----------------------
1514
+ private void cubicBezierUniformLength() {
1515
+
1516
+ float dx1 = controlPoints[0].x - startPoint.x;
1517
+ float dy1 = controlPoints[0].y - startPoint.y;
1518
+ float dx2 = controlPoints[1].x - controlPoints[0].x;
1519
+ float dy2 = controlPoints[1].y - controlPoints[0].y;
1520
+ float dx3 = endPoint.x - controlPoints[1].x;
1521
+ float dy3 = endPoint.y - controlPoints[1].y;
1578
1522
 
1579
- fy = fy + fiy;
1580
- fdy = fdy + fddy + fddd_per_2y;
1581
- fddy = fddy + fdddy;
1582
- fdd_per_2y = fdd_per_2y + fddd_per_2y;
1583
- }
1523
+ float len = (float) Math.sqrt(dx1 * dx1 + dy1 * dy1)
1524
+ + (float) Math.sqrt(dx2 * dx2 + dy2 * dy2)
1525
+ + (float) Math.sqrt(dx3 * dx3 + dy3 * dy3);
1526
+ float steps = (int) (len * 2);
1584
1527
 
1585
- //addCurvePoint(new RPoint(endPoint));
1586
- RCommand.segmentAccOffset = untilPoint;
1528
+ if (steps < 4) {
1529
+ steps = 4;
1587
1530
  }
1588
1531
 
1589
- private float quadBezierLength() {
1590
-
1591
- float dx1 = controlPoints[0].x - startPoint.x;
1592
- float dy1 = controlPoints[0].y - startPoint.y;
1593
- float dx2 = endPoint.x - controlPoints[0].x;
1594
- float dy2 = endPoint.y - controlPoints[0].y;
1595
- float len = (float) Math.sqrt(dx1 * dx1 + dy1 * dy1) + (float) Math.sqrt(dx2 * dx2 + dy2 * dy2);
1596
- float steps = (int) (len * 2);
1532
+ float dt = 1F / steps;
1533
+ float untilPoint = RCommand.segmentAccOffset;
1597
1534
 
1598
- if (steps < 4) {
1599
- steps = 4;
1600
- }
1535
+ float fx, fy, fdx, fdy, fddx, fddy, fdddx, fdddy, fdd_per_2x, fdd_per_2y, fddd_per_2x, fddd_per_2y, fddd_per_6x, fddd_per_6y, fix, fiy;
1536
+ float temp = dt * dt;
1537
+
1538
+ fx = startPoint.x;
1539
+ fdx = 3F * (controlPoints[0].x - startPoint.x) * dt;
1540
+ fdd_per_2x = 3F * (startPoint.x - 2F * controlPoints[0].x + controlPoints[1].x) * temp;
1541
+ fddd_per_2x = 3F * (3F * (controlPoints[0].x - controlPoints[1].x) + endPoint.x - startPoint.x) * temp * dt;
1542
+ fdddx = fddd_per_2x + fddd_per_2x;
1543
+ fddx = fdd_per_2x + fdd_per_2x;
1544
+ fddd_per_6x = fddd_per_2x * (1.0F / 3F);
1601
1545
 
1602
- float dt = 1F / steps;
1546
+ fy = startPoint.y;
1547
+ fdy = 3F * (controlPoints[0].y - startPoint.y) * dt;
1548
+ fdd_per_2y = 3F * (startPoint.y - 2F * controlPoints[0].y + controlPoints[1].y) * temp;
1549
+ fddd_per_2y = 3F * (3F * (controlPoints[0].y - controlPoints[1].y) + endPoint.y - startPoint.y) * temp * dt;
1550
+ fdddy = fddd_per_2y + fddd_per_2y;
1551
+ fddy = fdd_per_2y + fdd_per_2y;
1552
+ fddd_per_6y = fddd_per_2y * (1.0F / 3F);
1603
1553
 
1604
- float fx, fy, fdx, fdy, fddx, fddy, fdd_per_2x, fdd_per_2y, fix, fiy;
1605
- float temp = dt * dt;
1606
- float totallen = 0F;
1554
+ for (int loop = 0; loop < steps; loop++) {
1555
+ /* Add point to curve if segment length is reached */
1556
+ if (untilPoint <= 0) {
1557
+ addCurvePoint(new RPoint(fx, fy));
1558
+ untilPoint += RCommand.segmentLength;
1559
+ }
1560
+
1561
+ /* Add segment differential to segment length */
1562
+ fix = fdx + fdd_per_2x + fddd_per_6x;
1563
+ fiy = fdy + fdd_per_2y + fddd_per_6y;
1564
+ untilPoint -= (float) Math.sqrt(fix * fix + fiy * fiy); // Eventually try other distance measures
1565
+
1566
+ fx = fx + fix;
1567
+ fdx = fdx + fddx + fddd_per_2x;
1568
+ fddx = fddx + fdddx;
1569
+ fdd_per_2x = fdd_per_2x + fddd_per_2x;
1570
+
1571
+ fy = fy + fiy;
1572
+ fdy = fdy + fddy + fddd_per_2y;
1573
+ fddy = fddy + fdddy;
1574
+ fdd_per_2y = fdd_per_2y + fddd_per_2y;
1575
+ }
1576
+
1577
+ //addCurvePoint(new RPoint(endPoint));
1578
+ RCommand.segmentAccOffset = untilPoint;
1579
+ }
1580
+
1581
+ private float quadBezierLength() {
1582
+
1583
+ float dx1 = controlPoints[0].x - startPoint.x;
1584
+ float dy1 = controlPoints[0].y - startPoint.y;
1585
+ float dx2 = endPoint.x - controlPoints[0].x;
1586
+ float dy2 = endPoint.y - controlPoints[0].y;
1587
+ float len = (float) Math.sqrt(dx1 * dx1 + dy1 * dy1) + (float) Math.sqrt(dx2 * dx2 + dy2 * dy2);
1588
+ float steps = (int) (len * 2);
1589
+
1590
+ if (steps < 4) {
1591
+ steps = 4;
1592
+ }
1593
+
1594
+ float dt = 1F / steps;
1595
+
1596
+ float fx, fy, fdx, fdy, fddx, fddy, fdd_per_2x, fdd_per_2y, fix, fiy;
1597
+ float temp = dt * dt;
1598
+ float totallen = 0F;
1599
+
1600
+ fx = startPoint.x;
1601
+ fdx = 2F * (controlPoints[0].x - startPoint.x) * dt;
1602
+ fdd_per_2x = (startPoint.x - 2F * controlPoints[0].x + endPoint.x) * temp;
1603
+ fddx = fdd_per_2x + fdd_per_2x;
1604
+
1605
+ fy = startPoint.y;
1606
+ fdy = 2F * (controlPoints[0].y - startPoint.y) * dt;
1607
+ fdd_per_2y = (startPoint.y - 2F * controlPoints[0].y + endPoint.y) * temp;
1608
+ fddy = fdd_per_2y + fdd_per_2y;
1609
+
1610
+ for (int loop = 0; loop <= steps; loop++) {
1611
+ /* Add segment differential to segment length */
1612
+ fix = fdx + fdd_per_2x;
1613
+ fiy = fdy + fdd_per_2y;
1614
+ totallen += (float) Math.sqrt(fix * fix + fiy * fiy); // Eventually try other distance measures
1607
1615
 
1608
- fx = startPoint.x;
1609
- fdx = 2F * (controlPoints[0].x - startPoint.x) * dt;
1610
- fdd_per_2x = (startPoint.x - 2F * controlPoints[0].x + endPoint.x) * temp;
1611
- fddx = fdd_per_2x + fdd_per_2x;
1616
+ fx = fx + fix;
1617
+ fdx = fdx + fddx;
1612
1618
 
1613
- fy = startPoint.y;
1614
- fdy = 2F * (controlPoints[0].y - startPoint.y) * dt;
1615
- fdd_per_2y = (startPoint.y - 2F * controlPoints[0].y + endPoint.y) * temp;
1616
- fddy = fdd_per_2y + fdd_per_2y;
1619
+ fy = fy + fiy;
1620
+ fdy = fdy + fddy;
1621
+ }
1617
1622
 
1618
- for (int loop = 0; loop <= steps; loop++) {
1619
- /* Add segment differential to segment length */
1620
- fix = fdx + fdd_per_2x;
1621
- fiy = fdy + fdd_per_2y;
1622
- totallen += (float) Math.sqrt(fix * fix + fiy * fiy); // Eventually try other distance measures
1623
+ return totallen;
1624
+ }
1623
1625
 
1624
- fx = fx + fix;
1625
- fdx = fdx + fddx;
1626
+ private float cubicBezierLength() {
1626
1627
 
1627
- fy = fy + fiy;
1628
- fdy = fdy + fddy;
1629
- }
1628
+ float dx1 = controlPoints[0].x - startPoint.x;
1629
+ float dy1 = controlPoints[0].y - startPoint.y;
1630
+ float dx2 = controlPoints[1].x - controlPoints[0].x;
1631
+ float dy2 = controlPoints[1].y - controlPoints[0].y;
1632
+ float dx3 = endPoint.x - controlPoints[1].x;
1633
+ float dy3 = endPoint.y - controlPoints[1].y;
1630
1634
 
1631
- return totallen;
1635
+ float len = (float) Math.sqrt(dx1 * dx1 + dy1 * dy1)
1636
+ + (float) Math.sqrt(dx2 * dx2 + dy2 * dy2)
1637
+ + (float) Math.sqrt(dx3 * dx3 + dy3 * dy3);
1638
+ float steps = (int) (len * 2);
1639
+
1640
+ if (steps < 4) {
1641
+ steps = 4;
1632
1642
  }
1633
1643
 
1634
- private float cubicBezierLength() {
1644
+ float dt = 1F / steps;
1635
1645
 
1636
- float dx1 = controlPoints[0].x - startPoint.x;
1637
- float dy1 = controlPoints[0].y - startPoint.y;
1638
- float dx2 = controlPoints[1].x - controlPoints[0].x;
1639
- float dy2 = controlPoints[1].y - controlPoints[0].y;
1640
- float dx3 = endPoint.x - controlPoints[1].x;
1641
- float dy3 = endPoint.y - controlPoints[1].y;
1646
+ float fx, fy, fdx, fdy, fddx, fddy, fdddx, fdddy, fdd_per_2x, fdd_per_2y, fddd_per_2x, fddd_per_2y, fddd_per_6x, fddd_per_6y, fix, fiy;
1647
+ float temp = dt * dt;
1648
+ float totallen = 0F;
1642
1649
 
1643
- float len = (float) Math.sqrt(dx1 * dx1 + dy1 * dy1)
1644
- + (float) Math.sqrt(dx2 * dx2 + dy2 * dy2)
1645
- + (float) Math.sqrt(dx3 * dx3 + dy3 * dy3);
1646
- float steps = (int) (len * 2);
1650
+ fx = startPoint.x;
1651
+ fdx = 3F * (controlPoints[0].x - startPoint.x) * dt;
1652
+ fdd_per_2x = 3F * (startPoint.x - 2F * controlPoints[0].x + controlPoints[1].x) * temp;
1653
+ fddd_per_2x = 3F * (3F * (controlPoints[0].x - controlPoints[1].x) + endPoint.x - startPoint.x) * temp * dt;
1654
+ fdddx = fddd_per_2x + fddd_per_2x;
1655
+ fddx = fdd_per_2x + fdd_per_2x;
1656
+ fddd_per_6x = fddd_per_2x * (1.0F / 3F);
1647
1657
 
1648
- if (steps < 4) {
1649
- steps = 4;
1650
- }
1658
+ fy = startPoint.y;
1659
+ fdy = 3F * (controlPoints[0].y - startPoint.y) * dt;
1660
+ fdd_per_2y = 3F * (startPoint.y - 2F * controlPoints[0].y + controlPoints[1].y) * temp;
1661
+ fddd_per_2y = 3F * (3F * (controlPoints[0].y - controlPoints[1].y) + endPoint.y - startPoint.y) * temp * dt;
1651
1662
 
1652
- float dt = 1F / steps;
1653
-
1654
- float fx, fy, fdx, fdy, fddx, fddy, fdddx, fdddy, fdd_per_2x, fdd_per_2y, fddd_per_2x, fddd_per_2y, fddd_per_6x, fddd_per_6y, fix, fiy;
1655
- float temp = dt * dt;
1656
- float totallen = 0F;
1657
-
1658
- fx = startPoint.x;
1659
- fdx = 3F * (controlPoints[0].x - startPoint.x) * dt;
1660
- fdd_per_2x = 3F * (startPoint.x - 2F * controlPoints[0].x + controlPoints[1].x) * temp;
1661
- fddd_per_2x = 3F * (3F * (controlPoints[0].x - controlPoints[1].x) + endPoint.x - startPoint.x) * temp * dt;
1662
- fdddx = fddd_per_2x + fddd_per_2x;
1663
- fddx = fdd_per_2x + fdd_per_2x;
1664
- fddd_per_6x = fddd_per_2x * (1.0F / 3F);
1665
-
1666
- fy = startPoint.y;
1667
- fdy = 3F * (controlPoints[0].y - startPoint.y) * dt;
1668
- fdd_per_2y = 3F * (startPoint.y - 2F * controlPoints[0].y + controlPoints[1].y) * temp;
1669
- fddd_per_2y = 3F * (3F * (controlPoints[0].y - controlPoints[1].y) + endPoint.y - startPoint.y) * temp * dt;
1670
-
1671
- fdddy = fddd_per_2y + fddd_per_2y;
1672
- fddy = fdd_per_2y + fdd_per_2y;
1673
- fddd_per_6y = fddd_per_2y * (1.0F / 3F);
1674
-
1675
- for (int loop = 0; loop < steps; loop++) {
1676
- /* Add segment differential to segment length */
1677
- fix = fdx + fdd_per_2x + fddd_per_6x;
1678
- fiy = fdy + fdd_per_2y + fddd_per_6y;
1679
- totallen += (float) Math.sqrt(fix * fix + fiy * fiy); // Eventually try other distance measures
1680
-
1681
- fx = fx + fix;
1682
- fdx = fdx + fddx + fddd_per_2x;
1683
- fddx = fddx + fdddx;
1684
- fdd_per_2x = fdd_per_2x + fddd_per_2x;
1685
-
1686
- fy = fy + fiy;
1687
- fdy = fdy + fddy + fddd_per_2y;
1688
- fddy = fddy + fdddy;
1689
- fdd_per_2y = fdd_per_2y + fddd_per_2y;
1690
- }
1663
+ fdddy = fddd_per_2y + fddd_per_2y;
1664
+ fddy = fdd_per_2y + fdd_per_2y;
1665
+ fddd_per_6y = fddd_per_2y * (1.0F / 3F);
1666
+
1667
+ for (int loop = 0; loop < steps; loop++) {
1668
+ /* Add segment differential to segment length */
1669
+ fix = fdx + fdd_per_2x + fddd_per_6x;
1670
+ fiy = fdy + fdd_per_2y + fddd_per_6y;
1671
+ totallen += (float) Math.sqrt(fix * fix + fiy * fiy); // Eventually try other distance measures
1691
1672
 
1692
- return totallen;
1673
+ fx = fx + fix;
1674
+ fdx = fdx + fddx + fddd_per_2x;
1675
+ fddx = fddx + fdddx;
1676
+ fdd_per_2x = fdd_per_2x + fddd_per_2x;
1677
+
1678
+ fy = fy + fiy;
1679
+ fdy = fdy + fddy + fddd_per_2y;
1680
+ fddy = fddy + fdddy;
1681
+ fdd_per_2y = fdd_per_2y + fddd_per_2y;
1693
1682
  }
1694
1683
 
1695
- /**
1696
- * Use this method to transform the command.
1697
- *
1698
- * @eexample transformCommand
1699
- * @param g PGraphics, the graphics object on which to apply an affine
1700
- * transformation to the command
1701
- */
1702
- /*
1684
+ return totallen;
1685
+ }
1686
+
1687
+ /**
1688
+ * Use this method to transform the command.
1689
+ *
1690
+ transformCommand
1691
+ * @param g PGraphics, the graphics object on which to apply an affine
1692
+ * transformation to the command
1693
+ */
1694
+ /*
1703
1695
  public void transform(RMatrix m){
1704
1696
  int numControlPoints = countControlPoints();
1705
1697
  if(numControlPoints!=0){
@@ -1710,319 +1702,319 @@ public class RCommand extends RGeomElem {
1710
1702
  startPoint.transform(m);
1711
1703
  endPoint.transform(m);
1712
1704
  }
1713
- */
1714
- private void append(RPoint nextcontrolpoint) {
1715
- RPoint[] newcontrolPoints;
1716
- if (controlPoints == null) {
1717
- newcontrolPoints = new RPoint[1];
1718
- newcontrolPoints[0] = nextcontrolpoint;
1719
- } else {
1720
- newcontrolPoints = new RPoint[controlPoints.length + 1];
1721
- System.arraycopy(controlPoints, 0, newcontrolPoints, 0, controlPoints.length);
1722
- newcontrolPoints[controlPoints.length] = nextcontrolpoint;
1705
+ */
1706
+ private void append(RPoint nextcontrolpoint) {
1707
+ RPoint[] newcontrolPoints;
1708
+ if (controlPoints == null) {
1709
+ newcontrolPoints = new RPoint[1];
1710
+ newcontrolPoints[0] = nextcontrolpoint;
1711
+ } else {
1712
+ newcontrolPoints = new RPoint[controlPoints.length + 1];
1713
+ System.arraycopy(controlPoints, 0, newcontrolPoints, 0, controlPoints.length);
1714
+ newcontrolPoints[controlPoints.length] = nextcontrolpoint;
1715
+ }
1716
+ this.controlPoints = newcontrolPoints;
1717
+ }
1718
+
1719
+ private void addCurvePoint(RPoint nextcurvepoint) {
1720
+ RPoint[] newcurvePoints;
1721
+ if (curvePoints == null) {
1722
+ newcurvePoints = new RPoint[1];
1723
+ newcurvePoints[0] = nextcurvepoint;
1724
+ } else {
1725
+ newcurvePoints = new RPoint[curvePoints.length + 1];
1726
+ System.arraycopy(curvePoints, 0, newcurvePoints, 0, curvePoints.length);
1727
+ newcurvePoints[curvePoints.length] = nextcurvepoint;
1728
+ }
1729
+ this.curvePoints = newcurvePoints;
1730
+ }
1731
+
1732
+ public RPoint[] intersectionPoints(RCommand other) {
1733
+ RPoint[] result = null;
1734
+
1735
+ switch (commandType) {
1736
+ case LINETO:
1737
+ switch (other.getCommandType()) {
1738
+ case LINETO:
1739
+ result = lineLineIntersection(this, other);
1740
+ break;
1741
+
1742
+ case QUADBEZIERTO:
1743
+ result = lineQuadIntersection(this, other);
1744
+ break;
1745
+
1746
+ case CUBICBEZIERTO:
1747
+ result = lineCubicIntersection(this, other);
1748
+ break;
1723
1749
  }
1724
- this.controlPoints = newcontrolPoints;
1725
- }
1750
+ break;
1751
+
1752
+ case QUADBEZIERTO:
1753
+ switch (other.getCommandType()) {
1754
+ case LINETO:
1755
+ result = lineQuadIntersection(other, this);
1756
+ break;
1757
+
1758
+ case QUADBEZIERTO:
1759
+ result = quadQuadIntersection(this, other);
1760
+ break;
1726
1761
 
1727
- private void addCurvePoint(RPoint nextcurvepoint) {
1728
- RPoint[] newcurvePoints;
1729
- if (curvePoints == null) {
1730
- newcurvePoints = new RPoint[1];
1731
- newcurvePoints[0] = nextcurvepoint;
1732
- } else {
1733
- newcurvePoints = new RPoint[curvePoints.length + 1];
1734
- System.arraycopy(curvePoints, 0, newcurvePoints, 0, curvePoints.length);
1735
- newcurvePoints[curvePoints.length] = nextcurvepoint;
1762
+ case CUBICBEZIERTO:
1763
+ result = quadCubicIntersection(this, other);
1764
+ break;
1736
1765
  }
1737
- this.curvePoints = newcurvePoints;
1738
- }
1766
+ break;
1739
1767
 
1740
- public RPoint[] intersectionPoints(RCommand other) {
1741
- RPoint[] result = null;
1768
+ case CUBICBEZIERTO:
1769
+ switch (other.getCommandType()) {
1770
+ case LINETO:
1771
+ result = lineCubicIntersection(other, this);
1772
+ break;
1742
1773
 
1743
- switch (commandType) {
1744
- case LINETO:
1745
- switch (other.getCommandType()) {
1746
- case LINETO:
1747
- result = lineLineIntersection(this, other);
1748
- break;
1749
-
1750
- case QUADBEZIERTO:
1751
- result = lineQuadIntersection(this, other);
1752
- break;
1753
-
1754
- case CUBICBEZIERTO:
1755
- result = lineCubicIntersection(this, other);
1756
- break;
1757
- }
1758
- break;
1759
-
1760
- case QUADBEZIERTO:
1761
- switch (other.getCommandType()) {
1762
- case LINETO:
1763
- result = lineQuadIntersection(other, this);
1764
- break;
1765
-
1766
- case QUADBEZIERTO:
1767
- result = quadQuadIntersection(this, other);
1768
- break;
1769
-
1770
- case CUBICBEZIERTO:
1771
- result = quadCubicIntersection(this, other);
1772
- break;
1773
- }
1774
- break;
1775
-
1776
- case CUBICBEZIERTO:
1777
- switch (other.getCommandType()) {
1778
- case LINETO:
1779
- result = lineCubicIntersection(other, this);
1780
- break;
1781
-
1782
- case QUADBEZIERTO:
1783
- result = quadCubicIntersection(other, this);
1784
- break;
1785
-
1786
- case CUBICBEZIERTO:
1787
- result = cubicCubicIntersection(this, other);
1788
- break;
1789
- }
1790
- break;
1774
+ case QUADBEZIERTO:
1775
+ result = quadCubicIntersection(other, this);
1776
+ break;
1777
+
1778
+ case CUBICBEZIERTO:
1779
+ result = cubicCubicIntersection(this, other);
1780
+ break;
1791
1781
  }
1782
+ break;
1783
+ }
1792
1784
 
1793
- return result;
1785
+ return result;
1786
+ }
1787
+
1788
+ public static RPoint[] lineLineIntersection(RCommand c1, RCommand c2) {
1789
+ RPoint a = new RPoint(c1.startPoint);
1790
+ RPoint b = new RPoint(c1.endPoint);
1791
+
1792
+ RPoint c = new RPoint(c2.startPoint);
1793
+ RPoint d = new RPoint(c2.endPoint);
1794
+
1795
+ float epsilon = 1e-9f;
1796
+
1797
+ //test for parallel case
1798
+ float denom = (d.y - c.y) * (b.x - a.x) - (d.x - c.x) * (b.y - a.y);
1799
+ if (Math.abs(denom) < epsilon) {
1800
+ return null;
1801
+ }
1802
+
1803
+ //calculate segment parameter and ensure its within bounds
1804
+ float t1 = ((d.x - c.x) * (a.y - c.y) - (d.y - c.y) * (a.x - c.x)) / denom;
1805
+ float t2 = ((b.x - a.x) * (a.y - c.y) - (b.y - a.y) * (a.x - c.x)) / denom;
1806
+
1807
+ if (t1 < 0.0f || t1 > 1.0f || t2 < 0.0f || t2 > 1.0f) {
1808
+ return null;
1794
1809
  }
1795
1810
 
1796
- public static RPoint[] lineLineIntersection(RCommand c1, RCommand c2) {
1797
- RPoint a = new RPoint(c1.startPoint);
1798
- RPoint b = new RPoint(c1.endPoint);
1811
+ //store actual intersection
1812
+ RPoint[] result = new RPoint[1];
1813
+
1814
+ RPoint temp = new RPoint(b);
1815
+ temp.sub(a);
1816
+ temp.scale(t1);
1817
+
1818
+ result[0] = new RPoint(a);
1819
+ result[0].add(temp);
1820
+
1821
+ return result;
1822
+ }
1823
+
1824
+ public static RPoint[] lineQuadIntersection(RCommand c1, RCommand c2) {
1825
+ return null;
1826
+ }
1827
+
1828
+ public static RPoint[] lineCubicIntersection(RCommand c1, RCommand c2) {
1829
+ return null;
1830
+ }
1831
+
1832
+ public static RPoint[] quadQuadIntersection(RCommand c1, RCommand c2) {
1833
+ return null;
1834
+ }
1799
1835
 
1800
- RPoint c = new RPoint(c2.startPoint);
1801
- RPoint d = new RPoint(c2.endPoint);
1836
+ public static RPoint[] quadCubicIntersection(RCommand c1, RCommand c2) {
1837
+ return null;
1838
+ }
1802
1839
 
1803
- float epsilon = 1e-9f;
1840
+ public static RPoint[] cubicCubicIntersection(RCommand c1, RCommand c2) {
1841
+ return null;
1842
+ }
1804
1843
 
1805
- //test for parallel case
1806
- float denom = (d.y - c.y) * (b.x - a.x) - (d.x - c.x) * (b.y - a.y);
1807
- if (Math.abs(denom) < epsilon) {
1808
- return null;
1844
+ public RClosest closestPoints(RCommand other) {
1845
+ RClosest result = new RClosest();
1846
+ result.distance = 0;
1847
+ RPoint temp;
1848
+
1849
+ switch (commandType) {
1850
+ case LINETO:
1851
+ switch (other.getCommandType()) {
1852
+ case LINETO:
1853
+ result.intersects = lineLineIntersection(this, other);
1854
+ if (result.intersects == null) {
1855
+ result = lineLineClosest(this, other);
1856
+ }
1857
+ break;
1858
+
1859
+ case QUADBEZIERTO:
1860
+ result.intersects = lineQuadIntersection(this, other);
1861
+ if (result.intersects == null) {
1862
+ result = lineQuadClosest(this, other);
1863
+ }
1864
+ break;
1865
+
1866
+ case CUBICBEZIERTO:
1867
+ result.intersects = lineCubicIntersection(this, other);
1868
+ if (result.intersects == null) {
1869
+ result = lineCubicClosest(this, other);
1870
+ }
1871
+ break;
1809
1872
  }
1873
+ break;
1874
+
1875
+ case QUADBEZIERTO:
1876
+ switch (other.getCommandType()) {
1877
+ case LINETO:
1878
+ result.intersects = lineQuadIntersection(other, this);
1879
+ if (result.intersects == null) {
1880
+ result = lineQuadClosest(other, this);
1881
+ temp = result.closest[0];
1882
+ result.closest[0] = result.closest[1];
1883
+ result.closest[1] = temp;
1884
+ }
1885
+ break;
1810
1886
 
1811
- //calculate segment parameter and ensure its within bounds
1812
- float t1 = ((d.x - c.x) * (a.y - c.y) - (d.y - c.y) * (a.x - c.x)) / denom;
1813
- float t2 = ((b.x - a.x) * (a.y - c.y) - (b.y - a.y) * (a.x - c.x)) / denom;
1887
+ case QUADBEZIERTO:
1888
+ result.intersects = quadQuadIntersection(this, other);
1889
+ if (result.intersects == null) {
1890
+ result = quadQuadClosest(this, other);
1891
+ }
1892
+ break;
1814
1893
 
1815
- if (t1 < 0.0f || t1 > 1.0f || t2 < 0.0f || t2 > 1.0f) {
1816
- return null;
1894
+ case CUBICBEZIERTO:
1895
+ result.intersects = quadCubicIntersection(this, other);
1896
+ if (result.intersects == null) {
1897
+ result = quadCubicClosest(this, other);
1898
+ }
1899
+ break;
1817
1900
  }
1901
+ break;
1902
+
1903
+ case CUBICBEZIERTO:
1904
+ switch (other.getCommandType()) {
1905
+ case LINETO:
1906
+ result.intersects = lineCubicIntersection(other, this);
1907
+ if (result.intersects == null) {
1908
+ result = lineCubicClosest(other, this);
1909
+ temp = result.closest[0];
1910
+ result.closest[0] = result.closest[1];
1911
+ result.closest[1] = temp;
1912
+ }
1913
+ break;
1914
+
1915
+ case QUADBEZIERTO:
1916
+ result.intersects = quadCubicIntersection(other, this);
1917
+ if (result.intersects == null) {
1918
+ result = quadCubicClosest(other, this);
1919
+ temp = result.closest[0];
1920
+ result.closest[0] = result.closest[1];
1921
+ result.closest[1] = temp;
1922
+ }
1923
+ break;
1818
1924
 
1819
- //store actual intersection
1820
- RPoint[] result = new RPoint[1];
1925
+ case CUBICBEZIERTO:
1926
+ result.intersects = cubicCubicIntersection(this, other);
1927
+ if (result.intersects == null) {
1928
+ result = cubicCubicClosest(this, other);
1929
+ }
1930
+ break;
1931
+ }
1932
+ break;
1933
+ }
1821
1934
 
1822
- RPoint temp = new RPoint(b);
1823
- temp.sub(a);
1824
- temp.scale(t1);
1935
+ return result;
1936
+ }
1825
1937
 
1826
- result[0] = new RPoint(a);
1827
- result[0].add(temp);
1938
+ public static float closestAdvFrom(RCommand c, RPoint p) {
1939
+ RPoint a = new RPoint(c.startPoint);
1940
+ RPoint b = new RPoint(c.endPoint);
1828
1941
 
1829
- return result;
1830
- }
1942
+ RPoint ap = new RPoint(p);
1943
+ ap.sub(a);
1831
1944
 
1832
- public static RPoint[] lineQuadIntersection(RCommand c1, RCommand c2) {
1833
- return null;
1834
- }
1945
+ RPoint ab = new RPoint(b);
1946
+ ab.sub(a);
1835
1947
 
1836
- public static RPoint[] lineCubicIntersection(RCommand c1, RCommand c2) {
1837
- return null;
1838
- }
1948
+ float denom = ab.sqrnorm();
1949
+ float epsilon = 1e-19f;
1839
1950
 
1840
- public static RPoint[] quadQuadIntersection(RCommand c1, RCommand c2) {
1841
- return null;
1951
+ if (denom < epsilon) {
1952
+ return 0.5f;
1842
1953
  }
1843
1954
 
1844
- public static RPoint[] quadCubicIntersection(RCommand c1, RCommand c2) {
1845
- return null;
1846
- }
1955
+ float t = (ab.x * ap.x + ab.y * ap.y) / denom;
1847
1956
 
1848
- public static RPoint[] cubicCubicIntersection(RCommand c1, RCommand c2) {
1849
- return null;
1850
- }
1957
+ t = t > 0.0f ? t : 0.0f;
1958
+ t = t < 1.0f ? t : 1.0f;
1851
1959
 
1852
- public RClosest closestPoints(RCommand other) {
1853
- RClosest result = new RClosest();
1854
- result.distance = 0;
1855
- RPoint temp;
1960
+ return t;
1856
1961
 
1857
- switch (commandType) {
1858
- case LINETO:
1859
- switch (other.getCommandType()) {
1860
- case LINETO:
1861
- result.intersects = lineLineIntersection(this, other);
1862
- if (result.intersects == null) {
1863
- result = lineLineClosest(this, other);
1864
- }
1865
- break;
1866
-
1867
- case QUADBEZIERTO:
1868
- result.intersects = lineQuadIntersection(this, other);
1869
- if (result.intersects == null) {
1870
- result = lineQuadClosest(this, other);
1871
- }
1872
- break;
1873
-
1874
- case CUBICBEZIERTO:
1875
- result.intersects = lineCubicIntersection(this, other);
1876
- if (result.intersects == null) {
1877
- result = lineCubicClosest(this, other);
1878
- }
1879
- break;
1880
- }
1881
- break;
1882
-
1883
- case QUADBEZIERTO:
1884
- switch (other.getCommandType()) {
1885
- case LINETO:
1886
- result.intersects = lineQuadIntersection(other, this);
1887
- if (result.intersects == null) {
1888
- result = lineQuadClosest(other, this);
1889
- temp = result.closest[0];
1890
- result.closest[0] = result.closest[1];
1891
- result.closest[1] = temp;
1892
- }
1893
- break;
1894
-
1895
- case QUADBEZIERTO:
1896
- result.intersects = quadQuadIntersection(this, other);
1897
- if (result.intersects == null) {
1898
- result = quadQuadClosest(this, other);
1899
- }
1900
- break;
1901
-
1902
- case CUBICBEZIERTO:
1903
- result.intersects = quadCubicIntersection(this, other);
1904
- if (result.intersects == null) {
1905
- result = quadCubicClosest(this, other);
1906
- }
1907
- break;
1908
- }
1909
- break;
1910
-
1911
- case CUBICBEZIERTO:
1912
- switch (other.getCommandType()) {
1913
- case LINETO:
1914
- result.intersects = lineCubicIntersection(other, this);
1915
- if (result.intersects == null) {
1916
- result = lineCubicClosest(other, this);
1917
- temp = result.closest[0];
1918
- result.closest[0] = result.closest[1];
1919
- result.closest[1] = temp;
1920
- }
1921
- break;
1922
-
1923
- case QUADBEZIERTO:
1924
- result.intersects = quadCubicIntersection(other, this);
1925
- if (result.intersects == null) {
1926
- result = quadCubicClosest(other, this);
1927
- temp = result.closest[0];
1928
- result.closest[0] = result.closest[1];
1929
- result.closest[1] = temp;
1930
- }
1931
- break;
1932
-
1933
- case CUBICBEZIERTO:
1934
- result.intersects = cubicCubicIntersection(this, other);
1935
- if (result.intersects == null) {
1936
- result = cubicCubicClosest(this, other);
1937
- }
1938
- break;
1939
- }
1940
- break;
1941
- }
1962
+ }
1942
1963
 
1943
- return result;
1944
- }
1964
+ public static RClosest lineLineClosest(RCommand c1, RCommand c2) {
1965
+ RPoint c1b = new RPoint(c1.startPoint);
1966
+ RPoint c1e = new RPoint(c1.endPoint);
1945
1967
 
1946
- public static float closestAdvFrom(RCommand c, RPoint p) {
1947
- RPoint a = new RPoint(c.startPoint);
1948
- RPoint b = new RPoint(c.endPoint);
1968
+ float c2t1 = closestAdvFrom(c2, c1b);
1969
+ float c2t2 = closestAdvFrom(c2, c1e);
1949
1970
 
1950
- RPoint ap = new RPoint(p);
1951
- ap.sub(a);
1971
+ RPoint c2p1 = c2.getPoint(c2t1);
1972
+ RPoint c2p2 = c2.getPoint(c2t2);
1952
1973
 
1953
- RPoint ab = new RPoint(b);
1954
- ab.sub(a);
1974
+ float dist1c2 = c2p1.dist(c1b);
1975
+ float dist2c2 = c2p2.dist(c1e);
1955
1976
 
1956
- float denom = ab.sqrnorm();
1957
- float epsilon = 1e-19f;
1977
+ RPoint c2b = new RPoint(c2.startPoint);
1978
+ RPoint c2e = new RPoint(c2.endPoint);
1958
1979
 
1959
- if (denom < epsilon) {
1960
- return 0.5f;
1961
- }
1980
+ float c1t1 = closestAdvFrom(c1, c2b);
1981
+ float c1t2 = closestAdvFrom(c1, c2e);
1962
1982
 
1963
- float t = (ab.x * ap.x + ab.y * ap.y) / denom;
1983
+ RPoint c1p1 = c1.getPoint(c1t1);
1984
+ RPoint c1p2 = c1.getPoint(c1t2);
1964
1985
 
1965
- t = t > 0.0f ? t : 0.0f;
1966
- t = t < 1.0f ? t : 1.0f;
1986
+ float dist1c1 = c1p1.dist(c2b);
1987
+ float dist2c1 = c1p2.dist(c2e);
1967
1988
 
1968
- return t;
1989
+ RClosest result = new RClosest();
1990
+ result.distance = Math.min(Math.min(dist1c2, dist2c2), Math.min(dist1c1, dist2c1));
1991
+ result.closest = new RPoint[2];
1992
+ result.advancements = new float[2];
1969
1993
 
1994
+ if (result.distance == dist1c2) {
1995
+ result.closest[0] = c1b;
1996
+ result.closest[1] = c2p1;
1997
+ result.advancements[0] = 0;
1998
+ result.advancements[1] = c2t1;
1999
+ } else if (result.distance == dist2c2) {
2000
+ result.closest[0] = c1e;
2001
+ result.closest[1] = c2p2;
2002
+ result.advancements[0] = 1;
2003
+ result.advancements[1] = c2t2;
2004
+ } else if (result.distance == dist1c1) {
2005
+ result.closest[0] = c2b;
2006
+ result.closest[1] = c1p1;
2007
+ result.advancements[0] = 0;
2008
+ result.advancements[1] = c1t1;
2009
+ } else /*if (result.distance == dist2c1)*/ {
2010
+ result.closest[0] = c2e;
2011
+ result.closest[1] = c1p2;
2012
+ result.advancements[0] = 1;
2013
+ result.advancements[1] = c1t2;
1970
2014
  }
1971
2015
 
1972
- public static RClosest lineLineClosest(RCommand c1, RCommand c2) {
1973
- RPoint c1b = new RPoint(c1.startPoint);
1974
- RPoint c1e = new RPoint(c1.endPoint);
1975
-
1976
- float c2t1 = closestAdvFrom(c2, c1b);
1977
- float c2t2 = closestAdvFrom(c2, c1e);
1978
-
1979
- RPoint c2p1 = c2.getPoint(c2t1);
1980
- RPoint c2p2 = c2.getPoint(c2t2);
1981
-
1982
- float dist1c2 = c2p1.dist(c1b);
1983
- float dist2c2 = c2p2.dist(c1e);
1984
-
1985
- RPoint c2b = new RPoint(c2.startPoint);
1986
- RPoint c2e = new RPoint(c2.endPoint);
1987
-
1988
- float c1t1 = closestAdvFrom(c1, c2b);
1989
- float c1t2 = closestAdvFrom(c1, c2e);
1990
-
1991
- RPoint c1p1 = c1.getPoint(c1t1);
1992
- RPoint c1p2 = c1.getPoint(c1t2);
1993
-
1994
- float dist1c1 = c1p1.dist(c2b);
1995
- float dist2c1 = c1p2.dist(c2e);
1996
-
1997
- RClosest result = new RClosest();
1998
- result.distance = Math.min(Math.min(dist1c2, dist2c2), Math.min(dist1c1, dist2c1));
1999
- result.closest = new RPoint[2];
2000
- result.advancements = new float[2];
2001
-
2002
- if (result.distance == dist1c2) {
2003
- result.closest[0] = c1b;
2004
- result.closest[1] = c2p1;
2005
- result.advancements[0] = 0;
2006
- result.advancements[1] = c2t1;
2007
- } else if (result.distance == dist2c2) {
2008
- result.closest[0] = c1e;
2009
- result.closest[1] = c2p2;
2010
- result.advancements[0] = 1;
2011
- result.advancements[1] = c2t2;
2012
- } else if (result.distance == dist1c1) {
2013
- result.closest[0] = c2b;
2014
- result.closest[1] = c1p1;
2015
- result.advancements[0] = 0;
2016
- result.advancements[1] = c1t1;
2017
- } else /*if (result.distance == dist2c1)*/ {
2018
- result.closest[0] = c2e;
2019
- result.closest[1] = c1p2;
2020
- result.advancements[0] = 1;
2021
- result.advancements[1] = c1t2;
2022
- }
2023
-
2024
2016
 
2025
- /*
2017
+ /*
2026
2018
  RPoint c = new RPoint(c2.startPoint);
2027
2019
  RPoint d = new RPoint(c2.endPoint);
2028
2020
 
@@ -2051,27 +2043,27 @@ public class RCommand extends RGeomElem {
2051
2043
  result.advancements[0] = t1;
2052
2044
  result.advancements[1] = t2;
2053
2045
  }
2054
- */
2055
- return result;
2056
- }
2046
+ */
2047
+ return result;
2048
+ }
2057
2049
 
2058
- public static RClosest lineQuadClosest(RCommand c1, RCommand c2) {
2059
- return null;
2060
- }
2050
+ public static RClosest lineQuadClosest(RCommand c1, RCommand c2) {
2051
+ return null;
2052
+ }
2061
2053
 
2062
- public static RClosest lineCubicClosest(RCommand c1, RCommand c2) {
2063
- return null;
2064
- }
2054
+ public static RClosest lineCubicClosest(RCommand c1, RCommand c2) {
2055
+ return null;
2056
+ }
2065
2057
 
2066
- public static RClosest quadQuadClosest(RCommand c1, RCommand c2) {
2067
- return null;
2068
- }
2058
+ public static RClosest quadQuadClosest(RCommand c1, RCommand c2) {
2059
+ return null;
2060
+ }
2069
2061
 
2070
- public static RClosest quadCubicClosest(RCommand c1, RCommand c2) {
2071
- return null;
2072
- }
2062
+ public static RClosest quadCubicClosest(RCommand c1, RCommand c2) {
2063
+ return null;
2064
+ }
2073
2065
 
2074
- public static RClosest cubicCubicClosest(RCommand c1, RCommand c2) {
2075
- return null;
2076
- }
2066
+ public static RClosest cubicCubicClosest(RCommand c1, RCommand c2) {
2067
+ return null;
2068
+ }
2077
2069
  }