mirror of
https://github.com/BelfrySCAD/BOSL2.git
synced 2024-12-29 16:29:40 +00:00
misc tweaks
This commit is contained in:
parent
22847597b1
commit
a81b6c6931
14 changed files with 242 additions and 339 deletions
|
@ -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
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
84
drawing.scad
84
drawing.scad
|
@ -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
|
||||
|
|
133
lists.scad
133
lists.scad
|
@ -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
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
|
@ -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();
|
||||
|
||||
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
||||
|
||||
|
|
119
vectors.scad
119
vectors.scad
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue