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.
- checksums.yaml +4 -4
- data/.mvn/extensions.xml +1 -2
- data/.mvn/wrapper/MavenWrapperDownloader.java +2 -2
- data/.mvn/wrapper/maven-wrapper.properties +2 -2
- data/.travis.yml +2 -2
- data/CHANGELOG.md +12 -0
- data/Gemfile +2 -0
- data/README.md +17 -8
- data/Rakefile +10 -11
- data/bin/propane +3 -1
- data/lib/propane.rb +6 -4
- data/lib/propane/app.rb +20 -10
- data/lib/propane/creators/sketch_class.rb +7 -1
- data/lib/propane/creators/sketch_factory.rb +4 -2
- data/lib/propane/creators/sketch_writer.rb +1 -0
- data/lib/propane/helper_methods.rb +23 -24
- data/lib/propane/helpers/numeric.rb +2 -0
- data/lib/propane/helpers/version_error.rb +1 -0
- data/lib/propane/library.rb +5 -1
- data/lib/propane/library_loader.rb +2 -0
- data/lib/propane/native_folder.rb +10 -9
- data/lib/propane/native_loader.rb +3 -0
- data/lib/propane/runner.rb +14 -6
- data/lib/propane/version.rb +2 -1
- data/library/boids/boids.rb +21 -11
- data/library/color_group/color_group.rb +28 -0
- data/library/control_panel/control_panel.rb +8 -5
- data/library/dxf/dxf.rb +6 -0
- data/library/file_chooser/chooser.rb +10 -9
- data/library/file_chooser/file_chooser.rb +10 -9
- data/library/library_proxy/library_proxy.rb +2 -0
- data/library/net/net.rb +7 -0
- data/library/simplex_noise/simplex_noise.rb +2 -0
- data/library/slider/slider.rb +23 -22
- data/library/vector_utils/vector_utils.rb +4 -0
- data/library/video_event/video_event.rb +4 -1
- data/pom.rb +37 -36
- data/pom.xml +7 -7
- data/propane.gemspec +16 -12
- data/src/main/java/monkstone/ColorUtil.java +13 -1
- data/src/main/java/monkstone/MathToolModule.java +253 -203
- data/src/main/java/monkstone/PropaneLibrary.java +2 -2
- data/src/main/java/monkstone/fastmath/Deglut.java +1 -1
- data/src/main/java/monkstone/filechooser/Chooser.java +2 -1
- data/src/main/java/monkstone/noise/SimplexNoise.java +2 -2
- data/src/main/java/monkstone/slider/CustomHorizontalSlider.java +1 -1
- data/src/main/java/monkstone/slider/CustomVerticalSlider.java +1 -1
- data/src/main/java/monkstone/slider/SimpleHorizontalSlider.java +1 -1
- data/src/main/java/monkstone/slider/SimpleVerticalSlider.java +1 -1
- data/src/main/java/monkstone/slider/SliderBar.java +1 -1
- data/src/main/java/monkstone/slider/SliderGroup.java +1 -1
- data/src/main/java/monkstone/slider/WheelHandler.java +7 -6
- data/src/main/java/monkstone/vecmath/package-info.java +1 -1
- data/src/main/java/monkstone/vecmath/vec2/Vec2.java +1 -1
- data/src/main/java/monkstone/vecmath/vec3/Vec3.java +3 -3
- data/src/main/java/monkstone/videoevent/CaptureEvent.java +27 -0
- data/src/main/java/monkstone/videoevent/{VideoInterface.java → MovieEvent.java} +11 -27
- data/src/main/java/monkstone/videoevent/package-info.java +1 -1
- data/src/main/java/processing/awt/PGraphicsJava2D.java +781 -285
- data/src/main/java/processing/awt/PImageAWT.java +377 -0
- data/src/main/java/processing/awt/PShapeJava2D.java +56 -52
- data/src/main/java/processing/awt/PSurfaceAWT.java +309 -209
- data/src/main/java/processing/awt/ShimAWT.java +581 -0
- data/src/main/java/processing/core/PApplet.java +4510 -4503
- data/src/main/java/processing/core/PConstants.java +477 -447
- data/src/main/java/processing/core/PFont.java +914 -880
- data/src/main/java/processing/core/PGraphics.java +193 -177
- data/src/main/java/processing/core/PImage.java +611 -309
- data/src/main/java/processing/core/PMatrix.java +172 -159
- data/src/main/java/processing/core/PMatrix2D.java +478 -415
- data/src/main/java/processing/core/PMatrix3D.java +762 -735
- data/src/main/java/processing/core/PShape.java +2888 -2652
- data/src/main/java/processing/core/PShapeOBJ.java +97 -92
- data/src/main/java/processing/core/PShapeSVG.java +1705 -1490
- data/src/main/java/processing/core/PStyle.java +40 -37
- data/src/main/java/processing/core/PSurface.java +139 -97
- data/src/main/java/processing/core/PSurfaceNone.java +296 -218
- data/src/main/java/processing/core/PVector.java +997 -965
- data/src/main/java/processing/core/ThinkDifferent.java +15 -13
- data/src/main/java/processing/data/DoubleDict.java +756 -710
- data/src/main/java/processing/data/DoubleList.java +749 -696
- data/src/main/java/processing/data/FloatDict.java +748 -702
- data/src/main/java/processing/data/FloatList.java +751 -697
- data/src/main/java/processing/data/IntDict.java +720 -673
- data/src/main/java/processing/data/IntList.java +699 -633
- data/src/main/java/processing/data/JSONArray.java +931 -873
- data/src/main/java/processing/data/JSONObject.java +1262 -1165
- data/src/main/java/processing/data/JSONTokener.java +351 -341
- data/src/main/java/processing/data/LongDict.java +710 -663
- data/src/main/java/processing/data/LongList.java +701 -635
- data/src/main/java/processing/data/Sort.java +37 -41
- data/src/main/java/processing/data/StringDict.java +525 -486
- data/src/main/java/processing/data/StringList.java +626 -580
- data/src/main/java/processing/data/Table.java +3690 -3510
- data/src/main/java/processing/data/TableRow.java +182 -183
- data/src/main/java/processing/data/XML.java +957 -883
- data/src/main/java/processing/dxf/RawDXF.java +404 -0
- data/src/main/java/processing/event/Event.java +87 -67
- data/src/main/java/processing/event/KeyEvent.java +48 -41
- data/src/main/java/processing/event/MouseEvent.java +88 -113
- data/src/main/java/processing/event/TouchEvent.java +10 -6
- data/src/main/java/processing/javafx/PGraphicsFX2D.java +20 -345
- data/src/main/java/processing/javafx/PSurfaceFX.java +149 -121
- data/src/main/java/processing/net/Client.java +744 -0
- data/src/main/java/processing/net/Server.java +388 -0
- data/src/main/java/processing/opengl/FontTexture.java +289 -270
- data/src/main/java/processing/opengl/FrameBuffer.java +386 -364
- data/src/main/java/processing/opengl/LinePath.java +547 -500
- data/src/main/java/processing/opengl/LineStroker.java +588 -581
- data/src/main/java/processing/opengl/PGL.java +3047 -2914
- data/src/main/java/processing/opengl/PGraphics2D.java +408 -315
- data/src/main/java/processing/opengl/PGraphics3D.java +107 -72
- data/src/main/java/processing/opengl/PGraphicsOpenGL.java +12378 -12075
- data/src/main/java/processing/opengl/PJOGL.java +1753 -1670
- data/src/main/java/processing/opengl/PShader.java +1266 -1257
- data/src/main/java/processing/opengl/PShapeOpenGL.java +4678 -4580
- data/src/main/java/processing/opengl/PSurfaceJOGL.java +1114 -1027
- data/src/main/java/processing/opengl/Texture.java +1492 -1401
- data/src/main/java/processing/opengl/VertexBuffer.java +57 -55
- data/test/create_test.rb +21 -20
- data/test/deglut_spec_test.rb +4 -2
- data/test/helper_methods_test.rb +49 -20
- data/test/math_tool_test.rb +39 -32
- data/test/native_folder.rb +47 -0
- data/test/respond_to_test.rb +3 -2
- data/test/sketches/key_event.rb +2 -2
- data/test/sketches/library/my_library/my_library.rb +3 -0
- data/test/test_helper.rb +2 -0
- data/test/vecmath_spec_test.rb +35 -22
- data/vendors/Rakefile +33 -62
- metadata +56 -48
- data/src/main/java/processing/core/util/image/ImageLoadFacade.java +0 -161
- data/src/main/java/processing/core/util/image/ImageSaveFacade.java +0 -169
- data/src/main/java/processing/core/util/image/constants/TifConstants.java +0 -45
- data/src/main/java/processing/core/util/image/load/AwtImageLoadStrategy.java +0 -80
- data/src/main/java/processing/core/util/image/load/Base64StringImageLoadStrategy.java +0 -73
- data/src/main/java/processing/core/util/image/load/FallbackImageLoadStrategy.java +0 -70
- data/src/main/java/processing/core/util/image/load/ImageIoImageLoadStrategy.java +0 -132
- data/src/main/java/processing/core/util/image/load/ImageLoadStrategy.java +0 -48
- data/src/main/java/processing/core/util/image/load/ImageLoadUtil.java +0 -45
- data/src/main/java/processing/core/util/image/load/TgaImageLoadStrategy.java +0 -255
- data/src/main/java/processing/core/util/image/load/TiffImageLoadStrategy.java +0 -98
- data/src/main/java/processing/core/util/image/save/ImageSaveStrategy.java +0 -49
- data/src/main/java/processing/core/util/image/save/ImageSaveUtil.java +0 -48
- data/src/main/java/processing/core/util/image/save/ImageWriterImageSaveStrategy.java +0 -179
- data/src/main/java/processing/core/util/image/save/SaveImageException.java +0 -41
- data/src/main/java/processing/core/util/image/save/TgaImageSaveStrategy.java +0 -198
- data/src/main/java/processing/core/util/image/save/TiffImageSaveStrategy.java +0 -91
- data/src/main/java/processing/core/util/image/save/TiffNakedFilenameImageSaveStrategy.java +0 -57
- data/src/main/java/processing/core/util/io/InputFactory.java +0 -285
- data/src/main/java/processing/core/util/io/PathUtil.java +0 -109
- data/src/main/java/processing/opengl/shaders/LightVert-brcm.glsl +0 -154
- data/src/main/java/processing/opengl/shaders/LightVert-vc4.glsl +0 -154
- data/src/main/java/processing/opengl/shaders/TexLightVert-brcm.glsl +0 -160
- 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
|
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
|
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
|
43
|
-
private static Taskbar taskbar;
|
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
|
*
|
@@ -57,9 +58,11 @@ public class ThinkDifferent {
|
|
57
58
|
* @param sketch The sketch whose quit handler callback should be set.
|
58
59
|
*/
|
59
60
|
static public void init(final PApplet sketch) {
|
60
|
-
getDesktop().setQuitHandler((
|
61
|
-
sketch.exit();
|
62
|
-
|
61
|
+
getDesktop().setQuitHandler((event, quitResponse) -> {
|
62
|
+
sketch.exit();
|
63
|
+
|
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,38 +80,36 @@ 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() {
|
94
98
|
if (taskbar == null) {
|
95
99
|
taskbar = Taskbar.getTaskbar();
|
96
100
|
}
|
97
|
-
|
98
101
|
return taskbar;
|
99
102
|
}
|
100
103
|
|
104
|
+
|
101
105
|
/**
|
102
106
|
* Get the desktop where OS behavior can be provided.
|
103
|
-
*
|
104
107
|
* @return Cached desktop singleton instance.
|
105
108
|
*/
|
106
109
|
static private Desktop getDesktop() {
|
107
110
|
if (desktop == null) {
|
108
111
|
desktop = Desktop.getDesktop();
|
109
112
|
}
|
110
|
-
|
111
113
|
return desktop;
|
112
114
|
}
|
113
115
|
}
|
@@ -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
|
-
* @
|
15
|
+
* @nowebref
|
14
16
|
* @see IntDict
|
15
17
|
* @see StringDict
|
16
18
|
*/
|
17
19
|
public class DoubleDict {
|
18
20
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
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
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
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
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
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
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
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
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
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
|
-
|
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
|
-
|
180
|
-
|
181
|
-
|
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
|
-
|
189
|
-
|
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
|
-
|
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
|
-
|
210
|
-
|
211
|
-
|
212
|
-
};
|
213
|
-
}
|
182
|
+
public class Entry {
|
183
|
+
public String key;
|
184
|
+
public double value;
|
214
185
|
|
215
|
-
|
216
|
-
|
217
|
-
|
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
|
-
|
228
|
-
|
193
|
+
public Iterable<Entry> entries() {
|
194
|
+
return new Iterable<Entry>() {
|
229
195
|
|
230
|
-
|
231
|
-
|
232
|
-
|
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
|
-
|
243
|
-
|
244
|
-
|
245
|
-
}
|
203
|
+
public Iterator<Entry> entryIterator() {
|
204
|
+
return new Iterator<Entry>() {
|
205
|
+
int index = -1;
|
246
206
|
|
247
|
-
|
248
|
-
|
249
|
-
|
207
|
+
public void remove() {
|
208
|
+
removeIndex(index);
|
209
|
+
index--;
|
210
|
+
}
|
250
211
|
|
251
|
-
|
252
|
-
|
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
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
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
|
-
|
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
|
-
|
288
|
-
|
289
|
-
|
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
|
-
|
299
|
-
|
300
|
-
index--;
|
301
|
-
}
|
241
|
+
public Iterable<String> keys() {
|
242
|
+
return new Iterable<String>() {
|
302
243
|
|
303
|
-
|
304
|
-
|
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
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
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
|
-
|
361
|
-
|
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
|
-
|
373
|
-
|
374
|
-
|
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
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
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
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
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
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
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
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
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
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
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
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
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
|
-
|
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
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
}
|
555
|
-
return sum;
|
556
|
-
}
|
318
|
+
public void remove() {
|
319
|
+
removeIndex(index);
|
320
|
+
index--;
|
321
|
+
}
|
557
322
|
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
}
|
323
|
+
public Double next() {
|
324
|
+
return value(++index);
|
325
|
+
}
|
562
326
|
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
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
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
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
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
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
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
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
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
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
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
}
|
745
|
-
|
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
|
-
|
759
|
-
return outgoing;
|
760
|
-
}
|
762
|
+
}
|
761
763
|
|
762
|
-
|
763
|
-
|
764
|
-
|
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
|
-
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
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
|
-
|
779
|
-
|
780
|
-
|
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
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
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
|
-
|
801
|
-
|
802
|
-
|
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
|
}
|