propane 3.4.2-java → 3.8.0-java

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