propane 3.4.0-java → 3.7.0.pre-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. checksums.yaml +4 -4
  2. data/.mvn/extensions.xml +1 -2
  3. data/.mvn/wrapper/MavenWrapperDownloader.java +2 -2
  4. data/.mvn/wrapper/maven-wrapper.properties +2 -2
  5. data/.travis.yml +2 -2
  6. data/CHANGELOG.md +12 -0
  7. data/Gemfile +2 -0
  8. data/README.md +17 -8
  9. data/Rakefile +10 -11
  10. data/bin/propane +3 -1
  11. data/lib/propane.rb +6 -4
  12. data/lib/propane/app.rb +20 -10
  13. data/lib/propane/creators/sketch_class.rb +7 -1
  14. data/lib/propane/creators/sketch_factory.rb +4 -2
  15. data/lib/propane/creators/sketch_writer.rb +1 -0
  16. data/lib/propane/helper_methods.rb +23 -24
  17. data/lib/propane/helpers/numeric.rb +2 -0
  18. data/lib/propane/helpers/version_error.rb +1 -0
  19. data/lib/propane/library.rb +5 -1
  20. data/lib/propane/library_loader.rb +2 -0
  21. data/lib/propane/native_folder.rb +10 -9
  22. data/lib/propane/native_loader.rb +3 -0
  23. data/lib/propane/runner.rb +14 -6
  24. data/lib/propane/version.rb +2 -1
  25. data/library/boids/boids.rb +21 -11
  26. data/library/color_group/color_group.rb +28 -0
  27. data/library/control_panel/control_panel.rb +8 -5
  28. data/library/dxf/dxf.rb +6 -0
  29. data/library/file_chooser/chooser.rb +10 -9
  30. data/library/file_chooser/file_chooser.rb +10 -9
  31. data/library/library_proxy/library_proxy.rb +2 -0
  32. data/library/net/net.rb +7 -0
  33. data/library/simplex_noise/simplex_noise.rb +2 -0
  34. data/library/slider/slider.rb +23 -22
  35. data/library/vector_utils/vector_utils.rb +4 -0
  36. data/library/video_event/video_event.rb +4 -1
  37. data/pom.rb +37 -36
  38. data/pom.xml +7 -7
  39. data/propane.gemspec +16 -12
  40. data/src/main/java/monkstone/ColorUtil.java +13 -1
  41. data/src/main/java/monkstone/MathToolModule.java +253 -203
  42. data/src/main/java/monkstone/PropaneLibrary.java +2 -2
  43. data/src/main/java/monkstone/fastmath/Deglut.java +1 -1
  44. data/src/main/java/monkstone/filechooser/Chooser.java +2 -1
  45. data/src/main/java/monkstone/noise/SimplexNoise.java +2 -2
  46. data/src/main/java/monkstone/slider/CustomHorizontalSlider.java +1 -1
  47. data/src/main/java/monkstone/slider/CustomVerticalSlider.java +1 -1
  48. data/src/main/java/monkstone/slider/SimpleHorizontalSlider.java +1 -1
  49. data/src/main/java/monkstone/slider/SimpleVerticalSlider.java +1 -1
  50. data/src/main/java/monkstone/slider/SliderBar.java +1 -1
  51. data/src/main/java/monkstone/slider/SliderGroup.java +1 -1
  52. data/src/main/java/monkstone/slider/WheelHandler.java +7 -6
  53. data/src/main/java/monkstone/vecmath/package-info.java +1 -1
  54. data/src/main/java/monkstone/vecmath/vec2/Vec2.java +1 -1
  55. data/src/main/java/monkstone/vecmath/vec3/Vec3.java +3 -3
  56. data/src/main/java/monkstone/videoevent/CaptureEvent.java +27 -0
  57. data/src/main/java/monkstone/videoevent/{VideoInterface.java → MovieEvent.java} +11 -27
  58. data/src/main/java/monkstone/videoevent/package-info.java +1 -1
  59. data/src/main/java/processing/awt/PGraphicsJava2D.java +781 -285
  60. data/src/main/java/processing/awt/PImageAWT.java +377 -0
  61. data/src/main/java/processing/awt/PShapeJava2D.java +56 -52
  62. data/src/main/java/processing/awt/PSurfaceAWT.java +309 -209
  63. data/src/main/java/processing/awt/ShimAWT.java +581 -0
  64. data/src/main/java/processing/core/PApplet.java +4510 -4503
  65. data/src/main/java/processing/core/PConstants.java +477 -447
  66. data/src/main/java/processing/core/PFont.java +914 -880
  67. data/src/main/java/processing/core/PGraphics.java +193 -177
  68. data/src/main/java/processing/core/PImage.java +611 -309
  69. data/src/main/java/processing/core/PMatrix.java +172 -159
  70. data/src/main/java/processing/core/PMatrix2D.java +478 -415
  71. data/src/main/java/processing/core/PMatrix3D.java +762 -735
  72. data/src/main/java/processing/core/PShape.java +2888 -2652
  73. data/src/main/java/processing/core/PShapeOBJ.java +97 -92
  74. data/src/main/java/processing/core/PShapeSVG.java +1705 -1490
  75. data/src/main/java/processing/core/PStyle.java +40 -37
  76. data/src/main/java/processing/core/PSurface.java +139 -97
  77. data/src/main/java/processing/core/PSurfaceNone.java +296 -218
  78. data/src/main/java/processing/core/PVector.java +997 -965
  79. data/src/main/java/processing/core/ThinkDifferent.java +15 -13
  80. data/src/main/java/processing/data/DoubleDict.java +756 -710
  81. data/src/main/java/processing/data/DoubleList.java +749 -696
  82. data/src/main/java/processing/data/FloatDict.java +748 -702
  83. data/src/main/java/processing/data/FloatList.java +751 -697
  84. data/src/main/java/processing/data/IntDict.java +720 -673
  85. data/src/main/java/processing/data/IntList.java +699 -633
  86. data/src/main/java/processing/data/JSONArray.java +931 -873
  87. data/src/main/java/processing/data/JSONObject.java +1262 -1165
  88. data/src/main/java/processing/data/JSONTokener.java +351 -341
  89. data/src/main/java/processing/data/LongDict.java +710 -663
  90. data/src/main/java/processing/data/LongList.java +701 -635
  91. data/src/main/java/processing/data/Sort.java +37 -41
  92. data/src/main/java/processing/data/StringDict.java +525 -486
  93. data/src/main/java/processing/data/StringList.java +626 -580
  94. data/src/main/java/processing/data/Table.java +3690 -3510
  95. data/src/main/java/processing/data/TableRow.java +182 -183
  96. data/src/main/java/processing/data/XML.java +957 -883
  97. data/src/main/java/processing/dxf/RawDXF.java +404 -0
  98. data/src/main/java/processing/event/Event.java +87 -67
  99. data/src/main/java/processing/event/KeyEvent.java +48 -41
  100. data/src/main/java/processing/event/MouseEvent.java +88 -113
  101. data/src/main/java/processing/event/TouchEvent.java +10 -6
  102. data/src/main/java/processing/javafx/PGraphicsFX2D.java +20 -345
  103. data/src/main/java/processing/javafx/PSurfaceFX.java +149 -121
  104. data/src/main/java/processing/net/Client.java +744 -0
  105. data/src/main/java/processing/net/Server.java +388 -0
  106. data/src/main/java/processing/opengl/FontTexture.java +289 -270
  107. data/src/main/java/processing/opengl/FrameBuffer.java +386 -364
  108. data/src/main/java/processing/opengl/LinePath.java +547 -500
  109. data/src/main/java/processing/opengl/LineStroker.java +588 -581
  110. data/src/main/java/processing/opengl/PGL.java +3047 -2914
  111. data/src/main/java/processing/opengl/PGraphics2D.java +408 -315
  112. data/src/main/java/processing/opengl/PGraphics3D.java +107 -72
  113. data/src/main/java/processing/opengl/PGraphicsOpenGL.java +12378 -12075
  114. data/src/main/java/processing/opengl/PJOGL.java +1753 -1670
  115. data/src/main/java/processing/opengl/PShader.java +1266 -1257
  116. data/src/main/java/processing/opengl/PShapeOpenGL.java +4678 -4580
  117. data/src/main/java/processing/opengl/PSurfaceJOGL.java +1114 -1027
  118. data/src/main/java/processing/opengl/Texture.java +1492 -1401
  119. data/src/main/java/processing/opengl/VertexBuffer.java +57 -55
  120. data/test/create_test.rb +21 -20
  121. data/test/deglut_spec_test.rb +4 -2
  122. data/test/helper_methods_test.rb +49 -20
  123. data/test/math_tool_test.rb +39 -32
  124. data/test/native_folder.rb +47 -0
  125. data/test/respond_to_test.rb +3 -2
  126. data/test/sketches/key_event.rb +2 -2
  127. data/test/sketches/library/my_library/my_library.rb +3 -0
  128. data/test/test_helper.rb +2 -0
  129. data/test/vecmath_spec_test.rb +35 -22
  130. data/vendors/Rakefile +33 -62
  131. metadata +56 -48
  132. data/src/main/java/processing/core/util/image/ImageLoadFacade.java +0 -161
  133. data/src/main/java/processing/core/util/image/ImageSaveFacade.java +0 -169
  134. data/src/main/java/processing/core/util/image/constants/TifConstants.java +0 -45
  135. data/src/main/java/processing/core/util/image/load/AwtImageLoadStrategy.java +0 -80
  136. data/src/main/java/processing/core/util/image/load/Base64StringImageLoadStrategy.java +0 -73
  137. data/src/main/java/processing/core/util/image/load/FallbackImageLoadStrategy.java +0 -70
  138. data/src/main/java/processing/core/util/image/load/ImageIoImageLoadStrategy.java +0 -132
  139. data/src/main/java/processing/core/util/image/load/ImageLoadStrategy.java +0 -48
  140. data/src/main/java/processing/core/util/image/load/ImageLoadUtil.java +0 -45
  141. data/src/main/java/processing/core/util/image/load/TgaImageLoadStrategy.java +0 -255
  142. data/src/main/java/processing/core/util/image/load/TiffImageLoadStrategy.java +0 -98
  143. data/src/main/java/processing/core/util/image/save/ImageSaveStrategy.java +0 -49
  144. data/src/main/java/processing/core/util/image/save/ImageSaveUtil.java +0 -48
  145. data/src/main/java/processing/core/util/image/save/ImageWriterImageSaveStrategy.java +0 -179
  146. data/src/main/java/processing/core/util/image/save/SaveImageException.java +0 -41
  147. data/src/main/java/processing/core/util/image/save/TgaImageSaveStrategy.java +0 -198
  148. data/src/main/java/processing/core/util/image/save/TiffImageSaveStrategy.java +0 -91
  149. data/src/main/java/processing/core/util/image/save/TiffNakedFilenameImageSaveStrategy.java +0 -57
  150. data/src/main/java/processing/core/util/io/InputFactory.java +0 -285
  151. data/src/main/java/processing/core/util/io/PathUtil.java +0 -109
  152. data/src/main/java/processing/opengl/shaders/LightVert-brcm.glsl +0 -154
  153. data/src/main/java/processing/opengl/shaders/LightVert-vc4.glsl +0 -154
  154. data/src/main/java/processing/opengl/shaders/TexLightVert-brcm.glsl +0 -160
  155. data/src/main/java/processing/opengl/shaders/TexLightVert-vc4.glsl +0 -160
@@ -3,9 +3,11 @@ package processing.data;
3
3
  import java.io.*;
4
4
  import java.util.HashMap;
5
5
  import java.util.Iterator;
6
+ import java.util.NoSuchElementException;
6
7
 
7
8
  import processing.core.PApplet;
8
9
 
10
+
9
11
  /**
10
12
  * A simple table class to use a String as a lookup for an float value.
11
13
  *
@@ -15,787 +17,831 @@ import processing.core.PApplet;
15
17
  */
16
18
  public class FloatDict {
17
19
 
18
- /**
19
- * Number of elements in the table
20
- */
21
- protected int count;
22
-
23
- protected String[] keys;
24
- protected float[] values;
25
-
26
- /**
27
- * Internal implementation for faster lookups
28
- */
29
- private HashMap<String, Integer> indices = new HashMap<>();
30
-
31
- public FloatDict() {
32
- count = 0;
33
- keys = new String[10];
34
- values = new float[10];
35
- }
36
-
37
- /**
38
- * Create a new lookup with a specific size. This is more efficient than not
39
- * specifying a size. Use it when you know the rough size of the thing
40
- * you're creating.
41
- *
42
- * @nowebref
43
- */
44
- public FloatDict(int length) {
45
- count = 0;
46
- keys = new String[length];
47
- values = new float[length];
48
- }
49
-
50
- /**
51
- * Read a set of entries from a Reader that has each key/value pair on a
52
- * single line, separated by a tab.
53
- *
54
- * @nowebref
55
- */
56
- public FloatDict(BufferedReader reader) {
57
- String[] lines = PApplet.loadStrings(reader);
58
- keys = new String[lines.length];
59
- values = new float[lines.length];
60
-
61
- for (int i = 0; i < lines.length; i++) {
62
- String[] pieces = PApplet.split(lines[i], '\t');
63
- if (pieces.length == 2) {
64
- keys[count] = pieces[0];
65
- values[count] = PApplet.parseFloat(pieces[1]);
66
- indices.put(pieces[0], count);
67
- count++;
68
- }
69
- }
20
+ /** Number of elements in the table */
21
+ protected int count;
22
+
23
+ protected String[] keys;
24
+ protected float[] values;
25
+
26
+ /** Internal implementation for faster lookups */
27
+ private HashMap<String, Integer> indices = new HashMap<>();
28
+
29
+
30
+ public FloatDict() {
31
+ count = 0;
32
+ keys = new String[10];
33
+ values = new float[10];
34
+ }
35
+
36
+
37
+ /**
38
+ * Create a new lookup with a specific size. This is more efficient than not
39
+ * specifying a size. Use it when you know the rough size of the thing you're creating.
40
+ *
41
+ * @nowebref
42
+ */
43
+ public FloatDict(int length) {
44
+ count = 0;
45
+ keys = new String[length];
46
+ values = new float[length];
47
+ }
48
+
49
+
50
+ /**
51
+ * Read a set of entries from a Reader that has each key/value pair on
52
+ * a single line, separated by a tab.
53
+ *
54
+ * @nowebref
55
+ */
56
+ public FloatDict(BufferedReader reader) {
57
+ String[] lines = PApplet.loadStrings(reader);
58
+ keys = new String[lines.length];
59
+ values = new float[lines.length];
60
+
61
+ for (int i = 0; i < lines.length; i++) {
62
+ String[] pieces = PApplet.split(lines[i], '\t');
63
+ if (pieces.length == 2) {
64
+ keys[count] = pieces[0];
65
+ values[count] = PApplet.parseFloat(pieces[1]);
66
+ indices.put(pieces[0], count);
67
+ count++;
68
+ }
70
69
  }
70
+ }
71
71
 
72
- /**
73
- * @nowebref
74
- */
75
- public FloatDict(String[] keys, float[] values) {
76
- if (keys.length != values.length) {
77
- throw new IllegalArgumentException("key and value arrays must be the same length");
78
- }
79
- this.keys = keys;
80
- this.values = values;
81
- count = keys.length;
82
- for (int i = 0; i < count; i++) {
83
- indices.put(keys[i], i);
84
- }
85
- }
86
72
 
87
- /**
88
- * Constructor to allow (more intuitive) inline initialization, e.g.:
89
- * <pre>
90
- * new FloatDict(new Object[][] {
91
- * { "key1", 1 },
92
- * { "key2", 2 }
93
- * });
94
- * </pre>
95
- */
96
- public FloatDict(Object[][] pairs) {
97
- count = pairs.length;
98
- this.keys = new String[count];
99
- this.values = new float[count];
100
- for (int i = 0; i < count; i++) {
101
- keys[i] = (String) pairs[i][0];
102
- values[i] = (Float) pairs[i][1];
103
- indices.put(keys[i], i);
104
- }
73
+ /**
74
+ * @nowebref
75
+ */
76
+ public FloatDict(String[] keys, float[] values) {
77
+ if (keys.length != values.length) {
78
+ throw new IllegalArgumentException("key and value arrays must be the same length");
105
79
  }
80
+ this.keys = keys;
81
+ this.values = values;
82
+ count = keys.length;
83
+ for (int i = 0; i < count; i++) {
84
+ indices.put(keys[i], i);
85
+ }
86
+ }
87
+
106
88
 
107
- /**
108
- * @webref floatdict:method
109
- * @brief Returns the number of key/value pairs
110
- */
111
- public int size() {
112
- return count;
89
+ /**
90
+ * Constructor to allow (more intuitive) inline initialization, e.g.:
91
+ * <pre>
92
+ * new FloatDict(new Object[][] {
93
+ * { "key1", 1 },
94
+ * { "key2", 2 }
95
+ * });
96
+ * </pre>
97
+ */
98
+ public FloatDict(Object[][] pairs) {
99
+ count = pairs.length;
100
+ this.keys = new String[count];
101
+ this.values = new float[count];
102
+ for (int i = 0; i < count; i++) {
103
+ keys[i] = (String) pairs[i][0];
104
+ values[i] = (Float) pairs[i][1];
105
+ indices.put(keys[i], i);
113
106
  }
107
+ }
114
108
 
115
- /**
116
- * Resize the internal data, this can only be used to shrink the list.
117
- * Helpful for situations like sorting and then grabbing the top 50 entries.
118
- */
119
- public void resize(int length) {
120
- if (length == count) {
121
- return;
122
- }
123
109
 
124
- if (length > count) {
125
- throw new IllegalArgumentException("resize() can only be used to shrink the dictionary");
126
- }
127
- if (length < 1) {
128
- throw new IllegalArgumentException("resize(" + length + ") is too small, use 1 or higher");
129
- }
110
+ /**
111
+ * @webref floatdict:method
112
+ * @brief Returns the number of key/value pairs
113
+ */
114
+ public int size() {
115
+ return count;
116
+ }
130
117
 
131
- String[] newKeys = new String[length];
132
- float[] newValues = new float[length];
133
- PApplet.arrayCopy(keys, newKeys, length);
134
- PApplet.arrayCopy(values, newValues, length);
135
- keys = newKeys;
136
- values = newValues;
137
- count = length;
138
- resetIndices();
139
- }
140
-
141
- /**
142
- * Remove all entries.
143
- *
144
- * @webref floatdict:method
145
- * @brief Remove all entries
146
- */
147
- public void clear() {
148
- count = 0;
149
- indices = new HashMap<>();
150
- }
151
-
152
- private void resetIndices() {
153
- indices = new HashMap<>(count);
154
- for (int i = 0; i < count; i++) {
155
- indices.put(keys[i], i);
156
- }
118
+
119
+ /**
120
+ * Resize the internal data, this can only be used to shrink the list.
121
+ * Helpful for situations like sorting and then grabbing the top 50 entries.
122
+ */
123
+ public void resize(int length) {
124
+ if (length == count) return;
125
+
126
+ if (length > count) {
127
+ throw new IllegalArgumentException("resize() can only be used to shrink the dictionary");
128
+ }
129
+ if (length < 1) {
130
+ throw new IllegalArgumentException("resize(" + length + ") is too small, use 1 or higher");
157
131
  }
158
132
 
159
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
160
- public class Entry {
133
+ String[] newKeys = new String[length];
134
+ float[] newValues = new float[length];
135
+ PApplet.arrayCopy(keys, newKeys, length);
136
+ PApplet.arrayCopy(values, newValues, length);
137
+ keys = newKeys;
138
+ values = newValues;
139
+ count = length;
140
+ resetIndices();
141
+ }
161
142
 
162
- public String key;
163
- public float value;
164
143
 
165
- Entry(String key, float value) {
166
- this.key = key;
167
- this.value = value;
168
- }
169
- }
144
+ /**
145
+ * Remove all entries.
146
+ *
147
+ * @webref floatdict:method
148
+ * @brief Remove all entries
149
+ */
150
+ public void clear() {
151
+ count = 0;
152
+ indices = new HashMap<>();
153
+ }
170
154
 
171
- public Iterable<Entry> entries() {
172
- return new Iterable<Entry>() {
173
155
 
174
- public Iterator<Entry> iterator() {
175
- return entryIterator();
176
- }
177
- };
156
+ private void resetIndices() {
157
+ indices = new HashMap<>(count);
158
+ for (int i = 0; i < count; i++) {
159
+ indices.put(keys[i], i);
178
160
  }
161
+ }
179
162
 
180
- public Iterator<Entry> entryIterator() {
181
- return new Iterator<Entry>() {
182
- int index = -1;
183
163
 
184
- public void remove() {
185
- removeIndex(index);
186
- index--;
187
- }
164
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
188
165
 
189
- public Entry next() {
190
- ++index;
191
- Entry e = new Entry(keys[index], values[index]);
192
- return e;
193
- }
194
166
 
195
- public boolean hasNext() {
196
- return index + 1 < size();
197
- }
198
- };
199
- }
167
+ public class Entry {
168
+ public String key;
169
+ public float value;
200
170
 
201
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
202
- public String key(int index) {
203
- return keys[index];
171
+ Entry(String key, float value) {
172
+ this.key = key;
173
+ this.value = value;
204
174
  }
175
+ }
205
176
 
206
- protected void crop() {
207
- if (count != keys.length) {
208
- keys = PApplet.subset(keys, 0, count);
209
- values = PApplet.subset(values, 0, count);
210
- }
211
- }
212
177
 
213
- public Iterable<String> keys() {
214
- return new Iterable<String>() {
178
+ public Iterable<Entry> entries() {
179
+ return new Iterable<Entry>() {
215
180
 
216
- @Override
217
- public Iterator<String> iterator() {
218
- return keyIterator();
219
- }
220
- };
221
- }
181
+ public Iterator<Entry> iterator() {
182
+ return entryIterator();
183
+ }
184
+ };
185
+ }
222
186
 
223
- // Use this to iterate when you want to be able to remove elements along the way
224
- public Iterator<String> keyIterator() {
225
- return new Iterator<String>() {
226
- int index = -1;
227
187
 
228
- public void remove() {
229
- removeIndex(index);
230
- index--;
231
- }
188
+ public Iterator<Entry> entryIterator() {
189
+ return new Iterator<Entry>() {
190
+ int index = -1;
232
191
 
233
- public String next() {
234
- return key(++index);
235
- }
192
+ public void remove() {
193
+ removeIndex(index);
194
+ index--;
195
+ }
236
196
 
237
- public boolean hasNext() {
238
- return index + 1 < size();
239
- }
240
- };
241
- }
197
+ public Entry next() {
198
+ ++index;
199
+ Entry e = new Entry(keys[index], values[index]);
200
+ return e;
201
+ }
242
202
 
243
- /**
244
- * Return a copy of the internal keys array. This array can be modified.
245
- *
246
- * @webref floatdict:method
247
- * @brief Return a copy of the internal keys array
248
- */
249
- public String[] keyArray() {
250
- crop();
251
- return keyArray(null);
252
- }
203
+ public boolean hasNext() {
204
+ return index+1 < size();
205
+ }
206
+ };
207
+ }
253
208
 
254
- public String[] keyArray(String[] outgoing) {
255
- if (outgoing == null || outgoing.length != count) {
256
- outgoing = new String[count];
257
- }
258
- System.arraycopy(keys, 0, outgoing, 0, count);
259
- return outgoing;
260
- }
261
209
 
262
- public float value(int index) {
263
- return values[index];
264
- }
210
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
265
211
 
266
- /**
267
- * @webref floatdict:method
268
- * @brief Return the internal array being used to store the values
269
- */
270
- public Iterable<Float> values() {
271
- return new Iterable<Float>() {
272
212
 
273
- @Override
274
- public Iterator<Float> iterator() {
275
- return valueIterator();
276
- }
277
- };
213
+ public String key(int index) {
214
+ return keys[index];
215
+ }
216
+
217
+
218
+ protected void crop() {
219
+ if (count != keys.length) {
220
+ keys = PApplet.subset(keys, 0, count);
221
+ values = PApplet.subset(values, 0, count);
278
222
  }
223
+ }
279
224
 
280
- public Iterator<Float> valueIterator() {
281
- return new Iterator<Float>() {
282
- int index = -1;
283
225
 
284
- public void remove() {
285
- removeIndex(index);
286
- index--;
287
- }
226
+ public Iterable<String> keys() {
227
+ return new Iterable<String>() {
288
228
 
289
- public Float next() {
290
- return value(++index);
291
- }
229
+ @Override
230
+ public Iterator<String> iterator() {
231
+ return keyIterator();
232
+ }
233
+ };
234
+ }
292
235
 
293
- public boolean hasNext() {
294
- return index + 1 < size();
295
- }
296
- };
297
- }
298
-
299
- /**
300
- * Create a new array and copy each of the values into it.
301
- *
302
- * @webref floatdict:method
303
- * @brief Create a new array and copy each of the values into it
304
- */
305
- public float[] valueArray() {
306
- crop();
307
- return valueArray(null);
308
- }
309
-
310
- /**
311
- * Fill an already-allocated array with the values (more efficient than
312
- * creating a new array each time). If 'array' is null, or not the same size
313
- * as the number of values, a new array will be allocated and returned.
314
- */
315
- public float[] valueArray(float[] array) {
316
- if (array == null || array.length != size()) {
317
- array = new float[count];
318
- }
319
- System.arraycopy(values, 0, array, 0, count);
320
- return array;
321
- }
322
-
323
- /**
324
- * Return a value for the specified key.
325
- *
326
- * @webref floatdict:method
327
- * @brief Return a value for the specified key
328
- */
329
- public float get(String key) {
330
- int index = index(key);
331
- if (index == -1) {
332
- throw new IllegalArgumentException("No key named '" + key + "'");
333
- }
334
- return values[index];
335
- }
336
236
 
337
- public float get(String key, float alternate) {
338
- int index = index(key);
339
- if (index == -1) {
340
- return alternate;
341
- }
342
- return values[index];
343
- }
237
+ // Use this to iterate when you want to be able to remove elements along the way
238
+ public Iterator<String> keyIterator() {
239
+ return new Iterator<String>() {
240
+ int index = -1;
344
241
 
345
- /**
346
- * @webref floatdict:method
347
- * @brief Create a new key/value pair or change the value of one
348
- */
349
- public void set(String key, float amount) {
350
- int index = index(key);
351
- if (index == -1) {
352
- create(key, amount);
353
- } else {
354
- values[index] = amount;
355
- }
356
- }
242
+ public void remove() {
243
+ removeIndex(index);
244
+ index--;
245
+ }
357
246
 
358
- public void setIndex(int index, String key, float value) {
359
- if (index < 0 || index >= count) {
360
- throw new ArrayIndexOutOfBoundsException(index);
361
- }
362
- keys[index] = key;
363
- values[index] = value;
364
- }
365
-
366
- /**
367
- * @webref floatdict:method
368
- * @brief Check if a key is a part of the data structure
369
- */
370
- public boolean hasKey(String key) {
371
- return index(key) != -1;
372
- }
373
-
374
- /**
375
- * @webref floatdict:method
376
- * @brief Add to a value
377
- */
378
- public void add(String key, float amount) {
379
- int index = index(key);
380
- if (index == -1) {
381
- create(key, amount);
382
- } else {
383
- values[index] += amount;
384
- }
385
- }
247
+ public String next() {
248
+ return key(++index);
249
+ }
386
250
 
387
- /**
388
- * @webref floatdict:method
389
- * @brief Subtract from a value
390
- */
391
- public void sub(String key, float amount) {
392
- add(key, -amount);
393
- }
251
+ public boolean hasNext() {
252
+ return index+1 < size();
253
+ }
254
+ };
255
+ }
394
256
 
395
- /**
396
- * @webref floatdict:method
397
- * @brief Multiply a value
398
- */
399
- public void mult(String key, float amount) {
400
- int index = index(key);
401
- if (index != -1) {
402
- values[index] *= amount;
403
- }
404
- }
405
257
 
406
- /**
407
- * @webref floatdict:method
408
- * @brief Divide a value
409
- */
410
- public void div(String key, float amount) {
411
- int index = index(key);
412
- if (index != -1) {
413
- values[index] /= amount;
414
- }
415
- }
258
+ /**
259
+ * Return a copy of the internal keys array. This array can be modified.
260
+ *
261
+ * @webref floatdict:method
262
+ * @brief Return a copy of the internal keys array
263
+ */
264
+ public String[] keyArray() {
265
+ crop();
266
+ return keyArray(null);
267
+ }
416
268
 
417
- private void checkMinMax(String functionName) {
418
- if (count == 0) {
419
- String msg
420
- = String.format("Cannot use %s() on an empty %s.",
421
- functionName, getClass().getSimpleName());
422
- throw new RuntimeException(msg);
423
- }
269
+
270
+ public String[] keyArray(String[] outgoing) {
271
+ if (outgoing == null || outgoing.length != count) {
272
+ outgoing = new String[count];
424
273
  }
274
+ System.arraycopy(keys, 0, outgoing, 0, count);
275
+ return outgoing;
276
+ }
425
277
 
426
- /**
427
- * @webref floatlist:method
428
- * @brief Return the smallest value
429
- */
430
- public int minIndex() {
431
- //checkMinMax("minIndex");
432
- if (count == 0) {
433
- return -1;
434
- }
435
278
 
436
- // Will still return NaN if there are 1 or more entries, and they're all NaN
437
- float m = Float.NaN;
438
- int mi = -1;
439
- for (int i = 0; i < count; i++) {
440
- // find one good value to start
441
- if (values[i] == values[i]) {
442
- m = values[i];
443
- mi = i;
444
-
445
- // calculate the rest
446
- for (int j = i + 1; j < count; j++) {
447
- float d = values[j];
448
- if ((d == d) && (d < m)) {
449
- m = values[j];
450
- mi = j;
451
- }
452
- }
453
- break;
454
- }
455
- }
456
- return mi;
457
- }
279
+ public float value(int index) {
280
+ return values[index];
281
+ }
282
+
458
283
 
459
- // return the key for the minimum value
460
- public String minKey() {
461
- checkMinMax("minKey");
462
- int index = minIndex();
463
- if (index == -1) {
464
- return null;
465
- }
466
- return keys[index];
467
- }
284
+ /**
285
+ * @webref floatdict:method
286
+ * @brief Return the internal array being used to store the values
287
+ */
288
+ public Iterable<Float> values() {
289
+ return new Iterable<Float>() {
468
290
 
469
- // return the minimum value, or throw an error if there are no values
470
- public float minValue() {
471
- checkMinMax("minValue");
472
- int index = minIndex();
473
- if (index == -1) {
474
- return Float.NaN;
475
- }
476
- return values[index];
477
- }
478
-
479
- /**
480
- * @webref floatlist:method
481
- * @brief Return the largest value
482
- */
483
- // The index of the entry that has the max value. Reference above is incorrect.
484
- public int maxIndex() {
485
- //checkMinMax("maxIndex");
486
- if (count == 0) {
487
- return -1;
488
- }
489
- // Will still return NaN if there is 1 or more entries, and they're all NaN
490
- float m = Float.NaN;
491
- int mi = -1;
492
- for (int i = 0; i < count; i++) {
493
- // find one good value to start
494
- if (values[i] == values[i]) {
495
- m = values[i];
496
- mi = i;
497
-
498
- // calculate the rest
499
- for (int j = i + 1; j < count; j++) {
500
- float d = values[j];
501
- if (!Float.isNaN(d) && (d > m)) {
502
- m = values[j];
503
- mi = j;
504
- }
505
- }
506
- break;
507
- }
508
- }
509
- return mi;
510
- }
291
+ @Override
292
+ public Iterator<Float> iterator() {
293
+ return valueIterator();
294
+ }
295
+ };
296
+ }
511
297
 
512
- /**
513
- * The key for a max value; null if empty or everything is NaN (no max).
514
- */
515
- public String maxKey() {
516
- //checkMinMax("maxKey");
517
- int index = maxIndex();
518
- if (index == -1) {
519
- return null;
520
- }
521
- return keys[index];
522
- }
523
298
 
524
- /**
525
- * The max value. (Or NaN if no entries or they're all NaN.)
526
- */
527
- public float maxValue() {
528
- //checkMinMax("maxValue");
529
- int index = maxIndex();
530
- if (index == -1) {
531
- return Float.NaN;
532
- }
533
- return values[index];
534
- }
299
+ public Iterator<Float> valueIterator() {
300
+ return new Iterator<Float>() {
301
+ int index = -1;
535
302
 
536
- public float sum() {
537
- double amount = sumDouble();
538
- if (amount > Float.MAX_VALUE) {
539
- throw new RuntimeException("sum() exceeds " + Float.MAX_VALUE + ", use sumDouble()");
540
- }
541
- if (amount < -Float.MAX_VALUE) {
542
- throw new RuntimeException("sum() lower than " + -Float.MAX_VALUE + ", use sumDouble()");
543
- }
544
- return (float) amount;
545
- }
303
+ public void remove() {
304
+ removeIndex(index);
305
+ index--;
306
+ }
546
307
 
547
- public double sumDouble() {
548
- double sum = 0;
549
- for (int i = 0; i < count; i++) {
550
- sum += values[i];
551
- }
552
- return sum;
553
- }
308
+ public Float next() {
309
+ return value(++index);
310
+ }
554
311
 
555
- public int index(String what) {
556
- Integer found = indices.get(what);
557
- return (found == null) ? -1 : found.intValue();
312
+ public boolean hasNext() {
313
+ return index+1 < size();
314
+ }
315
+ };
316
+ }
317
+
318
+
319
+ /**
320
+ * Create a new array and copy each of the values into it.
321
+ *
322
+ * @webref floatdict:method
323
+ * @brief Create a new array and copy each of the values into it
324
+ */
325
+ public float[] valueArray() {
326
+ crop();
327
+ return valueArray(null);
328
+ }
329
+
330
+
331
+ /**
332
+ * Fill an already-allocated array with the values (more efficient than
333
+ * creating a new array each time). If 'array' is null, or not the same
334
+ * size as the number of values, a new array will be allocated and returned.
335
+ */
336
+ public float[] valueArray(float[] array) {
337
+ if (array == null || array.length != size()) {
338
+ array = new float[count];
339
+ }
340
+ System.arraycopy(values, 0, array, 0, count);
341
+ return array;
342
+ }
343
+
344
+
345
+ /**
346
+ * Return a value for the specified key.
347
+ *
348
+ * @webref floatdict:method
349
+ * @brief Return a value for the specified key
350
+ */
351
+ public float get(String key) {
352
+ int index = index(key);
353
+ if (index == -1) {
354
+ throw new IllegalArgumentException("No key named '" + key + "'");
355
+ }
356
+ return values[index];
357
+ }
358
+
359
+
360
+ public float get(String key, float alternate) {
361
+ int index = index(key);
362
+ if (index == -1) {
363
+ return alternate;
364
+ }
365
+ return values[index];
366
+ }
367
+
368
+
369
+ /**
370
+ * @webref floatdict:method
371
+ * @brief Create a new key/value pair or change the value of one
372
+ */
373
+ public void set(String key, float amount) {
374
+ int index = index(key);
375
+ if (index == -1) {
376
+ create(key, amount);
377
+ } else {
378
+ values[index] = amount;
379
+ }
380
+ }
381
+
382
+
383
+ public void setIndex(int index, String key, float value) {
384
+ if (index < 0 || index >= count) {
385
+ throw new ArrayIndexOutOfBoundsException(index);
386
+ }
387
+ keys[index] = key;
388
+ values[index] = value;
389
+ }
390
+
391
+
392
+ /**
393
+ * @webref floatdict:method
394
+ * @brief Check if a key is a part of the data structure
395
+ */
396
+ public boolean hasKey(String key) {
397
+ return index(key) != -1;
398
+ }
399
+
400
+
401
+ /**
402
+ * @webref floatdict:method
403
+ * @brief Add to a value
404
+ */
405
+ public void add(String key, float amount) {
406
+ int index = index(key);
407
+ if (index == -1) {
408
+ create(key, amount);
409
+ } else {
410
+ values[index] += amount;
411
+ }
412
+ }
413
+
414
+
415
+ /**
416
+ * @webref floatdict:method
417
+ * @brief Subtract from a value
418
+ */
419
+ public void sub(String key, float amount) {
420
+ add(key, -amount);
421
+ }
422
+
423
+
424
+ /**
425
+ * @webref floatdict:method
426
+ * @brief Multiply a value
427
+ */
428
+ public void mult(String key, float amount) {
429
+ int index = index(key);
430
+ if (index != -1) {
431
+ values[index] *= amount;
432
+ }
433
+ }
434
+
435
+
436
+ /**
437
+ * @webref floatdict:method
438
+ * @brief Divide a value
439
+ */
440
+ public void div(String key, float amount) {
441
+ int index = index(key);
442
+ if (index != -1) {
443
+ values[index] /= amount;
444
+ }
445
+ }
446
+
447
+
448
+ private void checkMinMax(String functionName) {
449
+ if (count == 0) {
450
+ String msg =
451
+ String.format("Cannot use %s() on an empty %s.",
452
+ functionName, getClass().getSimpleName());
453
+ throw new RuntimeException(msg);
454
+ }
455
+ }
456
+
457
+
458
+ /**
459
+ * @webref floatlist:method
460
+ * @brief Return the smallest value
461
+ */
462
+ public int minIndex() {
463
+ //checkMinMax("minIndex");
464
+ if (count == 0) return -1;
465
+
466
+ // Will still return NaN if there are 1 or more entries, and they're all NaN
467
+ float m = Float.NaN;
468
+ int mi = -1;
469
+ for (int i = 0; i < count; i++) {
470
+ // find one good value to start
471
+ if (values[i] == values[i]) {
472
+ m = values[i];
473
+ mi = i;
474
+
475
+ // calculate the rest
476
+ for (int j = i+1; j < count; j++) {
477
+ float d = values[j];
478
+ if ((d == d) && (d < m)) {
479
+ m = values[j];
480
+ mi = j;
481
+ }
482
+ }
483
+ break;
484
+ }
485
+ }
486
+ return mi;
487
+ }
488
+
489
+
490
+ // return the key for the minimum value
491
+ public String minKey() {
492
+ checkMinMax("minKey");
493
+ int index = minIndex();
494
+ if (index == -1) {
495
+ return null;
496
+ }
497
+ return keys[index];
498
+ }
499
+
500
+
501
+ // return the minimum value, or throw an error if there are no values
502
+ public float minValue() {
503
+ checkMinMax("minValue");
504
+ int index = minIndex();
505
+ if (index == -1) {
506
+ return Float.NaN;
558
507
  }
508
+ return values[index];
509
+ }
559
510
 
560
- protected void create(String what, float much) {
561
- if (count == keys.length) {
562
- keys = PApplet.expand(keys);
563
- values = PApplet.expand(values);
564
- }
565
- indices.put(what, Integer.valueOf(count));
566
- keys[count] = what;
567
- values[count] = much;
568
- count++;
511
+
512
+ /**
513
+ * @webref floatlist:method
514
+ * @brief Return the largest value
515
+ */
516
+ // The index of the entry that has the max value. Reference above is incorrect.
517
+ public int maxIndex() {
518
+ //checkMinMax("maxIndex");
519
+ if (count == 0) {
520
+ return -1;
569
521
  }
522
+ // Will still return NaN if there is 1 or more entries, and they're all NaN
523
+ float m = Float.NaN;
524
+ int mi = -1;
525
+ for (int i = 0; i < count; i++) {
526
+ // find one good value to start
527
+ if (values[i] == values[i]) {
528
+ m = values[i];
529
+ mi = i;
530
+
531
+ // calculate the rest
532
+ for (int j = i+1; j < count; j++) {
533
+ float d = values[j];
534
+ if (!Float.isNaN(d) && (d > m)) {
535
+ m = values[j];
536
+ mi = j;
537
+ }
538
+ }
539
+ break;
540
+ }
541
+ }
542
+ return mi;
543
+ }
544
+
545
+
546
+ /** The key for a max value; null if empty or everything is NaN (no max). */
547
+ public String maxKey() {
548
+ //checkMinMax("maxKey");
549
+ int index = maxIndex();
550
+ if (index == -1) {
551
+ return null;
552
+ }
553
+ return keys[index];
554
+ }
555
+
556
+
557
+ /** The max value. (Or NaN if no entries or they're all NaN.) */
558
+ public float maxValue() {
559
+ //checkMinMax("maxValue");
560
+ int index = maxIndex();
561
+ if (index == -1) {
562
+ return Float.NaN;
563
+ }
564
+ return values[index];
565
+ }
566
+
567
+
568
+ public float sum() {
569
+ double amount = sumDouble();
570
+ if (amount > Float.MAX_VALUE) {
571
+ throw new RuntimeException("sum() exceeds " + Float.MAX_VALUE + ", use sumDouble()");
572
+ }
573
+ if (amount < -Float.MAX_VALUE) {
574
+ throw new RuntimeException("sum() lower than " + -Float.MAX_VALUE + ", use sumDouble()");
575
+ }
576
+ return (float) amount;
577
+ }
570
578
 
571
- /**
572
- * @webref floatdict:method
573
- * @brief Remove a key/value pair
574
- */
575
- public int remove(String key) {
576
- int index = index(key);
577
- if (index != -1) {
578
- removeIndex(index);
579
- }
580
- return index;
579
+
580
+ public double sumDouble() {
581
+ double sum = 0;
582
+ for (int i = 0; i < count; i++) {
583
+ sum += values[i];
581
584
  }
585
+ return sum;
586
+ }
582
587
 
583
- public String removeIndex(int index) {
584
- if (index < 0 || index >= count) {
585
- throw new ArrayIndexOutOfBoundsException(index);
586
- }
587
- String key = keys[index];
588
- //System.out.println("index is " + which + " and " + keys[which]);
589
- indices.remove(keys[index]);
590
- for (int i = index; i < count - 1; i++) {
591
- keys[i] = keys[i + 1];
592
- values[i] = values[i + 1];
593
- indices.put(keys[i], i);
594
- }
595
- count--;
596
- keys[count] = null;
597
- values[count] = 0;
598
- return key;
588
+
589
+ public int index(String what) {
590
+ Integer found = indices.get(what);
591
+ return (found == null) ? -1 : found.intValue();
592
+ }
593
+
594
+
595
+ protected void create(String what, float much) {
596
+ if (count == keys.length) {
597
+ keys = PApplet.expand(keys);
598
+ values = PApplet.expand(values);
599
599
  }
600
+ indices.put(what, Integer.valueOf(count));
601
+ keys[count] = what;
602
+ values[count] = much;
603
+ count++;
604
+ }
600
605
 
601
- public void swap(int a, int b) {
602
- String tkey = keys[a];
603
- float tvalue = values[a];
604
- keys[a] = keys[b];
605
- values[a] = values[b];
606
- keys[b] = tkey;
607
- values[b] = tvalue;
608
606
 
609
- // indices.put(keys[a], Integer.valueOf(a));
610
- // indices.put(keys[b], Integer.valueOf(b));
607
+ /**
608
+ * @webref floatdict:method
609
+ * @brief Remove a key/value pair
610
+ */
611
+ public float remove(String key) {
612
+ int index = index(key);
613
+ if (index == -1) {
614
+ throw new NoSuchElementException("'" + key + "' not found");
615
+ }
616
+ float value = values[index];
617
+ removeIndex(index);
618
+ return value;
619
+ }
620
+
621
+
622
+ public float removeIndex(int index) {
623
+ if (index < 0 || index >= count) {
624
+ throw new ArrayIndexOutOfBoundsException(index);
611
625
  }
626
+ float value = values[index];
627
+ indices.remove(keys[index]);
628
+ for (int i = index; i < count-1; i++) {
629
+ keys[i] = keys[i+1];
630
+ values[i] = values[i+1];
631
+ indices.put(keys[i], i);
632
+ }
633
+ count--;
634
+ keys[count] = null;
635
+ values[count] = 0;
636
+ return value;
637
+ }
612
638
 
613
- /**
614
- * Sort the keys alphabetically (ignoring case). Uses the value as a
615
- * tie-breaker (only really possible with a key that has a case change).
616
- *
617
- * @webref floatdict:method
618
- * @brief Sort the keys alphabetically
619
- */
620
- public void sortKeys() {
621
- sortImpl(true, false, true);
622
- }
623
-
624
- /**
625
- * @webref floatdict:method
626
- * @brief Sort the keys alphabetically in reverse
627
- */
628
- public void sortKeysReverse() {
629
- sortImpl(true, true, true);
630
- }
631
-
632
- /**
633
- * Sort by values in descending order (largest value will be at [0]).
634
- *
635
- * @webref floatdict:method
636
- * @brief Sort by values in ascending order
637
- */
638
- public void sortValues() {
639
- sortValues(true);
640
- }
641
-
642
- /**
643
- * Set true to ensure that the order returned is identical. Slightly slower
644
- * because the tie-breaker for identical values compares the keys.
645
- *
646
- * @param stable
647
- */
648
- public void sortValues(boolean stable) {
649
- sortImpl(false, false, stable);
650
- }
651
-
652
- /**
653
- * @webref floatdict:method
654
- * @brief Sort by values in descending order
655
- */
656
- public void sortValuesReverse() {
657
- sortValuesReverse(true);
658
- }
659
-
660
- public void sortValuesReverse(boolean stable) {
661
- sortImpl(false, true, stable);
662
- }
663
-
664
- protected void sortImpl(final boolean useKeys, final boolean reverse,
665
- final boolean stable) {
666
- Sort s = new Sort() {
667
- @Override
668
- public int size() {
669
- if (useKeys) {
670
- return count; // don't worry about NaN values
671
-
672
- } else if (count == 0) { // skip the NaN check, it'll AIOOBE
673
- return 0;
674
-
675
- } else { // first move NaN values to the end of the list
676
- int right = count - 1;
677
- while (values[right] != values[right]) {
678
- right--;
679
- if (right == -1) {
680
- return 0; // all values are NaN
681
- }
682
- }
683
- for (int i = right; i >= 0; --i) {
684
- if (Float.isNaN(values[i])) {
685
- swap(i, right);
686
- --right;
687
- }
688
- }
689
- return right + 1;
690
- }
691
- }
692
639
 
693
- @Override
694
- public int compare(int a, int b) {
695
- float diff = 0;
696
- if (useKeys) {
697
- diff = keys[a].compareToIgnoreCase(keys[b]);
698
- if (diff == 0) {
699
- diff = values[a] - values[b];
700
- }
701
- } else { // sort values
702
- diff = values[a] - values[b];
703
- if (diff == 0 && stable) {
704
- diff = keys[a].compareToIgnoreCase(keys[b]);
705
- }
706
- }
707
- if (diff == 0) {
708
- return 0;
709
- } else if (reverse) {
710
- return diff < 0 ? 1 : -1;
711
- } else {
712
- return diff < 0 ? -1 : 1;
713
- }
714
- }
640
+ public void swap(int a, int b) {
641
+ String tkey = keys[a];
642
+ float tvalue = values[a];
643
+ keys[a] = keys[b];
644
+ values[a] = values[b];
645
+ keys[b] = tkey;
646
+ values[b] = tvalue;
715
647
 
716
- @Override
717
- public void swap(int a, int b) {
718
- FloatDict.this.swap(a, b);
648
+ // indices.put(keys[a], Integer.valueOf(a));
649
+ // indices.put(keys[b], Integer.valueOf(b));
650
+ }
651
+
652
+
653
+ /**
654
+ * Sort the keys alphabetically (ignoring case). Uses the value as a
655
+ * tie-breaker (only really possible with a key that has a case change).
656
+ *
657
+ * @webref floatdict:method
658
+ * @brief Sort the keys alphabetically
659
+ */
660
+ public void sortKeys() {
661
+ sortImpl(true, false, true);
662
+ }
663
+
664
+
665
+ /**
666
+ * @webref floatdict:method
667
+ * @brief Sort the keys alphabetically in reverse
668
+ */
669
+ public void sortKeysReverse() {
670
+ sortImpl(true, true, true);
671
+ }
672
+
673
+
674
+ /**
675
+ * Sort by values in descending order (largest value will be at [0]).
676
+ *
677
+ * @webref floatdict:method
678
+ * @brief Sort by values in ascending order
679
+ */
680
+ public void sortValues() {
681
+ sortValues(true);
682
+ }
683
+
684
+
685
+ /**
686
+ * Set true to ensure that the order returned is identical. Slightly
687
+ * slower because the tie-breaker for identical values compares the keys.
688
+ * @param stable
689
+ */
690
+ public void sortValues(boolean stable) {
691
+ sortImpl(false, false, stable);
692
+ }
693
+
694
+
695
+ /**
696
+ * @webref floatdict:method
697
+ * @brief Sort by values in descending order
698
+ */
699
+ public void sortValuesReverse() {
700
+ sortValuesReverse(true);
701
+ }
702
+
703
+
704
+ public void sortValuesReverse(boolean stable) {
705
+ sortImpl(false, true, stable);
706
+ }
707
+
708
+
709
+ protected void sortImpl(final boolean useKeys, final boolean reverse,
710
+ final boolean stable) {
711
+ Sort s = new Sort() {
712
+ @Override
713
+ public int size() {
714
+ if (useKeys) {
715
+ return count; // don't worry about NaN values
716
+
717
+ } else if (count == 0) { // skip the NaN check, it'll AIOOBE
718
+ return 0;
719
+
720
+ } else { // first move NaN values to the end of the list
721
+ int right = count - 1;
722
+ while (values[right] != values[right]) {
723
+ right--;
724
+ if (right == -1) {
725
+ return 0; // all values are NaN
719
726
  }
720
- };
721
- s.run();
722
-
723
- // Set the indices after sort/swaps (performance fix 160411)
724
- resetIndices();
725
- }
726
-
727
- /**
728
- * Sum all of the values in this dictionary, then return a new FloatDict of
729
- * each key, divided by the total sum. The total for all values will be
730
- * ~1.0.
731
- *
732
- * @return a FloatDict with the original keys, mapped to their pct of the
733
- * total
734
- */
735
- public FloatDict getPercent() {
736
- double sum = sum();
737
- FloatDict outgoing = new FloatDict();
738
- for (int i = 0; i < size(); i++) {
739
- double percent = value(i) / sum;
740
- outgoing.set(key(i), (float) percent);
741
- }
742
- return outgoing;
743
- }
744
-
745
- /**
746
- * Returns a duplicate copy of this object.
747
- */
748
- public FloatDict copy() {
749
- FloatDict outgoing = new FloatDict(count);
750
- System.arraycopy(keys, 0, outgoing.keys, 0, count);
751
- System.arraycopy(values, 0, outgoing.values, 0, count);
752
- for (int i = 0; i < count; i++) {
753
- outgoing.indices.put(keys[i], i);
727
+ }
728
+ for (int i = right; i >= 0; --i) {
729
+ if (Float.isNaN(values[i])) {
730
+ swap(i, right);
731
+ --right;
732
+ }
733
+ }
734
+ return right + 1;
735
+ }
736
+ }
737
+
738
+ @Override
739
+ public int compare(int a, int b) {
740
+ float diff = 0;
741
+ if (useKeys) {
742
+ diff = keys[a].compareToIgnoreCase(keys[b]);
743
+ if (diff == 0) {
744
+ diff = values[a] - values[b];
745
+ }
746
+ } else { // sort values
747
+ diff = values[a] - values[b];
748
+ if (diff == 0 && stable) {
749
+ diff = keys[a].compareToIgnoreCase(keys[b]);
750
+ }
751
+ }
752
+ if (diff == 0) {
753
+ return 0;
754
+ } else if (reverse) {
755
+ return diff < 0 ? 1 : -1;
756
+ } else {
757
+ return diff < 0 ? -1 : 1;
754
758
  }
755
- outgoing.count = count;
756
- return outgoing;
757
- }
759
+ }
758
760
 
759
- public void print() {
760
- for (int i = 0; i < size(); i++) {
761
- System.out.println(keys[i] + " = " + values[i]);
762
- }
761
+ @Override
762
+ public void swap(int a, int b) {
763
+ FloatDict.this.swap(a, b);
764
+ }
765
+ };
766
+ s.run();
767
+
768
+ // Set the indices after sort/swaps (performance fix 160411)
769
+ resetIndices();
770
+ }
771
+
772
+
773
+ /**
774
+ * Sum all of the values in this dictionary, then return a new FloatDict of
775
+ * each key, divided by the total sum. The total for all values will be ~1.0.
776
+ * @return a FloatDict with the original keys, mapped to their pct of the total
777
+ */
778
+ public FloatDict getPercent() {
779
+ double sum = sum();
780
+ FloatDict outgoing = new FloatDict();
781
+ for (int i = 0; i < size(); i++) {
782
+ double percent = value(i) / sum;
783
+ outgoing.set(key(i), (float) percent);
763
784
  }
785
+ return outgoing;
786
+ }
764
787
 
765
- /**
766
- * Save tab-delimited entries to a file (TSV format, UTF-8 encoding)
767
- */
768
- public void save(File file) {
769
- PrintWriter writer = PApplet.createWriter(file);
770
- write(writer);
771
- writer.close();
788
+
789
+ /** Returns a duplicate copy of this object. */
790
+ public FloatDict copy() {
791
+ FloatDict outgoing = new FloatDict(count);
792
+ System.arraycopy(keys, 0, outgoing.keys, 0, count);
793
+ System.arraycopy(values, 0, outgoing.values, 0, count);
794
+ for (int i = 0; i < count; i++) {
795
+ outgoing.indices.put(keys[i], i);
772
796
  }
797
+ outgoing.count = count;
798
+ return outgoing;
799
+ }
773
800
 
774
- /**
775
- * Write tab-delimited entries out to
776
- *
777
- * @param writer
778
- */
779
- public void write(PrintWriter writer) {
780
- for (int i = 0; i < count; i++) {
781
- writer.println(keys[i] + "\t" + values[i]);
782
- }
783
- writer.flush();
801
+
802
+ public void print() {
803
+ for (int i = 0; i < size(); i++) {
804
+ System.out.println(keys[i] + " = " + values[i]);
784
805
  }
806
+ }
785
807
 
786
- /**
787
- * Return this dictionary as a String in JSON format.
788
- */
789
- public String toJSON() {
790
- StringList items = new StringList();
791
- for (int i = 0; i < count; i++) {
792
- items.append(JSONObject.quote(keys[i]) + ": " + values[i]);
793
- }
794
- return "{ " + items.join(", ") + " }";
808
+
809
+ /**
810
+ * Save tab-delimited entries to a file (TSV format, UTF-8 encoding)
811
+ */
812
+ public void save(File file) {
813
+ PrintWriter writer = PApplet.createWriter(file);
814
+ write(writer);
815
+ writer.close();
816
+ }
817
+
818
+
819
+ /**
820
+ * Write tab-delimited entries out to
821
+ * @param writer
822
+ */
823
+ public void write(PrintWriter writer) {
824
+ for (int i = 0; i < count; i++) {
825
+ writer.println(keys[i] + "\t" + values[i]);
795
826
  }
827
+ writer.flush();
828
+ }
796
829
 
797
- @Override
798
- public String toString() {
799
- return getClass().getSimpleName() + " size=" + size() + " " + toJSON();
830
+
831
+ /**
832
+ * Return this dictionary as a String in JSON format.
833
+ */
834
+ public String toJSON() {
835
+ StringList items = new StringList();
836
+ for (int i = 0; i < count; i++) {
837
+ items.append(JSONObject.quote(keys[i])+ ": " + values[i]);
800
838
  }
839
+ return "{ " + items.join(", ") + " }";
840
+ }
841
+
842
+
843
+ @Override
844
+ public String toString() {
845
+ return getClass().getSimpleName() + " size=" + size() + " " + toJSON();
846
+ }
801
847
  }