mirror of
https://github.com/BelfrySCAD/BOSL2.git
synced 2024-12-29 16:29:40 +00:00
commit
cca4fad3ef
8 changed files with 149 additions and 113 deletions
10
coords.scad
10
coords.scad
|
@ -20,7 +20,7 @@
|
||||||
// Returns a 2D vector/point from a 2D or 3D vector. If given a 3D point, removes the Z coordinate.
|
// Returns a 2D vector/point from a 2D or 3D vector. If given a 3D point, removes the Z coordinate.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// p = The coordinates to force into a 2D vector/point.
|
// p = The coordinates to force into a 2D vector/point.
|
||||||
// fill = Value to fill missing values in vector with.
|
// fill = Value to fill missing values in vector with. Default: 0
|
||||||
function point2d(p, fill=0) = assert(is_list(p)) [for (i=[0:1]) (p[i]==undef)? fill : p[i]];
|
function point2d(p, fill=0) = assert(is_list(p)) [for (i=[0:1]) (p[i]==undef)? fill : p[i]];
|
||||||
|
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ function path2d(points) =
|
||||||
// Returns a 3D vector/point from a 2D or 3D vector.
|
// Returns a 3D vector/point from a 2D or 3D vector.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// p = The coordinates to force into a 3D vector/point.
|
// p = The coordinates to force into a 3D vector/point.
|
||||||
// fill = Value to fill missing values in vector with.
|
// fill = Value to fill missing values in vector with. Default: 0
|
||||||
function point3d(p, fill=0) =
|
function point3d(p, fill=0) =
|
||||||
assert(is_list(p))
|
assert(is_list(p))
|
||||||
[for (i=[0:2]) (p[i]==undef)? fill : p[i]];
|
[for (i=[0:2]) (p[i]==undef)? fill : p[i]];
|
||||||
|
@ -67,7 +67,7 @@ function point3d(p, fill=0) =
|
||||||
// by removing extra coordinates or adding the z coordinate.
|
// by removing extra coordinates or adding the z coordinate.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// points = A list of 2D, 3D or higher dimensional points/vectors.
|
// points = A list of 2D, 3D or higher dimensional points/vectors.
|
||||||
// fill = Value to fill missing values in vectors with (in the 2D case)
|
// fill = Value to fill missing values in vectors with (in the 2D case). Default: 0
|
||||||
function path3d(points, fill=0) =
|
function path3d(points, fill=0) =
|
||||||
assert(is_num(fill))
|
assert(is_num(fill))
|
||||||
assert(is_path(points, dim=undef, fast=true), "Input to path3d is not a path")
|
assert(is_path(points, dim=undef, fast=true), "Input to path3d is not a path")
|
||||||
|
@ -90,7 +90,7 @@ function path3d(points, fill=0) =
|
||||||
// Returns a 4D vector/point from a 2D or 3D vector.
|
// Returns a 4D vector/point from a 2D or 3D vector.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// p = The coordinates to force into a 4D vector/point.
|
// p = The coordinates to force into a 4D vector/point.
|
||||||
// fill = Value to fill missing values in vector with.
|
// fill = Value to fill missing values in vector with. Default: 0
|
||||||
function point4d(p, fill=0) = assert(is_list(p))
|
function point4d(p, fill=0) = assert(is_list(p))
|
||||||
[for (i=[0:3]) (p[i]==undef)? fill : p[i]];
|
[for (i=[0:3]) (p[i]==undef)? fill : p[i]];
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ function point4d(p, fill=0) = assert(is_list(p))
|
||||||
// Returns a list of 4D vectors/points from a list of 2D or 3D vectors/points.
|
// Returns a list of 4D vectors/points from a list of 2D or 3D vectors/points.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// points = A list of 2D or 3D points/vectors.
|
// points = A list of 2D or 3D points/vectors.
|
||||||
// fill = Value to fill missing values in vectors with.
|
// fill = Value to fill missing values in vectors with. Default: 0
|
||||||
function path4d(points, fill=0) =
|
function path4d(points, fill=0) =
|
||||||
assert(is_num(fill) || is_vector(fill))
|
assert(is_num(fill) || is_vector(fill))
|
||||||
assert(is_path(points, dim=undef, fast=true), "Input to path4d is not a path")
|
assert(is_path(points, dim=undef, fast=true), "Input to path4d is not a path")
|
||||||
|
|
53
lists.scad
53
lists.scad
|
@ -19,7 +19,7 @@
|
||||||
// Function: is_homogeneous()
|
// Function: is_homogeneous()
|
||||||
// Alias: is_homogenous()
|
// Alias: is_homogenous()
|
||||||
// Usage:
|
// Usage:
|
||||||
// bool = is_homogeneous(list, depth);
|
// bool = is_homogeneous(list, [depth]);
|
||||||
// Topics: List Handling, Type Checking
|
// Topics: List Handling, Type Checking
|
||||||
// See Also: is_vector(), is_matrix()
|
// See Also: is_vector(), is_matrix()
|
||||||
// Description:
|
// Description:
|
||||||
|
@ -27,7 +27,7 @@
|
||||||
// Booleans and numbers are not distinguinshed as of distinct types.
|
// Booleans and numbers are not distinguinshed as of distinct types.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// l = the list to check
|
// l = the list to check
|
||||||
// depth = the lowest level the check is done
|
// depth = the lowest level the check is done. Default: 10
|
||||||
// Example:
|
// Example:
|
||||||
// a = is_homogeneous([[1,["a"]], [2,["b"]]]); // Returns true
|
// a = is_homogeneous([[1,["a"]], [2,["b"]]]); // Returns true
|
||||||
// b = is_homogeneous([[1,["a"]], [2,[true]]]); // Returns false
|
// b = is_homogeneous([[1,["a"]], [2,[true]]]); // Returns false
|
||||||
|
@ -233,8 +233,8 @@ function select(list, start, end) =
|
||||||
// An index of -1 refers to the last list item.
|
// An index of -1 refers to the last list item.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// list = The list to get the slice of.
|
// list = The list to get the slice of.
|
||||||
// s = The index of the first item to return.
|
// start = The index of the first item to return. Default: 0
|
||||||
// e = The index of the last item to return.
|
// end = The index of the last item to return. Default: -1 (last item)
|
||||||
// See Also: select(), column(), last()
|
// See Also: select(), column(), last()
|
||||||
// Example:
|
// Example:
|
||||||
// a = slice([3,4,5,6,7,8,9], 3, 5); // Returns [6,7,8]
|
// a = slice([3,4,5,6,7,8,9], 3, 5); // Returns [6,7,8]
|
||||||
|
@ -243,17 +243,17 @@ function select(list, start, end) =
|
||||||
// d = slice([3,4,5,6,7,8,9], 5); // Returns [8,9]
|
// d = slice([3,4,5,6,7,8,9], 5); // Returns [8,9]
|
||||||
// e = slice([3,4,5,6,7,8,9], 2, -2); // Returns [5,6,7,8]
|
// e = slice([3,4,5,6,7,8,9], 2, -2); // Returns [5,6,7,8]
|
||||||
// f = slice([3,4,5,6,7,8,9], 4, 3; // Returns []
|
// f = slice([3,4,5,6,7,8,9], 4, 3; // Returns []
|
||||||
function slice(list,s=0,e=-1) =
|
function slice(list,start=0,end=-1) =
|
||||||
assert(is_list(list))
|
assert(is_list(list))
|
||||||
assert(is_int(s))
|
assert(is_int(start))
|
||||||
assert(is_int(e))
|
assert(is_int(end))
|
||||||
!list? [] :
|
!list? [] :
|
||||||
let(
|
let(
|
||||||
l = len(list),
|
l = len(list),
|
||||||
s = constrain(s + (s<0? l : 0), 0, l-1),
|
start = constrain(start + (start<0? l : 0), 0, l-1),
|
||||||
e = constrain(e + (e<0? l : 0), 0, l-1)
|
end = constrain(end + (end<0? l : 0), 0, l-1)
|
||||||
)
|
)
|
||||||
[if (e>=s) for (i=[s:1:e]) list[i]];
|
[if (end>=start) for (i=[start:1:end]) list[i]];
|
||||||
|
|
||||||
|
|
||||||
// Function: last()
|
// Function: last()
|
||||||
|
@ -279,12 +279,13 @@ function last(list) =
|
||||||
// See Also: select(), slice(), list_tail(), last()
|
// See Also: select(), slice(), list_tail(), last()
|
||||||
// Description:
|
// Description:
|
||||||
// Returns the head of the given list, from the first item up until the `to` index, inclusive.
|
// Returns the head of the given list, from the first item up until the `to` index, inclusive.
|
||||||
|
// By default returns all but the last element of the list.
|
||||||
// If the `to` index is negative, then the length of the list is added to it, such that
|
// If the `to` index is negative, then the length of the list is added to it, such that
|
||||||
// `-1` is the last list item. `-2` is the second from last. `-3` is third from last, etc.
|
// `-1` is the last list item. `-2` is the second from last. `-3` is third from last, etc.
|
||||||
// If the list is shorter than the given index, then the full list is returned.
|
// If the list is shorter than the given index, then the full list is returned.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// list = The list to get the head of.
|
// list = The list to get the head of.
|
||||||
// to = The last index to include. If negative, adds the list length to it. ie: -1 is the last list item.
|
// to = The last index to include. If negative, adds the list length to it. ie: -1 is the last list item. Default: -2
|
||||||
// Example:
|
// Example:
|
||||||
// hlist1 = list_head(["foo", "bar", "baz"]); // Returns: ["foo", "bar"]
|
// hlist1 = list_head(["foo", "bar", "baz"]); // Returns: ["foo", "bar"]
|
||||||
// hlist2 = list_head(["foo", "bar", "baz"], -3); // Returns: ["foo"]
|
// hlist2 = list_head(["foo", "bar", "baz"], -3); // Returns: ["foo"]
|
||||||
|
@ -306,12 +307,13 @@ function list_head(list, to=-2) =
|
||||||
// See Also: select(), slice(), list_tail(), last()
|
// See Also: select(), slice(), list_tail(), last()
|
||||||
// Description:
|
// Description:
|
||||||
// Returns the tail of the given list, from the `from` index up until the end of the list, inclusive.
|
// Returns the tail of the given list, from the `from` index up until the end of the list, inclusive.
|
||||||
|
// By default returns all but the first item.
|
||||||
// If the `from` index is negative, then the length of the list is added to it, such that
|
// If the `from` index is negative, then the length of the list is added to it, such that
|
||||||
// `-1` is the last list item. `-2` is the second from last. `-3` is third from last, etc.
|
// `-1` is the last list item. `-2` is the second from last. `-3` is third from last, etc.
|
||||||
// If you want it to return the last three items of the list, use `from=-3`.
|
// If you want it to return the last three items of the list, use `from=-3`.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// list = The list to get the tail of.
|
// list = The list to get the tail of.
|
||||||
// from = The first index to include. If negative, adds the list length to it. ie: -1 is the last list item.
|
// from = The first index to include. If negative, adds the list length to it. ie: -1 is the last list item. Default: 1.
|
||||||
// Example:
|
// Example:
|
||||||
// tlist1 = list_tail(["foo", "bar", "baz"]); // Returns: ["bar", "baz"]
|
// tlist1 = list_tail(["foo", "bar", "baz"]); // Returns: ["bar", "baz"]
|
||||||
// tlist2 = list_tail(["foo", "bar", "baz"], -1); // Returns: ["baz"]
|
// tlist2 = list_tail(["foo", "bar", "baz"], -1); // Returns: ["baz"]
|
||||||
|
@ -364,7 +366,7 @@ function bselect(list,index) =
|
||||||
// multi-dimensional array, filled with `val`.
|
// multi-dimensional array, filled with `val`.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// val = The value to repeat to make the list or array.
|
// val = The value to repeat to make the list or array.
|
||||||
// n = The number of copies to make of `val`.
|
// n = The number of copies to make of `val`. Can be a list to make an array of copies.
|
||||||
// Example:
|
// Example:
|
||||||
// a = repeat(1, 4); // Returns [1,1,1,1]
|
// a = repeat(1, 4); // Returns [1,1,1,1]
|
||||||
// b = repeat(8, [2,3]); // Returns [[8,8,8], [8,8,8]]
|
// b = repeat(8, [2,3]); // Returns [[8,8,8], [8,8,8]]
|
||||||
|
@ -391,7 +393,7 @@ function repeat(val, n, i=0) =
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// indexset = A list of boolean values.
|
// indexset = A list of boolean values.
|
||||||
// valuelist = The list of values to set into the returned list.
|
// valuelist = The list of values to set into the returned list.
|
||||||
// dflt = Default value to store when the indexset item is false.
|
// dflt = Default value to store when the indexset item is false. Default: 0
|
||||||
// Example:
|
// Example:
|
||||||
// a = list_bset([false,true,false,true,false], [3,4]); // Returns: [0,3,0,4,0]
|
// a = list_bset([false,true,false,true,false], [3,4]); // Returns: [0,3,0,4,0]
|
||||||
// b = list_bset([false,true,false,true,false], [3,4], dflt=1); // Returns: [1,3,1,4,1]
|
// b = list_bset([false,true,false,true,false], [3,4], dflt=1); // Returns: [1,3,1,4,1]
|
||||||
|
@ -461,13 +463,13 @@ function force_list(value, n=1, fill) =
|
||||||
// Description:
|
// Description:
|
||||||
// Reverses a list or string.
|
// Reverses a list or string.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// x = The list or string to reverse.
|
// list = The list or string to reverse.
|
||||||
// Example:
|
// Example:
|
||||||
// reverse([3,4,5,6]); // Returns [6,5,4,3]
|
// reverse([3,4,5,6]); // Returns [6,5,4,3]
|
||||||
function reverse(x) =
|
function reverse(list) =
|
||||||
assert(is_list(x)||is_string(x), str("Input to reverse must be a list or string. Got: ",x))
|
assert(is_list(list)||is_string(list), str("Input to reverse must be a list or string. Got: ",list))
|
||||||
let (elems = [ for (i = [len(x)-1 : -1 : 0]) x[i] ])
|
let (elems = [ for (i = [len(list)-1 : -1 : 0]) list[i] ])
|
||||||
is_string(x)? str_join(elems) : elems;
|
is_string(list)? str_join(elems) : elems;
|
||||||
|
|
||||||
|
|
||||||
// Function: list_rotate()
|
// Function: list_rotate()
|
||||||
|
@ -652,7 +654,12 @@ function list_set(list=[],indices,values,dflt=0,minlen=0) =
|
||||||
// Topics: List Handling
|
// Topics: List Handling
|
||||||
// See Also: list_set(), list_remove(), list_remove_values()
|
// See Also: list_set(), list_remove(), list_remove_values()
|
||||||
// Description:
|
// Description:
|
||||||
// Insert `values` into `list` before position `indices`.
|
// Insert `values` into `list` before position `indices`. The indices for insertion
|
||||||
|
// are based on the original list, before any insertions have occurred.
|
||||||
|
// Arguments:
|
||||||
|
// list = list to insert items into
|
||||||
|
// indices = index or list of indices where values are inserted
|
||||||
|
// values = value or list of values to insert
|
||||||
// Example:
|
// Example:
|
||||||
// a = list_insert([3,6,9,12],1,5); // Returns [3,5,6,9,12]
|
// a = list_insert([3,6,9,12],1,5); // Returns [3,5,6,9,12]
|
||||||
// b = list_insert([3,6,9,12],[1,3],[5,11]); // Returns [3,5,6,9,11,12]
|
// b = list_insert([3,6,9,12],[1,3],[5,11]); // Returns [3,5,6,9,11,12]
|
||||||
|
@ -729,8 +736,7 @@ function list_remove(list, ind) =
|
||||||
|
|
||||||
// Function: list_remove_values()
|
// Function: list_remove_values()
|
||||||
// Usage:
|
// Usage:
|
||||||
// list = list_remove_values(list, values);
|
// list = list_remove_values(list, values, [all]);
|
||||||
// list = list_remove_values(list, values, all=true);
|
|
||||||
// Topics: List Handling
|
// Topics: List Handling
|
||||||
// See Also: list_set(), list_insert(), list_remove()
|
// See Also: list_set(), list_insert(), list_remove()
|
||||||
// Description:
|
// Description:
|
||||||
|
@ -806,6 +812,7 @@ function list_remove_values(list,values=[],all=false) =
|
||||||
// Returns the range of indexes for the given list.
|
// Returns the range of indexes for the given list.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// list = The list to returns the index range of.
|
// list = The list to returns the index range of.
|
||||||
|
// ---
|
||||||
// s = The starting index. Default: 0
|
// s = The starting index. Default: 0
|
||||||
// e = The delta from the end of the list. Default: -1 (end of list)
|
// e = The delta from the end of the list. Default: -1 (end of list)
|
||||||
// step = The step size to stride through the list. Default: 1
|
// step = The step size to stride through the list. Default: 1
|
||||||
|
@ -906,7 +913,7 @@ function triplet(list, wrap=false) =
|
||||||
// For the list `[1,2,3,4]`, with `n=3`, this will return `[[1,2,3], [1,2,4], [1,3,4], [2,3,4]]`.
|
// For the list `[1,2,3,4]`, with `n=3`, this will return `[[1,2,3], [1,2,4], [1,3,4], [2,3,4]]`.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// l = The list to provide permutations for.
|
// l = The list to provide permutations for.
|
||||||
// n = The number of items in each permutation. Default: 2
|
// n = The number of items in each combination. Default: 2
|
||||||
// Example:
|
// Example:
|
||||||
// pairs = combinations([3,4,5,6]); // Returns: [[3,4],[3,5],[3,6],[4,5],[4,6],[5,6]]
|
// pairs = combinations([3,4,5,6]); // Returns: [[3,4],[3,5],[3,6],[4,5],[4,6],[5,6]]
|
||||||
// triplets = combinations([3,4,5,6],n=3); // Returns: [[3,4,5],[3,4,6],[3,5,6],[4,5,6]]
|
// triplets = combinations([3,4,5,6],n=3); // Returns: [[3,4,5],[3,4,6],[3,5,6],[4,5,6]]
|
||||||
|
|
|
@ -120,7 +120,7 @@ _hose_waist = [1.7698, 1.8251, 3.95998];
|
||||||
|
|
||||||
// Module: modular_hose()
|
// Module: modular_hose()
|
||||||
// Usage:
|
// Usage:
|
||||||
// modular_hose(size, type, [clearance], [waist_len], [anchor], [spin], [orient]) [attachments]
|
// modular_hose(size, type, [clearance], [waist_len], [anchor], [spin], [orient]) [ATTACHMENTS];
|
||||||
// Description:
|
// Description:
|
||||||
// Construct moduler hose segments or modular hose ends for connection to standard
|
// Construct moduler hose segments or modular hose ends for connection to standard
|
||||||
// modular hose systems. The 1/4", 1/2" and 3/4" sizes are supported and you can
|
// modular hose systems. The 1/4", 1/2" and 3/4" sizes are supported and you can
|
||||||
|
|
|
@ -968,7 +968,7 @@ module screw(name, head, thread="coarse", drive, drive_size, oversize=0, spec, l
|
||||||
{
|
{
|
||||||
spec = _validate_screw_spec(
|
spec = _validate_screw_spec(
|
||||||
is_def(spec) ? spec : screw_info(name, head, thread, drive, drive_size, oversize) );
|
is_def(spec) ? spec : screw_info(name, head, thread, drive, drive_size, oversize) );
|
||||||
struct_echo(spec,"spec");
|
echo_struct(spec,"spec");
|
||||||
head = struct_val(spec,"head");
|
head = struct_val(spec,"head");
|
||||||
pitch = struct_val(spec, "pitch");
|
pitch = struct_val(spec, "pitch");
|
||||||
diameter = struct_val(spec, "diameter");
|
diameter = struct_val(spec, "diameter");
|
||||||
|
@ -1324,7 +1324,7 @@ module nut(name, diameter, thickness, thread="coarse", oversize=0, spec, toleran
|
||||||
function _is_positive(x) = is_num(x) && x>0;
|
function _is_positive(x) = is_num(x) && x>0;
|
||||||
|
|
||||||
function _validate_screw_spec(spec) = let(
|
function _validate_screw_spec(spec) = let(
|
||||||
f=struct_echo(spec),
|
f=echo_struct(spec),
|
||||||
systemOK = in_list(struct_val(spec,"system"), ["UTS","ISO"]),
|
systemOK = in_list(struct_val(spec,"system"), ["UTS","ISO"]),
|
||||||
diamOK = _is_positive(struct_val(spec, "diameter")),
|
diamOK = _is_positive(struct_val(spec, "diameter")),
|
||||||
pitch = struct_val(spec,"pitch"),
|
pitch = struct_val(spec,"pitch"),
|
||||||
|
|
|
@ -56,7 +56,7 @@ function suffix(str,len) =
|
||||||
|
|
||||||
// Function: str_find()
|
// Function: str_find()
|
||||||
// Usage:
|
// Usage:
|
||||||
// str_find(str,pattern,[last],[all],[start])
|
// str_find(str,pattern,[last=],[all=],[start=])
|
||||||
// Description:
|
// Description:
|
||||||
// Searches input string `str` for the string `pattern` and returns the index or indices of the matches in `str`.
|
// Searches input string `str` for the string `pattern` and returns the index or indices of the matches in `str`.
|
||||||
// By default `str_find()` returns the index of the first match in `str`. If `last` is true then it returns the index of the last match.
|
// By default `str_find()` returns the index of the first match in `str`. If `last` is true then it returns the index of the last match.
|
||||||
|
@ -67,6 +67,7 @@ function suffix(str,len) =
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// str = String to search.
|
// str = String to search.
|
||||||
// pattern = string pattern to search for
|
// pattern = string pattern to search for
|
||||||
|
// ---
|
||||||
// last = set to true to return the last match. Default: false
|
// last = set to true to return the last match. Default: false
|
||||||
// all = set to true to return all matches as a list. Overrides last. Default: false
|
// all = set to true to return all matches as a list. Overrides last. Default: false
|
||||||
// start = index where the search starts
|
// start = index where the search starts
|
||||||
|
@ -402,7 +403,7 @@ function parse_float(str) =
|
||||||
|
|
||||||
// Function: parse_frac()
|
// Function: parse_frac()
|
||||||
// Usage:
|
// Usage:
|
||||||
// parse_frac(str,[mixed],[improper],[signed])
|
// parse_frac(str,[mixed=],[improper=],[signed=])
|
||||||
// Description:
|
// Description:
|
||||||
// Converts a string fraction to a floating point number. A string fraction has the form `[-][# ][#/#]` where each `#` is one or more of the
|
// Converts a string fraction to a floating point number. A string fraction has the form `[-][# ][#/#]` where each `#` is one or more of the
|
||||||
// digits 0-9, and there is an optional sign character at the beginning.
|
// digits 0-9, and there is an optional sign character at the beginning.
|
||||||
|
@ -414,6 +415,7 @@ function parse_float(str) =
|
||||||
// The empty string evaluates to zero. Any invalid string evaluates to NaN.
|
// The empty string evaluates to zero. Any invalid string evaluates to NaN.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// str = String to convert.
|
// str = String to convert.
|
||||||
|
// ---
|
||||||
// mixed = set to true to accept mixed fractions, false to reject them. Default: true
|
// mixed = set to true to accept mixed fractions, false to reject them. Default: true
|
||||||
// improper = set to true to accept improper fractions, false to reject them. Default: true
|
// improper = set to true to accept improper fractions, false to reject them. Default: true
|
||||||
// signed = set to true to accept a leading sign character, false to reject. Default: true
|
// signed = set to true to accept a leading sign character, false to reject. Default: true
|
||||||
|
|
117
structs.scad
117
structs.scad
|
@ -1,6 +1,8 @@
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
// LibFile: structs.scad
|
// LibFile: structs.scad
|
||||||
// Struct/Dictionary manipulation functions.
|
// This file provides manipulation of "structs". A "struct" is a data structure that
|
||||||
|
// associates keywords with values and allows you to get and set values
|
||||||
|
// by keyword.
|
||||||
// Includes:
|
// Includes:
|
||||||
// include <BOSL2/std.scad>
|
// include <BOSL2/std.scad>
|
||||||
// include <BOSL2/structs.scad>
|
// include <BOSL2/structs.scad>
|
||||||
|
@ -11,69 +13,74 @@
|
||||||
|
|
||||||
// Section: struct operations
|
// Section: struct operations
|
||||||
//
|
//
|
||||||
// A struct is a data structure that associates arbitrary keywords (of any type) with values (of any type).
|
// A struct is a data structure that associates arbitrary keys (of any type) with values (of any type).
|
||||||
// Structures are implemented as lists of [keyword, value] pairs.
|
// Structures are implemented as lists of [key, value] pairs.
|
||||||
//
|
//
|
||||||
// An empty list `[]` is an empty structure and can be used wherever a structure input is required.
|
// An empty list `[]` is an empty structure and can be used wherever a structure input is required.
|
||||||
|
|
||||||
// Function: struct_set()
|
// Function: struct_set()
|
||||||
// Usage:
|
// Usage:
|
||||||
// struct_set(struct, keyword, value, [grow])
|
// struct_set(struct, key, value, [grow=])
|
||||||
// struct_set(struct, [keyword1, value1, keyword2, value2, ...], [grow])
|
// struct_set(struct, [key1, value1, key2, value2, ...], [grow=])
|
||||||
// Description:
|
// Description:
|
||||||
// Sets the keyword(s) in the structure to the specified value(s), returning a new updated structure. If a keyword
|
// Sets the key(s) in the structure to the specified value(s), returning a new updated structure. If a key
|
||||||
// exists its value is changed, otherwise the keyword is added to the structure. If grow is set to false then
|
// exists its value is changed, otherwise the key is added to the structure. If grow is set to false then
|
||||||
// it is an error to set a keyword not already defined in the structure. If you specify the same keyword twice
|
// it is an error to set a key not already defined in the structure. If you specify the same key twice
|
||||||
// that is also an error. If speed matters, use the first form with scalars rather than the list form: this is
|
// that is also an error. Note that key order will change when you change a key's value.
|
||||||
// about thirty times faster.
|
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// struct = Input structure.
|
// struct = input structure.
|
||||||
// keyword = Keyword to set.
|
// key = key to set or list of key,value pairs to set
|
||||||
// value = Value to set the keyword to.
|
// value = value to set the key to (when giving a single key and value)
|
||||||
// grow = Set to true to allow structure to grow, or false for new keywords to generate an error. Default: true
|
// ---
|
||||||
function struct_set(struct, keyword, value=undef, grow=true) =
|
// grow = Set to true to allow structure to grow, or false for new keys to generate an error. Default: true
|
||||||
!is_list(keyword)? (
|
function struct_set(struct, key, value, grow=true) =
|
||||||
let( ind=search([keyword],struct,1,0)[0] )
|
is_def(value) ? struct_set(struct,[key,value],grow=grow)
|
||||||
ind==[]? (
|
:
|
||||||
assert(grow,str("Unknown keyword \"",keyword))
|
assert(is_list(key) && len(key)%2==0, "[key,value] pair list is not a list or has an odd length")
|
||||||
concat(struct, [[keyword,value]])
|
let(
|
||||||
) : list_set(struct, [ind], [[keyword,value]])
|
new_entries = [for(i=[0:1:len(key)/2-1]) [key[2*i], key[2*i+1]]],
|
||||||
) : _parse_pairs(struct,keyword,grow);
|
newkeys = column(new_entries,0),
|
||||||
|
indlist = search(newkeys, struct,0,0),
|
||||||
|
badkeys = grow ? (search([undef],new_entries,1,0)[0] != [] ? [undef] : [])
|
||||||
function _parse_pairs(spec, input, grow=true, index=0, result=undef) =
|
: [for(i=idx(indlist)) if (is_undef(newkeys[i]) || len(indlist[i])==0) newkeys[i]],
|
||||||
assert(len(input)%2==0,"Odd number of entries in [keyword,value] pair list")
|
ind = flatten(indlist),
|
||||||
let( result = result==undef ? spec : result)
|
dupfind = search(newkeys, new_entries,0,0),
|
||||||
index == len(input) ? result :
|
dupkeys = [for(i=idx(dupfind)) if (len(dupfind[i])>1) newkeys[i]]
|
||||||
_parse_pairs(spec,input,grow,index+2,struct_set(result, input[index], input[index+1],grow));
|
)
|
||||||
|
assert(badkeys==[], str("Unknown or bad key ",_format_key(badkeys[0])," in struct_set"))
|
||||||
|
assert(dupkeys==[], str("Duplicate key ",_format_key(dupkeys[0])," for struct"))
|
||||||
|
concat(list_remove(struct,ind), new_entries);
|
||||||
|
|
||||||
|
function _format_key(key) = is_string(key) ? str("\"",key,"\""): key;
|
||||||
|
|
||||||
// Function: struct_remove()
|
// Function: struct_remove()
|
||||||
// Usage:
|
// Usage:
|
||||||
// struct_remove(struct, keyword)
|
// struct_remove(struct, key)
|
||||||
// Description:
|
// Description:
|
||||||
// Remove keyword or keyword list from a structure
|
// Remove key or list of keys from a structure. If you want to remove a single key which is a list
|
||||||
|
// you must pass it as a singleton list, or struct_remove will attempt to remove the listed items as keys.
|
||||||
|
// If you list the same item multiple times for removal it will be removed without error.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// struct = input structure
|
// struct = input structure
|
||||||
// keyword = a single string (keyword) or list of strings (keywords) to remove
|
// key = a single key or list of keys to remove.
|
||||||
function struct_remove(struct, keyword) =
|
function struct_remove(struct, key) =
|
||||||
is_string(keyword)? struct_remove(struct, [keyword]) :
|
!is_list(key) ? struct_remove(struct, [key]) :
|
||||||
let(ind = search(keyword, struct))
|
let(ind = search(key, struct))
|
||||||
list_remove(struct, ind);
|
list_remove(struct, ind);
|
||||||
|
|
||||||
|
|
||||||
// Function: struct_val()
|
// Function: struct_val()
|
||||||
// Usage:
|
// Usage:
|
||||||
// struct_val(struct, keyword, default)
|
// struct_val(struct, key, default)
|
||||||
// Description:
|
// Description:
|
||||||
// Returns the value for the specified keyword in the structure, or default value if the keyword is not present
|
// Returns the value for the specified key in the structure, or default value if the key is not present
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// struct = input structure
|
// struct = input structure
|
||||||
// keyword = keyword whose value to return
|
// key = key whose value to return
|
||||||
// default = default value to return if keyword is not present, defaults to undef
|
// default = default value to return if key is not present. Default: undef
|
||||||
function struct_val(struct, keyword, default=undef) =
|
function struct_val(struct, key, default=undef) =
|
||||||
assert(is_def(keyword),"keyword is missing")
|
assert(is_def(key),"key is missing")
|
||||||
let(ind = search([keyword],struct)[0])
|
let(ind = search([key],struct)[0])
|
||||||
ind == [] ? default : struct[ind][1];
|
ind == [] ? default : struct[ind][1];
|
||||||
|
|
||||||
|
|
||||||
|
@ -84,26 +91,25 @@ function struct_val(struct, keyword, default=undef) =
|
||||||
// Returns a list of the keys in a structure
|
// Returns a list of the keys in a structure
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// struct = input structure
|
// struct = input structure
|
||||||
function struct_keys(struct) =
|
function struct_keys(struct) = column(struct,0);
|
||||||
[for(entry=struct) entry[0]];
|
|
||||||
|
|
||||||
|
|
||||||
// Function&Module: struct_echo()
|
// Function&Module: echo_struct()
|
||||||
// Usage:
|
// Usage:
|
||||||
// struct_echo(struct, [name])
|
// echo_struct(struct, [name])
|
||||||
// Description:
|
// Description:
|
||||||
// Displays a list of structure keywords and values, one pair per line, for easier reading.
|
// Displays a list of structure keys and values, one pair per line, for easier reading.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// struct = input structure
|
// struct = input structure
|
||||||
// name = optional structure name to list at the top of the output. Default: ""
|
// name = optional structure name to list at the top of the output. Default: ""
|
||||||
function struct_echo(struct,name="") =
|
function echo_struct(struct,name="") =
|
||||||
let( keylist = [for(entry=struct) str(" ",entry[0],": ",entry[1],"\n")])
|
let( keylist = [for(entry=struct) str(" ",entry[0],": ",entry[1],"\n")])
|
||||||
echo(str("\nStructure ",name,"\n",str_join(keylist)))
|
echo(str("\nStructure ",name,"\n",str_join(keylist)))
|
||||||
undef;
|
undef;
|
||||||
|
|
||||||
module struct_echo(struct,name="") {
|
module echo_struct(struct,name="") {
|
||||||
no_children($children);
|
no_children($children);
|
||||||
dummy = struct_echo(struct,name);
|
dummy = echo_struct(struct,name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -111,16 +117,9 @@ module struct_echo(struct,name="") {
|
||||||
// Usage:
|
// Usage:
|
||||||
// is_struct(struct)
|
// is_struct(struct)
|
||||||
// Description:
|
// Description:
|
||||||
// Returns true if the input has the form of a structure, false otherwise.
|
// Returns true if the input is a list of pairs, false otherwise.
|
||||||
function is_struct(x) =
|
function is_struct(x) =
|
||||||
is_list(x) && [
|
is_list(x) && [for (xx=x) if(!(is_list(xx) && len(xx)==2)) 1] == [];
|
||||||
for (xx=x) if(
|
|
||||||
!is_list(xx) ||
|
|
||||||
len(xx) != 2 ||
|
|
||||||
!is_string(xx[0])
|
|
||||||
) 1
|
|
||||||
] == [];
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
|
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
|
||||||
|
|
|
@ -8,7 +8,17 @@ module test_struct_set() {
|
||||||
st2 = struct_set(st, "Bar", 28);
|
st2 = struct_set(st, "Bar", 28);
|
||||||
assert(st2 == [["Foo",42],["Bar",28]]);
|
assert(st2 == [["Foo",42],["Bar",28]]);
|
||||||
st3 = struct_set(st2, "Foo", 91);
|
st3 = struct_set(st2, "Foo", 91);
|
||||||
assert(st3 == [["Foo",91],["Bar",28]]);
|
assert(st3 == [["Bar",28],["Foo",91]]);
|
||||||
|
st4 = struct_set(st3, [3,4,5,6]);
|
||||||
|
assert(st4 == [["Bar", 28],["Foo",91],[3,4],[5,6]]);
|
||||||
|
st5 = struct_set(st3, [[3,4],[5,6]]);
|
||||||
|
assert(st5 == [["Bar", 28],["Foo",91],[[3,4],[5,6]]]);
|
||||||
|
st6 = struct_set(st3, [3,4],true);
|
||||||
|
assert(st6 == [["Bar", 28],["Foo",91],[[3,4],true]]);
|
||||||
|
st7 = struct_set(st3, [3,4,[5,7],99]);
|
||||||
|
assert(st7 == [["Bar", 28],["Foo",91],[3,4],[[5,7],99]]);
|
||||||
|
st8 = struct_set(st3,[]);
|
||||||
|
assert(st8==st3);
|
||||||
}
|
}
|
||||||
test_struct_set();
|
test_struct_set();
|
||||||
|
|
||||||
|
@ -18,18 +28,26 @@ module test_struct_remove() {
|
||||||
assert(struct_remove(st, "Foo") == [["Bar",28],["Baz",9]]);
|
assert(struct_remove(st, "Foo") == [["Bar",28],["Baz",9]]);
|
||||||
assert(struct_remove(st, "Bar") == [["Foo",91],["Baz",9]]);
|
assert(struct_remove(st, "Bar") == [["Foo",91],["Baz",9]]);
|
||||||
assert(struct_remove(st, "Baz") == [["Foo",91],["Bar",28]]);
|
assert(struct_remove(st, "Baz") == [["Foo",91],["Bar",28]]);
|
||||||
|
assert(struct_remove(st, ["Baz","Baz"]) == [["Foo",91],["Bar",28]]);
|
||||||
|
assert(struct_remove(st, ["Baz","Foo"]) == [["Bar",28]]);
|
||||||
|
assert(struct_remove(st, []) == st);
|
||||||
|
assert(struct_remove(st, struct_keys(st)) == []);
|
||||||
}
|
}
|
||||||
test_struct_remove();
|
test_struct_remove();
|
||||||
|
|
||||||
|
|
||||||
module test_struct_val() {
|
module test_struct_val() {
|
||||||
st = [["Foo",91],["Bar",28],["Baz",9]];
|
st = [["Foo",91],["Bar",28],[true,99],["Baz",9],[[5,4],3], [7,92]];
|
||||||
assert(struct_val(st,"Foo") == 91);
|
assert(struct_val(st,"Foo") == 91);
|
||||||
assert(struct_val(st,"Bar") == 28);
|
assert(struct_val(st,"Bar") == 28);
|
||||||
assert(struct_val(st,"Baz") == 9);
|
assert(struct_val(st,"Baz") == 9);
|
||||||
assert(struct_val(st,"Baz",5) == 9);
|
assert(struct_val(st,"Baz",5) == 9);
|
||||||
assert(struct_val(st,"Qux") == undef);
|
assert(struct_val(st,"Qux") == undef);
|
||||||
assert(struct_val(st,"Qux",5) == 5);
|
assert(struct_val(st,"Qux",5) == 5);
|
||||||
|
assert(struct_val(st,[5,4])==3);
|
||||||
|
assert(struct_val(st,true)==99);
|
||||||
|
assert(struct_val(st,5) == undef);
|
||||||
|
assert(struct_val(st,7) == 92);
|
||||||
}
|
}
|
||||||
test_struct_val();
|
test_struct_val();
|
||||||
|
|
||||||
|
@ -37,14 +55,15 @@ test_struct_val();
|
||||||
module test_struct_keys() {
|
module test_struct_keys() {
|
||||||
assert(struct_keys([["Foo",3],["Bar",2],["Baz",1]]) == ["Foo","Bar","Baz"]);
|
assert(struct_keys([["Foo",3],["Bar",2],["Baz",1]]) == ["Foo","Bar","Baz"]);
|
||||||
assert(struct_keys([["Zee",1],["Why",2],["Exx",3]]) == ["Zee","Why","Exx"]);
|
assert(struct_keys([["Zee",1],["Why",2],["Exx",3]]) == ["Zee","Why","Exx"]);
|
||||||
|
assert(struct_keys([["Zee",1],[[3,4],2],["Why",2],[9,1],["Exx",3]]) == ["Zee",[3,4],"Why",9,"Exx"]);
|
||||||
}
|
}
|
||||||
test_struct_keys();
|
test_struct_keys();
|
||||||
|
|
||||||
|
|
||||||
module test_struct_echo() {
|
module test_echo_struct() {
|
||||||
// Can't yet test echo output
|
// Can't yet test echo output
|
||||||
}
|
}
|
||||||
test_struct_echo();
|
test_echo_struct();
|
||||||
|
|
||||||
|
|
||||||
module test_is_struct() {
|
module test_is_struct() {
|
||||||
|
@ -55,6 +74,7 @@ module test_is_struct() {
|
||||||
assert(!is_struct(3));
|
assert(!is_struct(3));
|
||||||
assert(!is_struct(true));
|
assert(!is_struct(true));
|
||||||
assert(!is_struct("foo"));
|
assert(!is_struct("foo"));
|
||||||
|
assert(is_struct([]));
|
||||||
}
|
}
|
||||||
test_is_struct();
|
test_is_struct();
|
||||||
|
|
||||||
|
|
42
version.scad
42
version.scad
|
@ -52,18 +52,20 @@ function bosl_version_str() = version_to_str(BOSL_VERSION);
|
||||||
|
|
||||||
// Module: bosl_required()
|
// Module: bosl_required()
|
||||||
// Usage:
|
// Usage:
|
||||||
// bosl_required(x);
|
// bosl_required(version);
|
||||||
// Topics: Versioning
|
// Topics: Versioning
|
||||||
// Description:
|
// Description:
|
||||||
// Given a version as a list, number, or string, asserts that the currently installed BOSL library is at least the given version.
|
// Given a version as a list, number, or string, asserts that the currently installed BOSL library is at least the given version.
|
||||||
// See Also: version_to_num(), version_to_str(), version_to_list(), version_cmp()
|
// See Also: version_to_num(), version_to_str(), version_to_list(), version_cmp()
|
||||||
module bosl_required(target) {
|
// Arguments:
|
||||||
|
// version = version required
|
||||||
|
module bosl_required(version) {
|
||||||
no_children($children);
|
no_children($children);
|
||||||
assert(
|
assert(
|
||||||
version_cmp(bosl_version(), target) >= 0,
|
version_cmp(bosl_version(), version) >= 0,
|
||||||
str(
|
str(
|
||||||
"BOSL ", bosl_version_str(), " is installed, but BOSL ",
|
"BOSL ", bosl_version_str(), " is installed, but BOSL ",
|
||||||
version_to_str(target), " or better is required."
|
version_to_str(version), " or better is required."
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -89,50 +91,56 @@ function _version_split_str(x, _i=0, _out=[], _num=0) =
|
||||||
// Description:
|
// Description:
|
||||||
// Given a version string, number, or list, returns the list of version integers [MAJOR,MINOR,REVISION].
|
// Given a version string, number, or list, returns the list of version integers [MAJOR,MINOR,REVISION].
|
||||||
// See Also: version_to_num(), version_to_str(), version_cmp(), bosl_required()
|
// See Also: version_to_num(), version_to_str(), version_cmp(), bosl_required()
|
||||||
|
// Arguments:
|
||||||
|
// x = version to convert
|
||||||
// Example:
|
// Example:
|
||||||
// v1 = version_to_list("2.1.43"); // Returns: [2,1,43]
|
// v1 = version_to_list("2.1.43"); // Returns: [2,1,43]
|
||||||
// v2 = version_to_list(2.120234); // Returns: [2,12,234]
|
// v2 = version_to_list(2.120234); // Returns: [2,12,234]
|
||||||
// v3 = version_to_list([2,3,4]); // Returns: [2,3,4]
|
// v3 = version_to_list([2,3,4]); // Returns: [2,3,4]
|
||||||
// v4 = version_to_list([2,3,4,5]); // Returns: [2,3,4]
|
// v4 = version_to_list([2,3,4,5]); // Returns: [2,3,4]
|
||||||
function version_to_list(x) =
|
function version_to_list(version) =
|
||||||
is_list(x)? [default(x[0],0), default(x[1],0), default(x[2],0)] :
|
is_list(version)? [default(version[0],0), default(version[1],0), default(version[2],0)] :
|
||||||
is_string(x)? _version_split_str(x) :
|
is_string(version)? _version_split_str(version) :
|
||||||
is_num(x)? [floor(x), floor(x*100%100), floor(x*1000000%10000+0.5)] :
|
is_num(version)? [floor(version), floor(version*100%100), floor(version*1000000%10000+0.5)] :
|
||||||
assert(is_num(x) || is_vector(x) || is_string(x)) 0;
|
assert(is_num(version) || is_vector(version) || is_string(version)) 0;
|
||||||
|
|
||||||
|
|
||||||
// Function: version_to_str()
|
// Function: version_to_str()
|
||||||
// Usage:
|
// Usage:
|
||||||
// str = version_to_str(x);
|
// str = version_to_str(version);
|
||||||
// Topics: Versioning
|
// Topics: Versioning
|
||||||
// Description:
|
// Description:
|
||||||
// Takes a version string, number, or list, and returns the properly formatter version string for it.
|
// Takes a version string, number, or list, and returns the properly formatter version string for it.
|
||||||
// See Also: version_to_num(), version_to_list(), version_cmp(), bosl_required()
|
// See Also: version_to_num(), version_to_list(), version_cmp(), bosl_required()
|
||||||
|
// Arguments:
|
||||||
|
// version = version to convert
|
||||||
// Example:
|
// Example:
|
||||||
// v1 = version_to_str([2,1,43]); // Returns: "2.1.43"
|
// v1 = version_to_str([2,1,43]); // Returns: "2.1.43"
|
||||||
// v2 = version_to_str(2.010043); // Returns: "2.1.43"
|
// v2 = version_to_str(2.010043); // Returns: "2.1.43"
|
||||||
// v3 = version_to_str(2.340789); // Returns: "2.34.789"
|
// v3 = version_to_str(2.340789); // Returns: "2.34.789"
|
||||||
// v4 = version_to_str("2.3.89"); // Returns: "2.3.89"
|
// v4 = version_to_str("2.3.89"); // Returns: "2.3.89"
|
||||||
function version_to_str(x) =
|
function version_to_str(version) =
|
||||||
let(x = version_to_list(x))
|
let(version = version_to_list(version))
|
||||||
str(x[0],".",x[1],".",x[2]);
|
str(version[0],".",version[1],".",version[2]);
|
||||||
|
|
||||||
|
|
||||||
// Function: version_to_num()
|
// Function: version_to_num()
|
||||||
// Usage:
|
// Usage:
|
||||||
// str = version_to_num(x);
|
// str = version_to_num(version);
|
||||||
// Topics: Versioning
|
// Topics: Versioning
|
||||||
// Description:
|
// Description:
|
||||||
// Takes a version string, number, or list, and returns the properly formatter version number for it.
|
// Takes a version string, number, or list, and returns the properly formatter version number for it.
|
||||||
// See Also: version_cmp(), version_to_str(), version_to_list(), bosl_required()
|
// See Also: version_cmp(), version_to_str(), version_to_list(), bosl_required()
|
||||||
|
// Arguments:
|
||||||
|
// version = version to convert
|
||||||
// Example:
|
// Example:
|
||||||
// v1 = version_to_num([2,1,43]); // Returns: 2.010043
|
// v1 = version_to_num([2,1,43]); // Returns: 2.010043
|
||||||
// v2 = version_to_num([2,34,567]); // Returns: 2.340567
|
// v2 = version_to_num([2,34,567]); // Returns: 2.340567
|
||||||
// v3 = version_to_num(2.120567); // Returns: 2.120567
|
// v3 = version_to_num(2.120567); // Returns: 2.120567
|
||||||
// v4 = version_to_num("2.6.79"); // Returns: 2.060079
|
// v4 = version_to_num("2.6.79"); // Returns: 2.060079
|
||||||
function version_to_num(x) =
|
function version_to_num(version) =
|
||||||
let(x = version_to_list(x))
|
let(version = version_to_list(version))
|
||||||
(x[0]*1000000 + x[1]*10000 + x[2])/1000000;
|
(version[0]*1000000 + version[1]*10000 + version[2])/1000000;
|
||||||
|
|
||||||
|
|
||||||
// Function: version_cmp()
|
// Function: version_cmp()
|
||||||
|
|
Loading…
Reference in a new issue