misc tweaks

This commit is contained in:
Adrian Mariano 2021-11-09 22:27:55 -05:00
parent 22847597b1
commit a81b6c6931
14 changed files with 242 additions and 339 deletions

View file

@ -290,6 +290,53 @@ function compare_lists(a, b) =
// Section: Finding the index of the minimum or maximum of a list
// Function: min_index()
// Usage:
// idx = min_index(vals);
// idxlist = min_index(vals, all=true);
// Topics: List Handling
// See Also: max_index(), is_increasing(), is_decreasing()
// Description:
// Returns the index of the first occurrence of the minimum value in the given list.
// If `all` is true then returns a list of all indices where the minimum value occurs.
// Arguments:
// vals = vector of values
// all = set to true to return indices of all occurences of the minimum. Default: false
// Example:
// a = min_index([5,3,9,6,2,7,8,2,1]); // Returns: 8
// b = min_index([5,3,9,6,2,7,8,2,7],all=true); // Returns: [4,7]
function min_index(vals, all=false) =
assert( is_vector(vals) && len(vals)>0 , "Invalid or empty list of numbers.")
all ? search(min(vals),vals,0) : search(min(vals), vals)[0];
// Function: max_index()
// Usage:
// idx = max_index(vals);
// idxlist = max_index(vals, all=true);
// Topics: List Handling
// See Also: min_index(), is_increasing(), is_decreasing()
// Description:
// Returns the index of the first occurrence of the maximum value in the given list.
// If `all` is true then returns a list of all indices where the maximum value occurs.
// Arguments:
// vals = vector of values
// all = set to true to return indices of all occurences of the maximum. Default: false
// Example:
// max_index([5,3,9,6,2,7,8,9,1]); // Returns: 2
// max_index([5,3,9,6,2,7,8,9,1],all=true); // Returns: [2,7]
function max_index(vals, all=false) =
assert( is_vector(vals) && len(vals)>0 , "Invalid or empty list of numbers.")
all ? search(max(vals),vals,0) : search(max(vals), vals)[0];
// Section: Dealing with duplicate list entries

View file

@ -255,7 +255,7 @@ module cubetruss_foot(w=1, size, strut, clipthick, anchor=CENTER, spin=0, orient
down(clipthick) {
// Base
up(clipthick/2) {
cuboid([w*(size-strut)+strut+2*clipthick, size-2*strut, clipthick], chamfer=strut, edges=edges("Z"));
cuboid([w*(size-strut)+strut+2*clipthick, size-2*strut, clipthick], chamfer=strut, edges="Z");
}
// Walls
@ -490,7 +490,7 @@ module cubetruss(extents=6, clips=[], bracing, size, strut, clipthick, anchor=CE
// Creates a corner cubetruss with extents jutting out in one or more directions.
// Arguments:
// h = The number of cubes high to make the base and horizontal extents.
// extents = The number of cubes to extend beyond the corner. If given as a vector of cube counts, gives the number of cubes to extend right, back, left, front, and up in order.
// extents = The number of cubes to extend beyond the corner. If given as a vector of cube counts, gives the number of cubes to extend right, back, left, front, and up in order. If the vector is shorter than length 5 the extra cube counts are taken to be zero.
// size = The length of each side of the cubetruss cubes. Default: `$cubetruss_size` (usually 30)
// strut = The width of the struts on the cubetruss cubes. Default: `$cubetruss_strut_size` (usually 3)
// bracing = If true, adds internal cross-braces. Default: `$cubetruss_bracing` (usually true)
@ -511,7 +511,8 @@ module cubetruss_corner(h=1, extents=[1,1,0,0,1], bracing, size, strut, clipthic
strut = is_undef(strut)? $cubetruss_strut_size : strut;
bracing = is_undef(bracing)? $cubetruss_bracing : bracing;
clipthick = is_undef(clipthick)? $cubetruss_clip_thickness : clipthick;
exts = is_vector(extents)? list_fit(extents,5,fill=0) : [extents, extents, 0, 0, extents];
exts = is_vector(extents)? list_pad(extents,5,fill=0) : [extents, extents, 0, 0, extents];
dummy = assert(len(exts)==5, "Input extents must be a scalar or vector with length 5 or less.");
s = [cubetruss_dist(exts[0]+1+exts[2],1), cubetruss_dist(exts[1]+1+exts[3],1), cubetruss_dist(h+exts[4],1)];
offset = [cubetruss_dist(exts[0]-exts[2],0), cubetruss_dist(exts[1]-exts[3],0), cubetruss_dist(h+exts[4]-1,0)]/2;
attachable(anchor,spin,orient, size=s, offset=offset) {

View file

@ -699,10 +699,13 @@ function arc(N, r, angle, d, cp, points, width, thickness, start, wedge=false, l
);
module arc(N, r, angle, d, cp, points, width, thickness, start, wedge=false)
module arc(N, r, angle, d, cp, points, width, thickness, start, wedge=false, anchor=CENTER, spin=0)
{
path = arc(N=N, r=r, angle=angle, d=d, cp=cp, points=points, width=width, thickness=thickness, start=start, wedge=wedge);
attachable(anchor,spin, two_d=true, path=path) {
polygon(path);
children();
}
}
@ -1018,4 +1021,83 @@ function _turtle_command(command, parm, parm2, state, index) =
[];
// Section: Debugging polygons
// Module: debug_polygon()
// Usage:
// debug_polygon(points, paths, [vertices=], [edges=], [convexity=], [size=]);
// Description:
// A drop-in replacement for `polygon()` that renders and labels the path points and
// edges. The start of each path is marked with a blue circle and the end with a pink diamond.
// You can suppress the display of vertex or edge labeling using the `vertices` and `edges` arguments.
// Arguments:
// points = The array of 2D polygon vertices.
// paths = The path connections between the vertices.
// ---
// vertices = if true display vertex labels and start/end markers. Default: true
// edges = if true display edge labels. Default: true
// convexity = The max number of walls a ray can pass through the given polygon paths.
// size = The base size of the line and labels.
// Example(Big2D):
// debug_polygon(
// points=concat(
// regular_ngon(or=10, n=8),
// regular_ngon(or=8, n=8)
// ),
// paths=[
// [for (i=[0:7]) i],
// [for (i=[15:-1:8]) i]
// ]
// );
module debug_polygon(points, paths, vertices=true, edges=true, convexity=2, size=1)
{
paths = is_undef(paths)? [count(points)] :
is_num(paths[0])? [paths] :
paths;
echo(points=points);
echo(paths=paths);
linear_extrude(height=0.01, convexity=convexity, center=true) {
polygon(points=points, paths=paths, convexity=convexity);
}
dups = vector_search(points, EPSILON, points);
if (vertices) color("red") {
for (ind=dups){
numstr = str_join([for(i=ind) str(i)],",");
up(0.2) {
translate(points[ind[0]]) {
linear_extrude(height=0.1, convexity=10, center=true) {
text(text=numstr, size=size, halign="center", valign="center");
}
}
}
}
}
if (edges)
for (j = [0:1:len(paths)-1]) {
path = paths[j];
if (vertices){
translate(points[path[0]]) {
color("cyan") up(0.1) cylinder(d=size*1.5, h=0.01, center=false, $fn=12);
}
translate(points[path[len(path)-1]]) {
color("pink") up(0.11) cylinder(d=size*1.5, h=0.01, center=false, $fn=4);
}
}
for (i = [0:1:len(path)-1]) {
midpt = (points[path[i]] + points[path[(i+1)%len(path)]])/2;
color("blue") {
up(0.2) {
translate(midpt) {
linear_extrude(height=0.1, convexity=10, center=true) {
text(text=str(chr(65+j),i), size=size/2, halign="center", valign="center");
}
}
}
}
}
}
}
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap

View file

@ -172,24 +172,6 @@ function in_list(val,list,idx) =
: [for(hit=allhits) if (list[hit][idx]==val) 1] != [];
// Function: add_scalar()
// Usage:
// v = add_scalar(v, s);
// Topics: List Handling
// Description:
// Given a list and a scalar, returns the list with the scalar added to each item in it.
// If given a list of arrays, recursively adds the scalar to the each array.
// Arguments:
// v = The initial array.
// s = A scalar value to add to every item in the array.
// Example:
// a = add_scalar([1,2,3],3); // Returns: [4,5,6]
// b = add_scalar([[1,2,3],[3,4,5]],3); // Returns: [[4,5,6],[6,7,8]]
function add_scalar(v,s) =
is_finite(s) ? [for (x=v) is_list(x)? add_scalar(x,s) : is_finite(x) ? x+s: x] : v;
// Section: List Indexing
@ -620,6 +602,25 @@ function repeat_entries(list, N, exact=true) =
[for(i=[0:length-1]) each repeat(list[i],reps[i])];
// Function: list_pad()
// Usage:
// arr = list_pad(array, minlen, [fill]);
// Topics: List Handling
// See Also: force_list(), scalar_vec3()
// Description:
// If the list `array` is shorter than `minlen` length, pad it to length with the value given in `fill`.
// Arguments:
// array = A list.
// minlen = The minimum length to pad the list to.
// fill = The value to pad the list with. Default: `undef`
// Example:
// list = [3,4,5];
// nlist = list_pad(list,5,23); // Returns: [3,4,5,23,23]
function list_pad(array, minlen, fill) =
assert(is_list(array), "Invalid input." )
concat(array,repeat(fill,minlen-len(array)));
// Function: list_set()
// Usage:
// list = list_set(list, indices, values, [dflt], [minlen]);
@ -812,70 +813,6 @@ function list_remove_values(list,values=[],all=false) =
];
// Section: List Length Manipulation
// Function: list_pad()
// Usage:
// arr = list_pad(array, minlen, [fill]);
// Topics: List Handling
// See Also: list_trim(), list_fit()
// Description:
// If the list `array` is shorter than `minlen` length, pad it to length with the value given in `fill`.
// Arguments:
// array = A list.
// minlen = The minimum length to pad the list to.
// fill = The value to pad the list with. Default: `undef`
// Example:
// list = [3,4,5];
// nlist = list_pad(list,5,23); // Returns: [3,4,5,23,23]
function list_pad(array, minlen, fill) =
assert(is_list(array), "Invalid input." )
concat(array,repeat(fill,minlen-len(array)));
// Function: list_trim()
// Usage:
// arr = list_trim(array, maxlen);
// Topics: List Handling
// See Also: list_pad(), list_fit()
// Description:
// If the list `array` is longer than `maxlen` length, truncates it to be `maxlen` items long.
// Arguments:
// array = A list.
// minlen = The minimum length to pad the list to.
// Example:
// list = [3,4,5,6,7,8];
// nlist = list_trim(list,4); // Returns: [3,4,5,6]
function list_trim(array, maxlen) =
assert(is_list(array), "Invalid input." )
[for (i=[0:1:min(len(array),maxlen)-1]) array[i]];
// Function: list_fit()
// Usage:
// arr = list_fit(array, length, fill);
// Topics: List Handling
// See Also: list_pad(), list_trim()
// Description:
// If the list `array` is longer than `length` items long, truncates it to be exactly `length` items long.
// If the list `array` is shorter than `length` items long, pad it to length with the value given in `fill`.
// Arguments:
// array = A list.
// minlen = The minimum length to pad the list to.
// fill = The value to pad the list with. Default: `undef`
// Example:
// list = [3,4,5,6];
// nlist = list_fit(list,3); // Returns: [3,4,5]
// Example:
// list = [3,4,5,6];
// nlist = list_fit(list,6,23); // Returns: [3,4,5,6,23,23]
function list_fit(array, length, fill) =
assert(is_list(array), "Invalid input." )
let(l=len(array))
l==length ? array :
l> length ? list_trim(array,length)
: list_pad(array,length,fill);
// Section: Iteration Helpers
@ -1057,8 +994,6 @@ function permutations(l,n=2) =
// Section: Changing list structure
// Function: list_to_matrix()
// Usage:
// groups = list_to_matrix(v, [cnt], [dflt]);
@ -1142,36 +1077,6 @@ function zip(a,b,c) =
[for (i=[0:1:n-1]) [for (x=a) x[i]]];
// Function: zip_long()
// Usage:
// pairs = zip_long(a,b);
// triples = zip_long(a,b,c);
// quads = zip_long([LIST1,LIST2,LIST3,LIST4]);
// Topics: List Handling, Iteration
// See Also: zip()
// Description:
// Zips together two or more lists into a single list. For example, if you have two
// lists [3,4,5], and [8,7,6], and zip them together, you get [ [3,8],[4,7],[5,6] ].
// The list returned will be as long as the longest list passed to zip_long(), with
// shorter lists padded by the value in `fill`.
// Arguments:
// a = The first list, or a list of lists if b and c are not given.
// b = The second list, if given.
// c = The third list, if given.
// fill = The value to pad shorter lists with. Default: undef
// Example:
// a = [9,8,7,6]; b = [1,2,3];
// for (p=zip_long(a,b,fill=88)) echo(p);
// // ECHO: [9,1]
// // ECHO: [8,2]
// // ECHO: [7,3]
// // ECHO: [6,88]]
function zip_long(a,b,c,fill) =
b!=undef? zip_long([a,b,if (c!=undef) c],fill=fill) :
let(n = max_length(a))
[for (i=[0:1:n-1]) [for (x=a) i<len(x)? x[i] : fill]];
// Section: Set Manipulation

View file

@ -483,7 +483,7 @@ module chain_hull()
// If you set caps to true for asymmetric children then incorrect caps will be generated.
// Arguments:
// path = The 2D path to extrude the geometry along.
// caps = If true, caps each end of the path with a `rotate_extrude()`d copy of the children. This may interact oddly when given asymmetric profile children. Default: false
// caps = If true, caps each end of the path with a rounded copy of the children. Children must by symmetric across the Y axis, or results are wrong. Default: false
// closed = If true, connect the starting point of the path to the ending point. Default: false
// convexity = The max number of times a line could pass though a wall. Default: 10
// s = Mask size to use. Use a number larger than twice your object's largest axis. If you make this too large, it messes with centering your view. Default: The length of the diagonal of the path's bounding box.

View file

@ -136,7 +136,7 @@ module nema11_stepper(h=24, shaft=5, shaft_len=20, anchor=TOP, spin=0, orient=UP
union() {
difference() {
color([0.4, 0.4, 0.4])
cuboid(size=[motor_width, motor_width, h], chamfer=2, edges=edges("Z"), anchor=TOP);
cuboid(size=[motor_width, motor_width, h], chamfer=2, edges="Z", anchor=TOP);
color("silver")
xcopies(screw_spacing)
ycopies(screw_spacing)
@ -201,7 +201,7 @@ module nema14_stepper(h=24, shaft=5, shaft_len=24, anchor=TOP, spin=0, orient=UP
union() {
difference() {
color([0.4, 0.4, 0.4])
cuboid(size=[motor_width, motor_width, h], chamfer=2, edges=edges("Z"), anchor=TOP);
cuboid(size=[motor_width, motor_width, h], chamfer=2, edges="Z", anchor=TOP);
color("silver")
xcopies(screw_spacing)
ycopies(screw_spacing)
@ -266,7 +266,7 @@ module nema17_stepper(h=34, shaft=5, shaft_len=20, anchor=TOP, spin=0, orient=UP
union() {
difference() {
color([0.4, 0.4, 0.4])
cuboid([motor_width, motor_width, h], chamfer=2, edges=edges("Z"), anchor=TOP);
cuboid([motor_width, motor_width, h], chamfer=2, edges="Z", anchor=TOP);
color("silver")
xcopies(screw_spacing)
ycopies(screw_spacing)
@ -351,7 +351,7 @@ module nema23_stepper(h=50, shaft=6.35, shaft_len=25, anchor=TOP, spin=0, orient
difference() {
union() {
color([0.4, 0.4, 0.4])
cuboid([motor_width, motor_width, h], chamfer=2, edges=edges("Z"), anchor=TOP);
cuboid([motor_width, motor_width, h], chamfer=2, edges="Z", anchor=TOP);
color([0.4, 0.4, 0.4])
cylinder(h=plinth_height, d=plinth_diam);
color("silver")
@ -418,7 +418,7 @@ module nema34_stepper(h=75, shaft=12.7, shaft_len=32, anchor=TOP, spin=0, orient
difference() {
union() {
color([0.4, 0.4, 0.4])
cuboid(size=[motor_width, motor_width, h], chamfer=2, edges=edges("Z"), anchor=TOP);
cuboid(size=[motor_width, motor_width, h], chamfer=2, edges="Z", anchor=TOP);
color([0.4, 0.4, 0.4])
cylinder(h=plinth_height, d=plinth_diam);
color("silver")

View file

@ -296,9 +296,7 @@ function _path_self_intersections(path, closed=true, eps=EPSILON) =
[isect[0], i, isect[1], j, isect[2]]
];
// Section: Resampling: changing the number of points in a path
// Section: Resampling---changing the number of points in a path
// Input `data` is a list that sums to an integer.

View file

@ -224,12 +224,14 @@ module circle(r, d, anchor=CENTER, spin=0) {
// Topics: Shapes (2D), Paths (2D), Path Generators, Attachable
// See Also: circle()
// Description:
// When called as a module, creates a 2D polygon that approximates a circle of the given size.
// When called as a function, returns a 2D list of points (path) for a polygon that approximates a circle of the given size.
// When called as a module, creates a 2D polygon that approximates a circle or ellipse of the given size.
// When called as a function, returns a 2D list of points (path) for a polygon that approximates a circle or ellipse of the given size.
// Note that the point list or shape is the same as the one you would get by scaling the output of {{circle()}}, but with this module your
// attachments to the oval will
// Arguments:
// r = Radius of the circle/oval to create. Can be a scalar, or a list of sizes per axis.
// r = Radius of the circle or pair of semiaxes of oval
// ---
// d = Diameter of the circle/oval to create. Can be a scalar, or a list of sizes per axis.
// d = Diameter of the circle or a pair giving the full X and Y axis lengths.
// realign = If true, rotates the polygon that approximates the circle/oval by half of one size.
// circum = If true, the polygon that approximates the circle will be upsized slightly to circumscribe the theoretical circle. If false, it inscribes the theoretical circle. Default: false
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `CENTER`
@ -246,6 +248,7 @@ module circle(r, d, anchor=CENTER, spin=0) {
// path = oval(d=50, anchor=FRONT, spin=45);
module oval(r, d, realign=false, circum=false, anchor=CENTER, spin=0) {
r = get_radius(r=r, d=d, dflt=1);
dummy = assert((is_finite(r) || is_vector(r,2)) && all_positive(r), "Invalid radius or diameter for oval");
sides = segs(max(r));
sc = circum? (1 / cos(180/sides)) : 1;
rx = default(r[0],r) * sc;
@ -1710,76 +1713,6 @@ function mask2d_ogee(pattern, excess=0.01, anchor=CENTER, spin=0) =
// Section: Debugging polygons
// Module: debug_polygon()
// Usage:
// debug_polygon(points, paths, [convexity=], [size=]);
// Description:
// A drop-in replacement for `polygon()` that renders and labels the path points.
// Arguments:
// points = The array of 2D polygon vertices.
// paths = The path connections between the vertices.
// ---
// convexity = The max number of walls a ray can pass through the given polygon paths.
// size = The base size of the line and labels.
// Example(Big2D):
// debug_polygon(
// points=concat(
// regular_ngon(or=10, n=8),
// regular_ngon(or=8, n=8)
// ),
// paths=[
// [for (i=[0:7]) i],
// [for (i=[15:-1:8]) i]
// ]
// );
module debug_polygon(points, paths, convexity=2, size=1)
{
paths = is_undef(paths)? [[for (i=[0:1:len(points)-1]) i]] :
is_num(paths[0])? [paths] :
paths;
echo(points=points);
echo(paths=paths);
linear_extrude(height=0.01, convexity=convexity, center=true) {
polygon(points=points, paths=paths, convexity=convexity);
}
for (i = [0:1:len(points)-1]) {
color("red") {
up(0.2) {
translate(points[i]) {
linear_extrude(height=0.1, convexity=10, center=true) {
text(text=str(i), size=size, halign="center", valign="center");
}
}
}
}
}
for (j = [0:1:len(paths)-1]) {
path = paths[j];
translate(points[path[0]]) {
color("cyan") up(0.1) cylinder(d=size*1.5, h=0.01, center=false, $fn=12);
}
translate(points[path[len(path)-1]]) {
color("pink") up(0.11) cylinder(d=size*1.5, h=0.01, center=false, $fn=4);
}
for (i = [0:1:len(path)-1]) {
midpt = (points[path[i]] + points[path[(i+1)%len(path)]])/2;
color("blue") {
up(0.2) {
translate(midpt) {
linear_extrude(height=0.1, convexity=10, center=true) {
text(text=str(chr(65+j),i), size=size/2, halign="center", valign="center");
}
}
}
}
}
}
}
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap

View file

@ -37,11 +37,11 @@ module slider(l=30, w=10, h=10, base=10, wall=5, ang=30, anchor=BOTTOM, spin=0,
zrot(90)
down(base+h/2) {
// Base
cuboid([full_width, l, base-$slop], chamfer=2, edges=edges([FRONT,BACK], except=BOT), anchor=BOTTOM);
cuboid([full_width, l, base-$slop], chamfer=2, edges=[FRONT,BACK], except_edges=BOT, anchor=BOTTOM);
// Wall
xflip_copy(offset=w/2+$slop) {
cuboid([wall, l, full_height], chamfer=2, edges=edges(RIGHT, except=BOT), anchor=BOTTOM+LEFT);
cuboid([wall, l, full_height], chamfer=2, edges=RIGHT, except_edges=BOT, anchor=BOTTOM+LEFT);
}
// Sliders

View file

@ -1,32 +0,0 @@
include <test_affine.scad>
include <test_attachments.scad>
include <test_comparisons.scad>
include <test_coords.scad>
include <test_cubetruss.scad>
include <test_distributors.scad>
include <test_drawing.scad>
include <test_edges.scad>
include <test_fnliterals.scad>
include <test_geometry.scad>
include <test_hull.scad>
include <test_linalg.scad>
include <test_linear_bearings.scad>
include <test_lists.scad>
include <test_math.scad>
include <test_mutators.scad>
include <test_paths.scad>
include <test_quaternions.scad>
include <test_regions.scad>
include <test_rounding.scad>
include <test_screw_drive.scad>
include <test_shapes2d.scad>
include <test_shapes3d.scad>
include <test_skin.scad>
include <test_strings.scad>
include <test_structs.scad>
include <test_transforms.scad>
include <test_trigonometry.scad>
include <test_utility.scad>
include <test_vectors.scad>
include <test_version.scad>
include <test_vnf.scad>

View file

@ -391,3 +391,19 @@ module test_compare_lists() {
}
test_compare_lists();
module test_min_index() {
assert(min_index([5,3,9,6,2,7,8,2,1])==8);
assert(min_index([5,3,9,6,2,7,8,2,7],all=true)==[4,7]);
}
test_min_index();
module test_max_index() {
assert(max_index([5,3,9,6,2,7,8,9,1])==2);
assert(max_index([5,3,9,6,2,7,8,9,7],all=true)==[2,7]);
}
test_max_index();

View file

@ -241,22 +241,6 @@ module test_list_pad() {
test_list_pad();
module test_list_trim() {
assert(list_trim([4,5,6], 5) == [4,5,6]);
assert(list_trim([4,5,6,7,8], 5) == [4,5,6,7,8]);
assert(list_trim([3,4,5,6,7,8,9], 5) == [3,4,5,6,7]);
}
test_list_trim();
module test_list_fit() {
assert(list_fit([4,5,6], 5, 8) == [4,5,6,8,8]);
assert(list_fit([4,5,6,7,8], 5, 8) == [4,5,6,7,8]);
assert(list_fit([3,4,5,6,7,8,9], 5, 8) == [3,4,5,6,7]);
}
test_list_fit();
module test_idx() {
colors = ["red", "green", "blue", "cyan"];
assert([for (i=idx(colors)) i] == [0,1,2,3]);
@ -327,13 +311,6 @@ test_set_intersection();
// Arrays
module test_add_scalar() {
assert(add_scalar([1,2,3],3) == [4,5,6]);
assert(add_scalar([[1,2,3],[3,4,5]],3) == [[4,5,6],[6,7,8]]);
}
test_add_scalar();
module test_force_list() {
assert_equal(force_list([3,4,5]), [3,4,5]);

View file

@ -242,19 +242,10 @@ module test_vector_nearest(){
test_vector_nearest();
module test_min_index() {
assert(min_index([5,3,9,6,2,7,8,2,1])==8);
assert(min_index([5,3,9,6,2,7,8,2,7],all=true)==[4,7]);
module test_add_scalar() {
assert(add_scalar([1,2,3],3) == [4,5,6]);
}
test_min_index();
module test_max_index() {
assert(max_index([5,3,9,6,2,7,8,9,1])==2);
assert(max_index([5,3,9,6,2,7,8,9,7],all=true)==[2,7]);
}
test_max_index();
test_add_scalar();

View file

@ -6,7 +6,7 @@
//////////////////////////////////////////////////////////////////////
// Section: Vector Manipulation
// Section: Vector Testing
// Function: is_vector()
@ -42,14 +42,24 @@ function is_vector(v, length, zero, all_nonzero=false, eps=EPSILON) =
&& (!all_nonzero || all_nonzero(v)) ;
// Function: v_theta()
// Section: Scalar operations on vectors
// Function: add_scalar()
// Usage:
// theta = v_theta([X,Y]);
// v_new = add_scalar(v, s);
// Topics: List Handling
// Description:
// Given a vector, returns the angle in degrees counter-clockwise from X+ on the XY plane.
function v_theta(v) =
assert( is_vector(v,2) || is_vector(v,3) , "Invalid vector")
atan2(v.y,v.x);
// Given a vector and a scalar, returns the vector with the scalar added to each item in it.
// Arguments:
// v = The initial array.
// s = A scalar value to add to every item in the array.
// Example:
// a = add_scalar([1,2,3],3); // Returns: [4,5,6]
function add_scalar(v,s) =
assert(is_vector(v), "Input v must be a vector")
assert(is_finite(s), "Input s must be a finite scalar")
[for(entry=v) entry+s];
// Function: v_mul()
@ -132,26 +142,7 @@ function v_lookup(x, v) =
lerp(lo,hi,u);
// Function: pointlist_bounds()
// Usage:
// pt_pair = pointlist_bounds(pts);
// Topics: Geometry, Bounding Boxes, Bounds
// Description:
// Finds the bounds containing all the points in `pts` which can be a list of points in any dimension.
// Returns a list of two items: a list of the minimums and a list of the maximums. For example, with
// 3d points `[[MINX, MINY, MINZ], [MAXX, MAXY, MAXZ]]`
// Arguments:
// pts = List of points.
function pointlist_bounds(pts) =
assert(is_path(pts,dim=undef,fast=true) , "Invalid pointlist." )
let(
select = ident(len(pts[0])),
spread = [
for(i=[0:len(pts[0])-1])
let( spreadi = pts*select[i] )
[ min(spreadi), max(spreadi) ]
]
) transpose(spread);
// Section: Vector Properties
// Function: unit()
@ -176,6 +167,17 @@ function unit(v, error=[[["ASSERT"]]]) =
v/norm(v);
// Function: v_theta()
// Usage:
// theta = v_theta([X,Y]);
// Description:
// Given a vector, returns the angle in degrees counter-clockwise from X+ on the XY plane.
function v_theta(v) =
assert( is_vector(v,2) || is_vector(v,3) , "Invalid vector")
atan2(v.y,v.x);
// Function: vector_angle()
// Usage:
// vector_angle(v1,v2);
@ -263,50 +265,33 @@ function vector_axis(v1,v2=undef,v3=undef) =
// Function: min_index()
// Usage:
// idx = min_index(vals);
// idxlist = min_index(vals, all=true);
// Topics: List Handling
// See Also: max_index(), is_increasing(), is_decreasing()
// Description:
// Returns the index of the first occurrence of the minimum value in the given list.
// If `all` is true then returns a list of all indices where the minimum value occurs.
// Arguments:
// vals = vector of values
// all = set to true to return indices of all occurences of the minimum. Default: false
// Example:
// a = min_index([5,3,9,6,2,7,8,2,1]); // Returns: 8
// b = min_index([5,3,9,6,2,7,8,2,7],all=true); // Returns: [4,7]
function min_index(vals, all=false) =
assert( is_vector(vals) && len(vals)>0 , "Invalid or empty list of numbers.")
all ? search(min(vals),vals,0) : search(min(vals), vals)[0];
// Function: max_index()
// Usage:
// idx = max_index(vals);
// idxlist = max_index(vals, all=true);
// Topics: List Handling
// See Also: min_index(), is_increasing(), is_decreasing()
// Description:
// Returns the index of the first occurrence of the maximum value in the given list.
// If `all` is true then returns a list of all indices where the maximum value occurs.
// Arguments:
// vals = vector of values
// all = set to true to return indices of all occurences of the maximum. Default: false
// Example:
// max_index([5,3,9,6,2,7,8,9,1]); // Returns: 2
// max_index([5,3,9,6,2,7,8,9,1],all=true); // Returns: [2,7]
function max_index(vals, all=false) =
assert( is_vector(vals) && len(vals)>0 , "Invalid or empty list of numbers.")
all ? search(max(vals),vals,0) : search(max(vals), vals)[0];
// Section: Vector Searching
// Function: pointlist_bounds()
// Usage:
// pt_pair = pointlist_bounds(pts);
// Topics: Geometry, Bounding Boxes, Bounds
// Description:
// Finds the bounds containing all the points in `pts` which can be a list of points in any dimension.
// Returns a list of two items: a list of the minimums and a list of the maximums. For example, with
// 3d points `[[MINX, MINY, MINZ], [MAXX, MAXY, MAXZ]]`
// Arguments:
// pts = List of points.
function pointlist_bounds(pts) =
assert(is_path(pts,dim=undef,fast=true) , "Invalid pointlist." )
let(
select = ident(len(pts[0])),
spread = [
for(i=[0:len(pts[0])-1])
let( spreadi = pts*select[i] )
[ min(spreadi), max(spreadi) ]
]
) transpose(spread);
// Function: closest_point()
// Usage:
// index = closest_point(pt, points);