geomerative 0.1.0-java

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