mirror of
https://github.com/BelfrySCAD/BOSL2.git
synced 2025-01-01 09:49:45 +00:00
Resolved conflicts with master.
This commit is contained in:
parent
bda2661855
commit
698268c8c7
12 changed files with 107 additions and 61 deletions
57
arrays.scad
57
arrays.scad
|
@ -145,18 +145,59 @@ function last(list) =
|
||||||
list[len(list)-1];
|
list[len(list)-1];
|
||||||
|
|
||||||
|
|
||||||
// Function: delete_last()
|
// Function: list_head()
|
||||||
// Usage:
|
// Usage:
|
||||||
// list = delete_last(list);
|
// list = list_head(list,<to>);
|
||||||
// Topics: List Handling
|
// Topics: List Handling
|
||||||
// See Also: select(), slice(), subindex(), last()
|
// See Also: select(), slice(), list_tail(), last()
|
||||||
// Description:
|
// Description:
|
||||||
// Returns a list with all but the last entry from the input list. If input is empty, returns empty list.
|
// Returns the head of the given list, from the first item up until the `to` index, inclusive.
|
||||||
// Example:
|
// If the `to` index is negative, then the length of the list is added to it, such that
|
||||||
// nlist = delete_last(["foo", "bar", "baz"]); // Returns: ["foo", "bar"]
|
// `-1` is the last list item. `-2` is the second from last. `-3` is third from last, etc.
|
||||||
function delete_last(list) =
|
// If the list is shorter than the given index, then the full list is returned.
|
||||||
|
// Arguments:
|
||||||
|
// 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.
|
||||||
|
// Examples:
|
||||||
|
// hlist = list_head(["foo", "bar", "baz"]); // Returns: ["foo", "bar"]
|
||||||
|
// hlist = list_head(["foo", "bar", "baz"], -3); // Returns: ["foo"]
|
||||||
|
// hlist = list_head(["foo", "bar", "baz"], 2); // Returns: ["foo","bar"]
|
||||||
|
// hlist = list_head(["foo", "bar", "baz"], -5); // Returns: []
|
||||||
|
// hlist = list_head(["foo", "bar", "baz"], 5); // Returns: ["foo","bar","baz"]
|
||||||
|
function list_head(list, to=-2) =
|
||||||
assert(is_list(list))
|
assert(is_list(list))
|
||||||
list==[] ? [] : slice(list,0,-2);
|
assert(is_finite(to))
|
||||||
|
to<0? [for (i=[0:1:len(list)+to]) list[i]] :
|
||||||
|
to<len(list)? [for (i=[0:1:to]) list[i]] :
|
||||||
|
list;
|
||||||
|
|
||||||
|
|
||||||
|
// Function: list_tail()
|
||||||
|
// Usage:
|
||||||
|
// list = list_tail(list,<from>);
|
||||||
|
// Topics: List Handling
|
||||||
|
// See Also: select(), slice(), list_tail(), last()
|
||||||
|
// Description:
|
||||||
|
// Returns the tail of the given list, from the `from` index up until the end of the list, inclusive.
|
||||||
|
// 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.
|
||||||
|
// If you want it to return the last three items of the list, use `from=-3`.
|
||||||
|
// Arguments:
|
||||||
|
// 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.
|
||||||
|
// Examples:
|
||||||
|
// tlist = list_tail(["foo", "bar", "baz"]); // Returns: ["bar", "baz"]
|
||||||
|
// tlist = list_tail(["foo", "bar", "baz"], -1); // Returns: ["baz"]
|
||||||
|
// tlist = list_tail(["foo", "bar", "baz"], 2); // Returns: ["baz"]
|
||||||
|
// tlist = list_tail(["foo", "bar", "baz"], -5); // Returns: ["foo","bar","baz"]
|
||||||
|
// tlist = list_tail(["foo", "bar", "baz"], 5); // Returns: []
|
||||||
|
function list_tail(list, from=1) =
|
||||||
|
assert(is_list(list))
|
||||||
|
assert(is_finite(from))
|
||||||
|
from>=0? [for (i=[from:1:len(list)-1]) list[i]] :
|
||||||
|
let(from = from + len(list))
|
||||||
|
from>=0? [for (i=[from:1:len(list)-1]) list[i]] :
|
||||||
|
list;
|
||||||
|
|
||||||
|
|
||||||
// Function: list()
|
// Function: list()
|
||||||
|
|
|
@ -945,7 +945,7 @@ module bezier_polygon(bezier, splinesteps=16, N=3) {
|
||||||
assert(is_int(splinesteps));
|
assert(is_int(splinesteps));
|
||||||
assert(len(bezier)%N == 1, str("A degree ",N," bezier path shound have a multiple of ",N," points in it, plus 1."));
|
assert(len(bezier)%N == 1, str("A degree ",N," bezier path shound have a multiple of ",N," points in it, plus 1."));
|
||||||
polypoints=bezier_path(bezier, splinesteps, N);
|
polypoints=bezier_path(bezier, splinesteps, N);
|
||||||
polygon(points=slice(polypoints, 0, -1));
|
polygon(points=polypoints);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
21
common.scad
21
common.scad
|
@ -273,7 +273,6 @@ function is_bool_list(list, length) =
|
||||||
// Topics: Undef Handling
|
// Topics: Undef Handling
|
||||||
// See Also: first_defined(), one_defined(), num_defined()
|
// See Also: first_defined(), one_defined(), num_defined()
|
||||||
// Description:
|
// Description:
|
||||||
// Returns the value given as `v` if it is not `undef`. Otherwise, returns the value of `dflt`.
|
|
||||||
// Returns the value given as `v` if it is not `undef`.
|
// Returns the value given as `v` if it is not `undef`.
|
||||||
// Otherwise, returns the value of `dflt`.
|
// Otherwise, returns the value of `dflt`.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
|
@ -294,8 +293,7 @@ function default(v,dflt=undef) = is_undef(v)? dflt : v;
|
||||||
// v = The list whose items are being checked.
|
// v = The list whose items are being checked.
|
||||||
// recursive = If true, sublists are checked recursively for defined values. The first sublist that has a defined item is returned.
|
// recursive = If true, sublists are checked recursively for defined values. The first sublist that has a defined item is returned.
|
||||||
// Examples:
|
// Examples:
|
||||||
// list = ***
|
// val = first_defined([undef,7,undef,true]); // Returns: 1
|
||||||
// val = first_defined(list)
|
|
||||||
function first_defined(v,recursive=false,_i=0) =
|
function first_defined(v,recursive=false,_i=0) =
|
||||||
_i<len(v) && (
|
_i<len(v) && (
|
||||||
is_undef(v[_i]) || (
|
is_undef(v[_i]) || (
|
||||||
|
@ -311,7 +309,6 @@ function first_defined(v,recursive=false,_i=0) =
|
||||||
// val = one_defined(vals, names, <dflt>)
|
// val = one_defined(vals, names, <dflt>)
|
||||||
// Topics: Undef Handling
|
// Topics: Undef Handling
|
||||||
// See Also: default(), first_defined(), num_defined(), any_defined(), all_defined()
|
// See Also: default(), first_defined(), num_defined(), any_defined(), all_defined()
|
||||||
// one_defined(vars, names, <required>)
|
|
||||||
// Description:
|
// Description:
|
||||||
// Examines the input list `vals` and returns the entry which is not `undef`.
|
// Examines the input list `vals` and returns the entry which is not `undef`.
|
||||||
// If more than one entry is not `undef` then an error is asserted, specifying
|
// If more than one entry is not `undef` then an error is asserted, specifying
|
||||||
|
@ -608,15 +605,15 @@ function segs(r) =
|
||||||
|
|
||||||
|
|
||||||
// Module: no_children()
|
// Module: no_children()
|
||||||
|
// Topics: Error Checking
|
||||||
// Usage:
|
// Usage:
|
||||||
// no_children($children);
|
// no_children($children);
|
||||||
// Topics: Error Checking
|
|
||||||
// See Also: no_function(), no_module()
|
|
||||||
// Description:
|
// Description:
|
||||||
// Assert that the calling module does not support children. Prints an error message to this effect
|
// Assert that the calling module does not support children. Prints an error message to this effect and fails if children are present,
|
||||||
// and fails if children are present, as indicated by its argument.
|
// as indicated by its argument.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// $children = number of children the module has.
|
// $children = number of children the module has.
|
||||||
|
// See Also: no_function(), no_module()
|
||||||
// Example:
|
// Example:
|
||||||
// module foo() {
|
// module foo() {
|
||||||
// no_children($children);
|
// no_children($children);
|
||||||
|
@ -679,7 +676,7 @@ function _valstr(x) =
|
||||||
// expected = The value that was expected.
|
// expected = The value that was expected.
|
||||||
// info = Extra info to print out to make the error clearer.
|
// info = Extra info to print out to make the error clearer.
|
||||||
// Example:
|
// Example:
|
||||||
// assert_approx(1/3, 0.333333333333333, str("number=",1,", demon=",3));
|
// assert_approx(1/3, 0.333333333333333, str("numer=",1,", demon=",3));
|
||||||
module assert_approx(got, expected, info) {
|
module assert_approx(got, expected, info) {
|
||||||
no_children($children);
|
no_children($children);
|
||||||
if (!approx(got, expected)) {
|
if (!approx(got, expected)) {
|
||||||
|
@ -778,8 +775,8 @@ module shape_compare(eps=1/1024) {
|
||||||
// The syntax is: `[for (INIT; CONDITION; NEXT) RETVAL]` where:
|
// The syntax is: `[for (INIT; CONDITION; NEXT) RETVAL]` where:
|
||||||
// - INIT is zero or more `let()` style assignments that are evaluated exactly one time, before the first loop.
|
// - INIT is zero or more `let()` style assignments that are evaluated exactly one time, before the first loop.
|
||||||
// - CONDITION is an expression evaluated at the start of each loop. If true, continues with the loop.
|
// - CONDITION is an expression evaluated at the start of each loop. If true, continues with the loop.
|
||||||
// - RETVAL is an expression that returns a list item at each loop beginning.
|
// - RETVAL is an expression that returns a list item for each loop.
|
||||||
// - NEXT is one or more `let()` style assignments that is evaluated for each loop.
|
// - NEXT is one or more `let()` style assignments that is evaluated at the end of each loop.
|
||||||
// .
|
// .
|
||||||
// Since the INIT phase is only run once, and the CONDITION and RETVAL expressions cannot update
|
// Since the INIT phase is only run once, and the CONDITION and RETVAL expressions cannot update
|
||||||
// variables, that means that only the NEXT phase can be used for iterative calculations.
|
// variables, that means that only the NEXT phase can be used for iterative calculations.
|
||||||
|
@ -824,7 +821,6 @@ function looping(state) = state < 2;
|
||||||
|
|
||||||
// Function: loop_while()
|
// Function: loop_while()
|
||||||
// Usage:
|
// Usage:
|
||||||
// state = loop_while(state, continue)
|
|
||||||
// state = loop_while(state, continue);
|
// state = loop_while(state, continue);
|
||||||
// Topics: Iteration
|
// Topics: Iteration
|
||||||
// See Also: looping(), loop_done()
|
// See Also: looping(), loop_done()
|
||||||
|
@ -843,7 +839,6 @@ function loop_while(state, continue) =
|
||||||
|
|
||||||
// Function: loop_done()
|
// Function: loop_done()
|
||||||
// Usage:
|
// Usage:
|
||||||
// loop_done(state)
|
|
||||||
// bool = loop_done(state);
|
// bool = loop_done(state);
|
||||||
// Topics: Iteration
|
// Topics: Iteration
|
||||||
// See Also: looping(), loop_while()
|
// See Also: looping(), loop_while()
|
||||||
|
|
|
@ -303,9 +303,9 @@ module distribute(spacing=undef, sizes=undef, dir=RIGHT, l=undef)
|
||||||
spc = !is_undef(l)? ((l - sum(gaps)) / ($children-1)) : default(spacing, 10);
|
spc = !is_undef(l)? ((l - sum(gaps)) / ($children-1)) : default(spacing, 10);
|
||||||
gaps2 = [for (gap = gaps) gap+spc];
|
gaps2 = [for (gap = gaps) gap+spc];
|
||||||
spos = dir * -sum(gaps2)/2;
|
spos = dir * -sum(gaps2)/2;
|
||||||
|
spacings = cumsum([0, each gaps2]);
|
||||||
for (i=[0:1:$children-1]) {
|
for (i=[0:1:$children-1]) {
|
||||||
totspc = sum(concat([0], slice(gaps2, 0, i)));
|
$pos = spos + spacings[i] * dir;
|
||||||
$pos = spos + totspc * dir;
|
|
||||||
$idx = i;
|
$idx = i;
|
||||||
translate($pos) children(i);
|
translate($pos) children(i);
|
||||||
}
|
}
|
||||||
|
@ -348,9 +348,9 @@ module xdistribute(spacing=10, sizes=undef, l=undef)
|
||||||
spc = !is_undef(l)? ((l - sum(gaps)) / ($children-1)) : default(spacing, 10);
|
spc = !is_undef(l)? ((l - sum(gaps)) / ($children-1)) : default(spacing, 10);
|
||||||
gaps2 = [for (gap = gaps) gap+spc];
|
gaps2 = [for (gap = gaps) gap+spc];
|
||||||
spos = dir * -sum(gaps2)/2;
|
spos = dir * -sum(gaps2)/2;
|
||||||
|
spacings = cumsum([0, each gaps2]);
|
||||||
for (i=[0:1:$children-1]) {
|
for (i=[0:1:$children-1]) {
|
||||||
totspc = sum(concat([0], slice(gaps2, 0, i)));
|
$pos = spos + spacings[i] * dir;
|
||||||
$pos = spos + totspc * dir;
|
|
||||||
$idx = i;
|
$idx = i;
|
||||||
translate($pos) children(i);
|
translate($pos) children(i);
|
||||||
}
|
}
|
||||||
|
@ -393,9 +393,9 @@ module ydistribute(spacing=10, sizes=undef, l=undef)
|
||||||
spc = !is_undef(l)? ((l - sum(gaps)) / ($children-1)) : default(spacing, 10);
|
spc = !is_undef(l)? ((l - sum(gaps)) / ($children-1)) : default(spacing, 10);
|
||||||
gaps2 = [for (gap = gaps) gap+spc];
|
gaps2 = [for (gap = gaps) gap+spc];
|
||||||
spos = dir * -sum(gaps2)/2;
|
spos = dir * -sum(gaps2)/2;
|
||||||
|
spacings = cumsum([0, each gaps2]);
|
||||||
for (i=[0:1:$children-1]) {
|
for (i=[0:1:$children-1]) {
|
||||||
totspc = sum(concat([0], slice(gaps2, 0, i)));
|
$pos = spos + spacings[i] * dir;
|
||||||
$pos = spos + totspc * dir;
|
|
||||||
$idx = i;
|
$idx = i;
|
||||||
translate($pos) children(i);
|
translate($pos) children(i);
|
||||||
}
|
}
|
||||||
|
@ -438,9 +438,9 @@ module zdistribute(spacing=10, sizes=undef, l=undef)
|
||||||
spc = !is_undef(l)? ((l - sum(gaps)) / ($children-1)) : default(spacing, 10);
|
spc = !is_undef(l)? ((l - sum(gaps)) / ($children-1)) : default(spacing, 10);
|
||||||
gaps2 = [for (gap = gaps) gap+spc];
|
gaps2 = [for (gap = gaps) gap+spc];
|
||||||
spos = dir * -sum(gaps2)/2;
|
spos = dir * -sum(gaps2)/2;
|
||||||
|
spacings = cumsum([0, each gaps2]);
|
||||||
for (i=[0:1:$children-1]) {
|
for (i=[0:1:$children-1]) {
|
||||||
totspc = sum(concat([0], slice(gaps2, 0, i)));
|
$pos = spos + spacings[i] * dir;
|
||||||
$pos = spos + totspc * dir;
|
|
||||||
$idx = i;
|
$idx = i;
|
||||||
translate($pos) children(i);
|
translate($pos) children(i);
|
||||||
}
|
}
|
||||||
|
|
|
@ -812,7 +812,9 @@ function adj_opp_to_ang(adj,opp) =
|
||||||
// Returns the area of a triangle formed between three 2D or 3D vertices.
|
// Returns the area of a triangle formed between three 2D or 3D vertices.
|
||||||
// Result will be negative if the points are 2D and in clockwise order.
|
// Result will be negative if the points are 2D and in clockwise order.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// a, b, c = The three vertices of the triangle.
|
// a = The first vertex of the triangle.
|
||||||
|
// b = The second vertex of the triangle.
|
||||||
|
// c = The third vertex of the triangle.
|
||||||
// Examples:
|
// Examples:
|
||||||
// triangle_area([0,0], [5,10], [10,0]); // Returns -50
|
// triangle_area([0,0], [5,10], [10,0]); // Returns -50
|
||||||
// triangle_area([10,0], [5,10], [0,0]); // Returns 50
|
// triangle_area([10,0], [5,10], [0,0]); // Returns 50
|
||||||
|
@ -881,7 +883,7 @@ function plane3pt_indexed(points, i1, i2, i3) =
|
||||||
// Description:
|
// Description:
|
||||||
// Returns a plane defined by a normal vector and a point.
|
// Returns a plane defined by a normal vector and a point.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// normal = Normal vector to the plane to find..
|
// normal = Normal vector to the plane to find.
|
||||||
// pt = Point 3D on the plane to find.
|
// pt = Point 3D on the plane to find.
|
||||||
// Example:
|
// Example:
|
||||||
// plane_from_normal([0,0,1], [2,2,2]); // Returns the xy plane passing through the point (2,2,2)
|
// plane_from_normal([0,0,1], [2,2,2]); // Returns the xy plane passing through the point (2,2,2)
|
||||||
|
@ -1905,8 +1907,8 @@ function align_polygon(reference, poly, angles, cp) =
|
||||||
// Description:
|
// Description:
|
||||||
// Given a simple 2D polygon, returns the 2D coordinates of the polygon's centroid.
|
// Given a simple 2D polygon, returns the 2D coordinates of the polygon's centroid.
|
||||||
// Given a simple 3D planar polygon, returns the 3D coordinates of the polygon's centroid.
|
// Given a simple 3D planar polygon, returns the 3D coordinates of the polygon's centroid.
|
||||||
// Collinear points produce an error.
|
// Collinear points produce an error. The results are meaningless for self-intersecting
|
||||||
// The results are meaningless for self-intersecting polygons or an error is produced.
|
// polygons or an error is produced.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// poly = Points of the polygon from which the centroid is calculated.
|
// poly = Points of the polygon from which the centroid is calculated.
|
||||||
// eps = Tolerance in geometric comparisons. Default: `EPSILON` (1e-9)
|
// eps = Tolerance in geometric comparisons. Default: `EPSILON` (1e-9)
|
||||||
|
|
|
@ -543,9 +543,8 @@ function _lcm(a,b) =
|
||||||
|
|
||||||
// Computes lcm for a list of values
|
// Computes lcm for a list of values
|
||||||
function _lcmlist(a) =
|
function _lcmlist(a) =
|
||||||
len(a)==1
|
len(a)==1 ? a[0] :
|
||||||
? a[0]
|
_lcmlist(concat(lcm(a[0],a[1]),list_tail(a,2)));
|
||||||
: _lcmlist(concat(slice(a,0,len(a)-2),[lcm(a[len(a)-2],a[len(a)-1])]));
|
|
||||||
|
|
||||||
|
|
||||||
// Function: lcm()
|
// Function: lcm()
|
||||||
|
|
|
@ -885,7 +885,7 @@ function assemble_a_path_from_fragments(fragments, rightmost=true, startfrag=0,
|
||||||
[outpath, newfrags]
|
[outpath, newfrags]
|
||||||
) : let(
|
) : let(
|
||||||
// Path still incomplete. Continue building it.
|
// Path still incomplete. Continue building it.
|
||||||
newpath = concat(path, slice(foundfrag, 1, -1)),
|
newpath = concat(path, list_tail(foundfrag)),
|
||||||
newfrags = concat([newpath], remainder)
|
newfrags = concat([newpath], remainder)
|
||||||
)
|
)
|
||||||
assemble_a_path_from_fragments(
|
assemble_a_path_from_fragments(
|
||||||
|
@ -1428,7 +1428,7 @@ function path_cut(path,cutdist,closed) =
|
||||||
cuts = len(cutlist)
|
cuts = len(cutlist)
|
||||||
)
|
)
|
||||||
[
|
[
|
||||||
[ each slice(path,0,cutlist[0][1]),
|
[ each list_head(path,cutlist[0][1]-1),
|
||||||
if (!approx(cutlist[0][0], path[cutlist[0][1]-1])) cutlist[0][0]
|
if (!approx(cutlist[0][0], path[cutlist[0][1]-1])) cutlist[0][0]
|
||||||
],
|
],
|
||||||
for(i=[0:1:cuts-2])
|
for(i=[0:1:cuts-2])
|
||||||
|
|
|
@ -88,7 +88,7 @@ function check_and_fix_path(path, valid_dim=undef, closed=false, name="path") =
|
||||||
is_list(valid_dim) ? str("one of ",valid_dim) : valid_dim
|
is_list(valid_dim) ? str("one of ",valid_dim) : valid_dim
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
closed && approx(path[0],select(path,-1))? slice(path,0,-2) : path;
|
closed && approx(path[0], last(path))? list_head(path) : path;
|
||||||
|
|
||||||
|
|
||||||
// Function: cleanup_region()
|
// Function: cleanup_region()
|
||||||
|
|
|
@ -413,7 +413,7 @@ function _rounding_offsets(edgespec,z_dir=1) =
|
||||||
assert(argsOK,str("Invalid specification with type ",edgetype))
|
assert(argsOK,str("Invalid specification with type ",edgetype))
|
||||||
let(
|
let(
|
||||||
offsets =
|
offsets =
|
||||||
edgetype == "profile"? scale([-1,z_dir], p=slice(points,1,-1)) :
|
edgetype == "profile"? scale([-1,z_dir], p=list_tail(points)) :
|
||||||
edgetype == "chamfer"? chamf_width==0 && chamf_height==0? [] : [[-chamf_width,z_dir*abs(chamf_height)]] :
|
edgetype == "chamfer"? chamf_width==0 && chamf_height==0? [] : [[-chamf_width,z_dir*abs(chamf_height)]] :
|
||||||
edgetype == "teardrop"? (
|
edgetype == "teardrop"? (
|
||||||
radius==0? [] : concat(
|
radius==0? [] : concat(
|
||||||
|
|
|
@ -851,7 +851,7 @@ function _turtle_command(command, parm, parm2, state, index) =
|
||||||
)
|
)
|
||||||
list_set(
|
list_set(
|
||||||
state, [path,step], [
|
state, [path,step], [
|
||||||
concat(state[path], slice(arcpath,1,-1)),
|
concat(state[path], list_tail(arcpath)),
|
||||||
rot(lrsign * myangle,p=state[step],planar=true)
|
rot(lrsign * myangle,p=state[step],planar=true)
|
||||||
]
|
]
|
||||||
) :
|
) :
|
||||||
|
@ -877,7 +877,7 @@ function _turtle_command(command, parm, parm2, state, index) =
|
||||||
)
|
)
|
||||||
list_set(
|
list_set(
|
||||||
state, [path,step], [
|
state, [path,step], [
|
||||||
concat(state[path], slice(arcpath,1,-1)),
|
concat(state[path], list_tail(arcpath)),
|
||||||
rot(delta_angle,p=state[step],planar=true)
|
rot(delta_angle,p=state[step],planar=true)
|
||||||
]
|
]
|
||||||
) :
|
) :
|
||||||
|
|
|
@ -48,24 +48,33 @@ module test_last() {
|
||||||
}
|
}
|
||||||
test_last();
|
test_last();
|
||||||
|
|
||||||
module test_delete_last() {
|
|
||||||
|
module test_list_head() {
|
||||||
list = [1,2,3,4];
|
list = [1,2,3,4];
|
||||||
assert(delete_last(list) == [1,2,3]);
|
assert_equal(list_head(list), [1,2,3]);
|
||||||
assert(delete_last([1]) == []);
|
assert_equal(list_head([1]), []);
|
||||||
assert(delete_last([]) == []);
|
assert_equal(list_head([]), []);
|
||||||
|
assert_equal(list_head(list,-3), [1,2]);
|
||||||
|
assert_equal(list_head(list,1), [1,2]);
|
||||||
|
assert_equal(list_head(list,2), [1,2,3]);
|
||||||
|
assert_equal(list_head(list,6), [1,2,3,4]);
|
||||||
|
assert_equal(list_head(list,-6), []);
|
||||||
}
|
}
|
||||||
test_delete_last();
|
test_list_head();
|
||||||
|
|
||||||
|
|
||||||
module test_slice() {
|
module test_list_tail() {
|
||||||
assert(slice([3,4,5,6,7,8,9], 3, 5) == [6,7]);
|
list = [1,2,3,4];
|
||||||
assert(slice([3,4,5,6,7,8,9], 2, -1) == [5,6,7,8,9]);
|
assert_equal(list_tail(list), [2,3,4]);
|
||||||
assert(slice([3,4,5,6,7,8,9], 1, 1) == []);
|
assert_equal(list_tail([1]), []);
|
||||||
assert(slice([3,4,5,6,7,8,9], 6, -1) == [9]);
|
assert_equal(list_tail([]), []);
|
||||||
assert(slice([3,4,5,6,7,8,9], 2, -2) == [5,6,7,8]);
|
assert_equal(list_tail(list,-3), [2,3,4]);
|
||||||
assert(slice([], 2, -2) == []);
|
assert_equal(list_tail(list,2), [3,4]);
|
||||||
|
assert_equal(list_tail(list,3), [4]);
|
||||||
|
assert_equal(list_tail(list,6), []);
|
||||||
|
assert_equal(list_tail(list,-6), [1,2,3,4]);
|
||||||
}
|
}
|
||||||
test_slice();
|
test_list_tail();
|
||||||
|
|
||||||
|
|
||||||
module test_in_list() {
|
module test_in_list() {
|
||||||
|
|
|
@ -540,28 +540,28 @@ function _turtle3d_command(command, parm, parm2, state, index) =
|
||||||
command=="addlength" ? list_set(state, movestep, state[movestep]+parm) :
|
command=="addlength" ? list_set(state, movestep, state[movestep]+parm) :
|
||||||
command=="arcsteps" ? assert(is_int(parm) && parm>0, str("\"",command,"\" requires a postive integer argument at index ",index))
|
command=="arcsteps" ? assert(is_int(parm) && parm>0, str("\"",command,"\" requires a postive integer argument at index ",index))
|
||||||
list_set(state, arcsteps, parm) :
|
list_set(state, arcsteps, parm) :
|
||||||
command=="roll" ? list_set(state, trlist, concat(slice(state[trlist],0,-2), [lastT*xrot(parm)])):
|
command=="roll" ? list_set(state, trlist, concat(list_head(state[trlist]), [lastT*xrot(parm)])):
|
||||||
in_list(command,["right","left","up","down"]) ?
|
in_list(command,["right","left","up","down"]) ?
|
||||||
list_set(state, trlist, concat(slice(state[trlist],0,-2), [lastT*_turtle3d_rotation(command,default(parm,state[angle]))])):
|
list_set(state, trlist, concat(list_head(state[trlist]), [lastT*_turtle3d_rotation(command,default(parm,state[angle]))])):
|
||||||
in_list(command,["xrot","yrot","zrot"]) ?
|
in_list(command,["xrot","yrot","zrot"]) ?
|
||||||
let(
|
let(
|
||||||
Trot = _rotpart(lastT), // Extract rotational part of lastT
|
Trot = _rotpart(lastT), // Extract rotational part of lastT
|
||||||
shift = _transpart(lastT) // Translation part of lastT
|
shift = _transpart(lastT) // Translation part of lastT
|
||||||
)
|
)
|
||||||
list_set(state, trlist, concat(slice(state[trlist],0,-2),
|
list_set(state, trlist, concat(list_head(state[trlist]),
|
||||||
[move(shift)*_turtle3d_rotation(command,default(parm,state[angle])) * Trot])):
|
[move(shift)*_turtle3d_rotation(command,default(parm,state[angle])) * Trot])):
|
||||||
command=="rot" ?
|
command=="rot" ?
|
||||||
let(
|
let(
|
||||||
Trot = _rotpart(lastT), // Extract rotational part of lastT
|
Trot = _rotpart(lastT), // Extract rotational part of lastT
|
||||||
shift = _transpart(lastT) // Translation part of lastT
|
shift = _transpart(lastT) // Translation part of lastT
|
||||||
)
|
)
|
||||||
list_set(state, trlist, concat(slice(state[trlist],0,-2),[move(shift) * parm * Trot])):
|
list_set(state, trlist, concat(list_head(state[trlist]),[move(shift) * parm * Trot])):
|
||||||
command=="setdir" ?
|
command=="setdir" ?
|
||||||
let(
|
let(
|
||||||
Trot = _rotpart(lastT),
|
Trot = _rotpart(lastT),
|
||||||
shift = _transpart(lastT)
|
shift = _transpart(lastT)
|
||||||
)
|
)
|
||||||
list_set(state, trlist, concat(slice(state[trlist],0,-2),
|
list_set(state, trlist, concat(list_head(state[trlist]),
|
||||||
[move(shift)*rot(from=apply(Trot,RIGHT),to=parm) * Trot ])):
|
[move(shift)*rot(from=apply(Trot,RIGHT),to=parm) * Trot ])):
|
||||||
in_list(command,["arcleft","arcright","arcup","arcdown"]) ?
|
in_list(command,["arcleft","arcright","arcup","arcdown"]) ?
|
||||||
assert(is_num(parm),str("\"",command,"\" command requires a numeric radius value at index ",index))
|
assert(is_num(parm),str("\"",command,"\" command requires a numeric radius value at index ",index))
|
||||||
|
|
Loading…
Reference in a new issue