July 8, 2022
Description
For some complex OpenSCAD projects I wanted to have to ability to put many different settings for a module into one parameter as a hash / associative array. This would be useful when I have a large number of settings and module which call sub-modules which call sub-sub-modules.
Putting these settings into module parameters would be unwieldy, especially if I have to add a settings later. Putting these settings into global parameters prevents me from using the module with several different settings at the same time.
OpenSCAD does not natively support hashes / associative array (as of mid 2022). But it does have a search() function that can (among other things) locate a string in an array.
So I build this library that encapsulates the creation, modification and use of hashes.
This library can be used by including the following line:
use <af-hash.scad>
The basic use case is where I have a module that can receive any number of settings in one parameter, and I can call this module with different settings. Optionally the module calls a sub-module which also uses these settings.
Example:
use <af-hash.scad>
settings1 = hash_create([
"size", [10,20,30],
"wall-thickness", 2,
"hole-diameter", 5
]);
settings2 = hash_create([
"size", [20,30,60],
"wall-thickness", 3,
"hole-diameter", 8
]);
translate([-30,0,0]) my_module(settings1);
translate([30,0,0]) my_module(settings2);
module my_module(settings) {
s = hash_get(settings, "size");
w = hash_get(settings, "wall-thickness");
[...]
my_submodule(settings);
[...]
}
module my_submodule(settings) {
w = hash_get(settings, "wall-thickness");
d = hash_get(settings, "hole-diameter");
[...]
}
The functions in this library are (the most important function are in bold):
Update 2022-07-30:
Added the following function:
Some technical details:
Hashes are internally stored as a vector of vectors of key and value:
hash = [
[ <key1>, <value1> ],
[ <key2>, <value2> ],
[ <key3>, <value3> ],
etc.
];Hash keys are automatically converted to strings both during creation of the hash and during access of the hash data.
Hash values can be any kind of data, including undef, number, vector, string or a hash.
As hash_print will show you, hash_set does not actually modify the old hash. Instead it puts the new values at the start of the newly generated hash:
hash1 = [
[ "abc", 1 ],
[ "def", 2 ]
];
hash2 = [
[ "def", 3 ],
[ "ghi", 4 ]
];
hash3 = hash_set(hash1, hash2);
==> hash3 = [
[ "def", 3 ],
[ "ghi", 4 ],
[ "abc", 1 ],
[ "def", 2 ]
];hash_get("def") will find the new value (3) first and return it instead of the old value (2).
A hash value can be “deleted” by overriding it with the value undef. The key still counts as contained in the hash, but hash_get will return the default value (which is also undef if not specified).
hash_create allows key-value pairs in sub-arrays, sub-sub-arrays etc., it will flatten the data into the above described hash structure:
hash = hash_create([ "ab",1, "cd",2, [ "ef",3, [ "gh",4 ] ], "ij",5 ]);
==> hash = [
[ "ab", 1 ],
[ "cd", 2 ],
[ "ef", 3 ],
[ "gh", 4 ],
[ "ij", 5 ]
];The value overriding mechanism can create quite big hashes. The output of hash_print will then be difficult to read. By using hash_prune the hash will be smaller because all overridden values are removed:
hash1 = hash_create([ "a",1, "b",2, "a",3, "c",4, "a",5 ]);
==> hash1 = [
[ "a", 1 ],
[ "b", 2 ],
[ "a", 3 ],
[ "c", 4 ],
[ "a", 5 ]
];
hash2 = hash_prune(hash1);
==> hash2 = [
[ "a", 1 ],
[ "b", 2 ],
[ "c", 4 ]
];License:
Creative Commons — Attribution
9