geomerative 1.1.0-java → 2.0.0-java

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