mirror of
https://github.com/BelfrySCAD/BOSL2.git
synced 2025-01-04 03:09:45 +00:00
commit
225d6f512b
19 changed files with 761 additions and 773 deletions
|
@ -504,8 +504,9 @@ module hulling(a)
|
|||
// Description:
|
||||
// Takes a 3D mask shape, and attaches it to the given edges, with the appropriate orientation to be
|
||||
// `diff()`ed away. The mask shape should be vertically oriented (Z-aligned) with the back-right
|
||||
// quadrant (X+Y+) shaped to be diffed away from the edge of parent attachable shape. For a more
|
||||
// step-by-step explanation of attachments, see the [[Attachments Tutorial|Tutorial-Attachments]].
|
||||
// quadrant (X+Y+) shaped to be diffed away from the edge of parent attachable shape.
|
||||
// For details on specifying the edges to mask see [Specifying Edges](edges.scad#section-specifying-edges).
|
||||
// For a step-by-step explanation of attachments, see the [[Attachments Tutorial|Tutorial-Attachments]].
|
||||
// Figure: A Typical Edge Rounding Mask
|
||||
// module roundit(l,r) difference() {
|
||||
// translate([-1,-1,-l/2])
|
||||
|
@ -515,8 +516,8 @@ module hulling(a)
|
|||
// }
|
||||
// roundit(l=30,r=10);
|
||||
// Arguments:
|
||||
// edges = Edges to mask. See the docs for [`edges()`](edges.scad#edges) to see acceptable values. Default: All edges.
|
||||
// except = Edges to explicitly NOT mask. See the docs for [`edges()`](edges.scad#edges) to see acceptable values. Default: No edges.
|
||||
// edges = Edges to mask. See [Specifying Edges](edges.scad#section-specifying-edges). Default: All edges.
|
||||
// except = Edges to explicitly NOT mask. See [Specifying Edges](edges.scad#section-specifying-edges). Default: No edges.
|
||||
// Side Effects:
|
||||
// Sets `$tags = "mask"` for all children.
|
||||
// Example:
|
||||
|
@ -526,7 +527,7 @@ module hulling(a)
|
|||
// rounding_edge_mask(l=71,r=10);
|
||||
module edge_mask(edges=EDGES_ALL, except=[]) {
|
||||
assert($parent_geom != undef, "No object to attach to!");
|
||||
edges = edges(edges, except=except);
|
||||
edges = _edges(edges, except=except);
|
||||
vecs = [
|
||||
for (i = [0:3], axis=[0:2])
|
||||
if (edges[axis][i]>0)
|
||||
|
@ -556,12 +557,13 @@ module edge_mask(edges=EDGES_ALL, except=[]) {
|
|||
// Topics: Attachments
|
||||
// See Also: attachable(), position(), attach(), face_profile(), edge_profile(), edge_mask()
|
||||
// Description:
|
||||
// Takes a 3D mask shape, and attaches it to the given corners, with the appropriate orientation to
|
||||
// Takes a 3D mask shape, and attaches it to the specified corners, with the appropriate orientation to
|
||||
// be `diff()`ed away. The 3D corner mask shape should be designed to mask away the X+Y+Z+ octant.
|
||||
// For a more step-by-step explanation of attachments, see the [[Attachments Tutorial|Tutorial-Attachments]].
|
||||
// See [Specifying Corners](edges.scad#section-specifying-corners) for information on how to specify corner sets.
|
||||
// For a step-by-step explanation of attachments, see the [[Attachments Tutorial|Tutorial-Attachments]].
|
||||
// Arguments:
|
||||
// corners = Edges to mask. See the docs for [`corners()`](edges.scad#corners) to see acceptable values. Default: All corners.
|
||||
// except = Edges to explicitly NOT mask. See the docs for [`corners()`](edges.scad#corners) to see acceptable values. Default: No corners.
|
||||
// corners = Corners to mask. See [Specifying Corners](edges.scad#section-specifying-corners). Default: All corners.
|
||||
// except = Corners to explicitly NOT mask. See [Specifying Corners](edges.scad#section-specifying-corners). Default: No corners.
|
||||
// Side Effects:
|
||||
// Sets `$tags = "mask"` for all children.
|
||||
// Example:
|
||||
|
@ -574,7 +576,7 @@ module edge_mask(edges=EDGES_ALL, except=[]) {
|
|||
// }
|
||||
module corner_mask(corners=CORNERS_ALL, except=[]) {
|
||||
assert($parent_geom != undef, "No object to attach to!");
|
||||
corners = corners(corners, except=except);
|
||||
corners = _corners(corners, except=except);
|
||||
vecs = [for (i = [0:7]) if (corners[i]>0) CORNER_OFFSETS[i]];
|
||||
for (vec = vecs) {
|
||||
vcount = (vec.x?1:0) + (vec.y?1:0) + (vec.z?1:0);
|
||||
|
@ -599,7 +601,8 @@ module corner_mask(corners=CORNERS_ALL, except=[]) {
|
|||
// See Also: attachable(), position(), attach(), edge_profile(), corner_profile()
|
||||
// Description:
|
||||
// Given a 2D edge profile, extrudes it into a mask for all edges and corners bounding each given face.
|
||||
// For a more step-by-step explanation of attachments, see the [[Attachments Tutorial|Tutorial-Attachments]].
|
||||
// See [Specifying Faces](edges.scad#section-specifying-faces) for information on specifying faces.
|
||||
// For a step-by-step explanation of attachments, see the [[Attachments Tutorial|Tutorial-Attachments]].
|
||||
// Arguments:
|
||||
// faces = Faces to mask edges and corners of.
|
||||
// r = Radius of corner mask.
|
||||
|
@ -630,11 +633,13 @@ module face_profile(faces=[], r, d, convexity=10) {
|
|||
// See Also: attachable(), position(), attach(), face_profile(), corner_profile()
|
||||
// Description:
|
||||
// Takes a 2D mask shape and attaches it to the selected edges, with the appropriate orientation and
|
||||
// extruded length to be `diff()`ed away, to give the edge a matching profile. For a more step-by-step
|
||||
// extruded length to be `diff()`ed away, to give the edge a matching profile.
|
||||
// For details on specifying the edges to mask see [Specifying Edges](edges.scad#section-specifying-edges).
|
||||
// For a step-by-step
|
||||
// explanation of attachments, see the [[Attachments Tutorial|Tutorial-Attachments]].
|
||||
// Arguments:
|
||||
// edges = Edges to mask. See the docs for [`edges()`](edges.scad#edges) to see acceptable values. Default: All edges.
|
||||
// except = Edges to explicitly NOT mask. See the docs for [`edges()`](edges.scad#edges) to see acceptable values. Default: No edges.
|
||||
// edges = Edges to mask. See [Specifying Edges](edges.scad#section-specifying-edges). Default: All edges.
|
||||
// except = Edges to explicitly NOT mask. See [Specifying Edges](edges.scad#section-specifying-edges). Default: No edges.
|
||||
// convexity = Max number of times a line could intersect the perimeter of the mask shape. Default: 10
|
||||
// Side Effects:
|
||||
// Sets `$tags = "mask"` for all children.
|
||||
|
@ -645,7 +650,7 @@ module face_profile(faces=[], r, d, convexity=10) {
|
|||
// mask2d_roundover(r=10, inset=2);
|
||||
module edge_profile(edges=EDGES_ALL, except=[], convexity=10) {
|
||||
assert($parent_geom != undef, "No object to attach to!");
|
||||
edges = edges(edges, except=except);
|
||||
edges = _edges(edges, except=except);
|
||||
vecs = [
|
||||
for (i = [0:3], axis=[0:2])
|
||||
if (edges[axis][i]>0)
|
||||
|
@ -684,11 +689,12 @@ module edge_profile(edges=EDGES_ALL, except=[], convexity=10) {
|
|||
// Description:
|
||||
// Takes a 2D mask shape, rotationally extrudes and converts it into a corner mask, and attaches it
|
||||
// to the selected corners with the appropriate orientation. Tags it as a "mask" to allow it to be
|
||||
// `diff()`ed away, to give the corner a matching profile. For a more step-by-step explanation of
|
||||
// attachments, see the [[Attachments Tutorial|Tutorial-Attachments]].
|
||||
// `diff()`ed away, to give the corner a matching profile.
|
||||
// See [Specifying Corners](edges.scad#section-specifying-corners) for information on how to specify corner sets.
|
||||
// For a step-by-step explanation of attachments, see the [[Attachments Tutorial|Tutorial-Attachments]].
|
||||
// Arguments:
|
||||
// corners = Edges to mask. See the docs for [`corners()`](edges.scad#corners) to see acceptable values. Default: All corners.
|
||||
// except = Edges to explicitly NOT mask. See the docs for [`corners()`](edges.scad#corners) to see acceptable values. Default: No corners.
|
||||
// corners = Corners to mask. See [Specifying Corners](edges.scad#section-specifying-corners). Default: All corners.
|
||||
// except = Corners to explicitly NOT mask. See [Specifying Corners](edges.scad#section-specifying-corners). Default: No corners.
|
||||
// ---
|
||||
// r = Radius of corner mask.
|
||||
// d = Diameter of corner mask.
|
||||
|
@ -705,7 +711,7 @@ module corner_profile(corners=CORNERS_ALL, except=[], r, d, convexity=10) {
|
|||
assert($parent_geom != undef, "No object to attach to!");
|
||||
r = get_radius(r=r, d=d, dflt=undef);
|
||||
assert(is_num(r));
|
||||
corners = corners(corners, except=except);
|
||||
corners = _corners(corners, except=except);
|
||||
vecs = [for (i = [0:7]) if (corners[i]>0) CORNER_OFFSETS[i]];
|
||||
for (vec = vecs) {
|
||||
vcount = (vec.x?1:0) + (vec.y?1:0) + (vec.z?1:0);
|
||||
|
@ -740,8 +746,6 @@ module corner_profile(corners=CORNERS_ALL, except=[], r, d, convexity=10) {
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Section: Making your objects attachable
|
||||
|
||||
|
||||
|
|
41
beziers.scad
41
beziers.scad
|
@ -634,7 +634,8 @@ function bezier_path_point(path, seg, u, N=3) =
|
|||
// max_err = The maximum allowed error when approximating the closest approach.
|
||||
// Example(2D):
|
||||
// pt = [100,0];
|
||||
// bez = [[0,0], [20,40], [60,-25], [80,0], [100,25], [140,25], [160,0]];
|
||||
// bez = [[0,0], [20,40], [60,-25], [80,0],
|
||||
// [100,25], [140,25], [160,0]];
|
||||
// pos = bezier_path_closest_point(bez, pt);
|
||||
// xy = bezier_path_point(bez,pos[0],pos[1]);
|
||||
// trace_bezier(bez, N=3);
|
||||
|
@ -848,11 +849,13 @@ function fillet_path(pts, fillet, maxerr=0.1) = concat(
|
|||
// axis = The axis to close to, "X", or "Y". Default: "X"
|
||||
// N = The degree of the bezier curves. Cubic beziers have N=3. Default: 3
|
||||
// Example(2D):
|
||||
// bez = [[50,30], [40,10], [10,50], [0,30], [-10, 10], [-30,10], [-50,20]];
|
||||
// bez = [[50,30], [40,10], [10,50], [0,30],
|
||||
// [-10, 10], [-30,10], [-50,20]];
|
||||
// closed = bezier_close_to_axis(bez);
|
||||
// trace_bezier(closed);
|
||||
// Example(2D):
|
||||
// bez = [[30,50], [10,40], [50,10], [30,0], [10, -10], [10,-30], [20,-50]];
|
||||
// bez = [[30,50], [10,40], [50,10], [30,0],
|
||||
// [10, -10], [10,-30], [20,-50]];
|
||||
// closed = bezier_close_to_axis(bez, axis="Y");
|
||||
// trace_bezier(closed);
|
||||
function bezier_close_to_axis(bezier, axis="X", N=3) =
|
||||
|
@ -1264,7 +1267,7 @@ function bezier_patch(patch, splinesteps=16, style="default") =
|
|||
// splinesteps = Number of segments to produce on each side. Default: 16
|
||||
// reverse = reverse direction of faces. Default: false
|
||||
// return_edges = if true return the points on the four edges: [left, right, top, bottom]. Default: false
|
||||
// Example: This quartic patch is degenerate at one corner, where a row of control points are equal. Processing this degenerate patch normally produces excess triangles near the degenerate point.
|
||||
// Example(3D): This quartic patch is degenerate at one corner, where a row of control points are equal. Processing this degenerate patch normally produces excess triangles near the degenerate point.
|
||||
// splinesteps=8;
|
||||
// patch=[
|
||||
// repeat([-12.5, 12.5, 15],5),
|
||||
|
@ -1273,9 +1276,9 @@ function bezier_patch(patch, splinesteps=16, style="default") =
|
|||
// [[0, 10, 8.75], [0, 5, 8.75], [0, 0, 8.75], [-5, 0, 8.75], [-10, 0, 8.75]],
|
||||
// [[0, 10, 2.5], [0, 5, 2.5], [0, 0, 2.5], [-5, 0, 2.5], [-10, 0, 2.5]]
|
||||
// ];
|
||||
// vnf_wireframe((bezier_patch(patch, splinesteps)),d=0.1);
|
||||
// vnf_wireframe((bezier_patch(patch, splinesteps)),width=0.1);
|
||||
// color("red")move_copies(flatten(patch)) sphere(r=0.3,$fn=9);
|
||||
// Example: With bezier_patch_degenerate the degenerate point does not have excess triangles. The top half of the patch decreases the number of sampled points by 2 for each row.
|
||||
// Example(3D): With bezier_patch_degenerate the degenerate point does not have excess triangles. The top half of the patch decreases the number of sampled points by 2 for each row.
|
||||
// splinesteps=8;
|
||||
// patch=[
|
||||
// repeat([-12.5, 12.5, 15],5),
|
||||
|
@ -1284,9 +1287,9 @@ function bezier_patch(patch, splinesteps=16, style="default") =
|
|||
// [[0, 10, 8.75], [0, 5, 8.75], [0, 0, 8.75], [-5, 0, 8.75], [-10, 0, 8.75]],
|
||||
// [[0, 10, 2.5], [0, 5, 2.5], [0, 0, 2.5], [-5, 0, 2.5], [-10, 0, 2.5]]
|
||||
// ];
|
||||
// vnf_wireframe(bezier_patch_degenerate(patch, splinesteps),d=0.1);
|
||||
// vnf_wireframe(bezier_patch_degenerate(patch, splinesteps),width=0.1);
|
||||
// color("red")move_copies(flatten(patch)) sphere(r=0.3,$fn=9);
|
||||
// Example: With splinesteps odd you get one "odd" row where the point count decreases by 1 instead of 2. You may prefer even values for splinesteps to avoid this.
|
||||
// Example(3D): With splinesteps odd you get one "odd" row where the point count decreases by 1 instead of 2. You may prefer even values for splinesteps to avoid this.
|
||||
// splinesteps=7;
|
||||
// patch=[
|
||||
// repeat([-12.5, 12.5, 15],5),
|
||||
|
@ -1295,9 +1298,9 @@ function bezier_patch(patch, splinesteps=16, style="default") =
|
|||
// [[0, 10, 8.75], [0, 5, 8.75], [0, 0, 8.75], [-5, 0, 8.75], [-10, 0, 8.75]],
|
||||
// [[0, 10, 2.5], [0, 5, 2.5], [0, 0, 2.5], [-5, 0, 2.5], [-10, 0, 2.5]]
|
||||
// ];
|
||||
// vnf_wireframe(bezier_patch_degenerate(patch, splinesteps),d=0.1);
|
||||
// vnf_wireframe(bezier_patch_degenerate(patch, splinesteps),width=0.1);
|
||||
// color("red")move_copies(flatten(patch)) sphere(r=0.3,$fn=9);
|
||||
// Example: A more extreme degeneracy occurs when the top half of a patch is degenerate to a line. (For odd length patches the middle row must be degenerate to trigger this style.) In this case the number of points in each row decreases by 1 for every row. It doesn't matter of splinesteps is odd or even.
|
||||
// Example(3D): A more extreme degeneracy occurs when the top half of a patch is degenerate to a line. (For odd length patches the middle row must be degenerate to trigger this style.) In this case the number of points in each row decreases by 1 for every row. It doesn't matter of splinesteps is odd or even.
|
||||
// splinesteps=8;
|
||||
// patch = [[[10, 0, 0], [10, -10.4, 0], [10, -20.8, 0], [1.876, -14.30, 0], [-6.24, -7.8, 0]],
|
||||
// [[5, 0, 0], [5, -5.2, 0], [5, -10.4, 0], [0.938, -7.15, 0], [-3.12, -3.9, 0]],
|
||||
|
@ -1305,9 +1308,9 @@ function bezier_patch(patch, splinesteps=16, style="default") =
|
|||
// repeat([0,0,5],5),
|
||||
// repeat([0,0,10],5)
|
||||
// ];
|
||||
// vnf_wireframe(bezier_patch_degenerate(patch, splinesteps),d=0.1);
|
||||
// vnf_wireframe(bezier_patch_degenerate(patch, splinesteps),width=0.1);
|
||||
// color("red")move_copies(flatten(patch)) sphere(r=0.3,$fn=9);
|
||||
// Example: Here is a degenerate cubic patch.
|
||||
// Example(3D): Here is a degenerate cubic patch.
|
||||
// splinesteps=8;
|
||||
// patch = [ [ [-20,0,0], [-10,0,0],[0,10,0],[0,20,0] ],
|
||||
// [ [-20,0,10], [-10,0,10],[0,10,10],[0,20,10]],
|
||||
|
@ -1315,8 +1318,8 @@ function bezier_patch(patch, splinesteps=16, style="default") =
|
|||
// repeat([0,0,30],4)
|
||||
// ];
|
||||
// color("red")move_copies(flatten(patch)) sphere(r=0.3,$fn=9);
|
||||
// vnf_wireframe(bezier_patch_degenerate(patch, splinesteps),d=0.1);
|
||||
// Example: A more extreme degenerate cubic patch, where two rows are equal.
|
||||
// vnf_wireframe(bezier_patch_degenerate(patch, splinesteps),width=0.1);
|
||||
// Example(3D): A more extreme degenerate cubic patch, where two rows are equal.
|
||||
// splinesteps=8;
|
||||
// patch = [ [ [-20,0,0], [-10,0,0],[0,10,0],[0,20,0] ],
|
||||
// [ [-20,0,10], [-10,0,10],[0,10,10],[0,20,10] ],
|
||||
|
@ -1324,15 +1327,15 @@ function bezier_patch(patch, splinesteps=16, style="default") =
|
|||
// repeat([-10,10,30],4)
|
||||
// ];
|
||||
// color("red")move_copies(flatten(patch)) sphere(r=0.3,$fn=9);
|
||||
// vnf_wireframe(bezier_patch_degenerate(patch, splinesteps),d=0.1);
|
||||
// Example: Quadratic patch degenerate at the right side:
|
||||
// vnf_wireframe(bezier_patch_degenerate(patch, splinesteps),width=0.1);
|
||||
// Example(3D): Quadratic patch degenerate at the right side:
|
||||
// splinesteps=8;
|
||||
// patch = [[[0, -10, 0],[10, -5, 0],[20, 0, 0]],
|
||||
// [[0, 0, 0], [10, 0, 0], [20, 0, 0]],
|
||||
// [[0, 0, 10], [10, 0, 5], [20, 0, 0]]];
|
||||
// vnf_wireframe(bezier_patch_degenerate(patch, splinesteps),d=0.1);
|
||||
// vnf_wireframe(bezier_patch_degenerate(patch, splinesteps),width=0.1);
|
||||
// color("red")move_copies(flatten(patch)) sphere(r=0.3,$fn=9);
|
||||
// Example: Cubic patch degenerate at both ends. In this case the point count changes by 2 at every row.
|
||||
// Example(3D): Cubic patch degenerate at both ends. In this case the point count changes by 2 at every row.
|
||||
// splinesteps=8;
|
||||
// patch = [
|
||||
// repeat([10,-10,0],4),
|
||||
|
@ -1340,7 +1343,7 @@ function bezier_patch(patch, splinesteps=16, style="default") =
|
|||
// [ [-20,0,10], [-10,0,10],[0,10,10],[0,20,10] ],
|
||||
// repeat([-10,10,20],4),
|
||||
// ];
|
||||
// vnf_wireframe(bezier_patch_degenerate(patch, splinesteps),d=0.1);
|
||||
// vnf_wireframe(bezier_patch_degenerate(patch, splinesteps),width=0.1);
|
||||
// color("red")move_copies(flatten(patch)) sphere(r=0.3,$fn=9);
|
||||
function bezier_patch_degenerate(patch, splinesteps=16, reverse=false, return_edges=false) =
|
||||
!return_edges ? bezier_patch_degenerate(patch, splinesteps, reverse, true)[0] :
|
||||
|
|
|
@ -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) {
|
||||
|
|
86
drawing.scad
86
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);
|
||||
polygon(path);
|
||||
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
|
||||
|
|
676
edges.scad
676
edges.scad
|
@ -5,7 +5,252 @@
|
|||
// include <BOSL2/std.scad>
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
// Section: Specifying Directions
|
||||
// You can use direction vectors to specify anchors for objects or to specify edges, faces, and
|
||||
// corners of cubes. You can simply specify these direction vectors numerically, but another
|
||||
// option is to use named constants for direction vectors. These constants define unit vectors
|
||||
// for the six axis directions as shown below.
|
||||
// Figure(3D,Big,VPD=7): Named constants for direction vectors. Some directions have more than one name.
|
||||
// $fn=12;
|
||||
// stroke([[0,0,0],RIGHT], endcap2="arrow2", width=.05);
|
||||
// right(.05)up(.05)move(RIGHT)atext("RIGHT",size=.1,h=.01,anchor=LEFT,orient=FRONT);
|
||||
// stroke([[0,0,0],LEFT], endcap2="arrow2", width=.05);
|
||||
// left(.05)up(.05)move(LEFT)atext("LEFT",size=.1,h=.01,anchor=RIGHT,orient=FRONT);
|
||||
// stroke([[0,0,0],FRONT], endcap2="arrow2", width=.05);
|
||||
// left(.1){
|
||||
// up(.1)move(FRONT)atext("FRONT",size=.1,h=.01,anchor=RIGHT,orient=FRONT);
|
||||
// move(FRONT)atext("FWD",size=.1,h=.01,anchor=RIGHT,orient=FRONT);
|
||||
// down(.1)move(FRONT)atext("FORWARD",size=.1,h=.01,anchor=RIGHT,orient=FRONT);
|
||||
// }
|
||||
// stroke([[0,0,0],BACK], endcap2="arrow2", width=.05);
|
||||
// right(.05)
|
||||
// move(BACK)atext("BACK",size=.1,h=.01,anchor=LEFT,orient=FRONT);
|
||||
// stroke([[0,0,0],DOWN], endcap2="arrow2", width=.05);
|
||||
// right(.1){
|
||||
// up(.1)move(BOT)atext("DOWN",size=.1,h=.01,anchor=LEFT,orient=FRONT);
|
||||
// move(BOT)atext("BOTTOM",size=.1,h=.01,anchor=LEFT,orient=FRONT);
|
||||
// down(.1)move(BOT)atext("BOT",size=.1,h=.01,anchor=LEFT,orient=FRONT);
|
||||
// down(.2)move(BOT)atext("BTM",size=.1,h=.01,anchor=LEFT,orient=FRONT);
|
||||
// }
|
||||
// stroke([[0,0,0],TOP], endcap2="arrow2", width=.05);
|
||||
// left(.05){
|
||||
// up(.1)move(TOP)atext("TOP",size=.1,h=.01,anchor=RIGHT,orient=FRONT);
|
||||
// move(TOP)atext("UP",size=.1,h=.01,anchor=RIGHT,orient=FRONT);
|
||||
// }
|
||||
// Section: Specifying Faces
|
||||
// Modules operating on faces accept a list of faces to describe the faces to operate on. Each
|
||||
// face is given by a vector that points to that face. Attachments of cuboid objects also
|
||||
// work by choosing an attachment face with a single vector in the same manner.
|
||||
// Figure(3D,Big,NoScales,VPD=250): The six faces of the cube. Some have faces have more than one name.
|
||||
// ydistribute(50) {
|
||||
// xdistribute(35){
|
||||
// _show_cube_faces([BACK], botlabel=["BACK"]);
|
||||
// _show_cube_faces([UP],botlabel=["TOP","UP"]);
|
||||
// _show_cube_faces([RIGHT],botlabel=["RIGHT"]);
|
||||
// }
|
||||
// xdistribute(35){
|
||||
// _show_cube_faces([FRONT],toplabel=["FRONT","FWD", "FORWARD"]);
|
||||
// _show_cube_faces([DOWN],toplabel=["BOTTOM","BOT","BTM","DOWN"]);
|
||||
// _show_cube_faces([LEFT],toplabel=["LEFT"]);
|
||||
// }
|
||||
// }
|
||||
// Section: Specifying Edges
|
||||
// Modules operating on edges use two arguments to describe the edge set they will use: The `edges` argument
|
||||
// is a list of edge set descriptors to include in the edge set and the `except` argument is a list of
|
||||
// edge set descriptors to remove from the edge set. If either argument is just a single edge set
|
||||
// descriptor it can be passed directly rather than in a singleton list.
|
||||
// Each edge set descriptor must be one of:
|
||||
// - A vector pointing towards an edge, indicating that single edge.
|
||||
// - A vector pointing towards a face, indicating all edges surrounding that face.
|
||||
// - A vector pointing towards a corner, indicating all edges touching that corner.
|
||||
// - The string `"X"`, indicating all X axis aligned edges.
|
||||
// - The string `"Y"`, indicating all Y axis aligned edges.
|
||||
// - The string `"Z"`, indicating all Z axis aligned edges.
|
||||
// - The string `"ALL"`, indicating all edges.
|
||||
// - The string `"NONE"`, indicating no edges at all.
|
||||
// - A 3x4 array, where each entry corresponds to one of the 12 edges and is set to 1 if that edge is included and 0 if the edge is not. The edge ordering is:
|
||||
// ```
|
||||
// [
|
||||
// [Y-Z-, Y+Z-, Y-Z+, Y+Z+],
|
||||
// [X-Z-, X+Z-, X-Z+, X+Z+],
|
||||
// [X-Y-, X+Y-, X-Y+, X+Y+]
|
||||
// ]
|
||||
// ```
|
||||
// You can specify edge descriptors directly by giving a vector, or you can use sums of the
|
||||
// named direction vectors described above. Below we show all of the edge sets you can
|
||||
// describe with sums of the direction vectors.
|
||||
// Figure(3D,Big,VPD=300,NoScales): Vectors pointing toward an edge select that single edge
|
||||
// ydistribute(50) {
|
||||
// xdistribute(30) {
|
||||
// _show_edges(edges=BOT+RIGHT);
|
||||
// _show_edges(edges=BOT+BACK);
|
||||
// _show_edges(edges=BOT+LEFT);
|
||||
// _show_edges(edges=BOT+FRONT);
|
||||
// }
|
||||
// xdistribute(30) {
|
||||
// _show_edges(edges=FWD+RIGHT);
|
||||
// _show_edges(edges=BACK+RIGHT);
|
||||
// _show_edges(edges=BACK+LEFT);
|
||||
// _show_edges(edges=FWD+LEFT);
|
||||
// }
|
||||
// xdistribute(30) {
|
||||
// _show_edges(edges=TOP+RIGHT);
|
||||
// _show_edges(edges=TOP+BACK);
|
||||
// _show_edges(edges=TOP+LEFT);
|
||||
// _show_edges(edges=TOP+FRONT);
|
||||
// }
|
||||
// }
|
||||
// Figure(3D,Med,VPD=205,NoScales): Vectors pointing toward a face select all edges surrounding that face.
|
||||
// ydistribute(50) {
|
||||
// xdistribute(30) {
|
||||
// _show_edges(edges=LEFT);
|
||||
// _show_edges(edges=FRONT);
|
||||
// _show_edges(edges=RIGHT);
|
||||
// }
|
||||
// xdistribute(30) {
|
||||
// _show_edges(edges=TOP);
|
||||
// _show_edges(edges=BACK);
|
||||
// _show_edges(edges=BOTTOM);
|
||||
// }
|
||||
// }
|
||||
// Figure(3D,Big,VPD=300,NoScales): Vectors pointing toward a corner select all edges surrounding that corner.
|
||||
// ydistribute(50) {
|
||||
// xdistribute(30) {
|
||||
// _show_edges(edges=FRONT+LEFT+TOP);
|
||||
// _show_edges(edges=FRONT+RIGHT+TOP);
|
||||
// _show_edges(edges=FRONT+LEFT+BOT);
|
||||
// _show_edges(edges=FRONT+RIGHT+BOT);
|
||||
// }
|
||||
// xdistribute(30) {
|
||||
// _show_edges(edges=TOP+LEFT+BACK);
|
||||
// _show_edges(edges=TOP+RIGHT+BACK);
|
||||
// _show_edges(edges=BOT+LEFT+BACK);
|
||||
// _show_edges(edges=BOT+RIGHT+BACK);
|
||||
// }
|
||||
// }
|
||||
// Figure(3D,Med,VPD=205,NoScales): Named Edge Sets
|
||||
// ydistribute(50) {
|
||||
// xdistribute(30) {
|
||||
// _show_edges(edges="X");
|
||||
// _show_edges(edges="Y");
|
||||
// _show_edges(edges="Z");
|
||||
// }
|
||||
// xdistribute(30) {
|
||||
// _show_edges(edges="ALL");
|
||||
// _show_edges(edges="NONE");
|
||||
// }
|
||||
// }
|
||||
// Figure(3D,Big,VPD=310,NoScales): Next are some examples showing how you can combine edge descriptors to obtain different edge sets. The default value for `edges` is `"ALL"`, the set of all edges. The default value for `except` is the empty set, meaning no edges are removed. You can specify the top front edge with a numerical vector or by combining the named direction vectors. If you combine them as a list you get all the edges around the front or top faces. Adding `except` removes an edge.
|
||||
// xdistribute(43){
|
||||
// _show_edges(_edges([0,-1,1]),toplabel=["edges=[0,-1,1]"]);
|
||||
// _show_edges(_edges(TOP+FRONT),toplabel=["edges=TOP+FRONT"]);
|
||||
// _show_edges(_edges([TOP,FRONT]),toplabel=["edges=[TOP,FRONT]"]);
|
||||
// _show_edges(_edges([TOP,FRONT],TOP+FRONT),toplabel=["edges=[TOP,FRONT]","except=TOP+FRONT"]);
|
||||
// }
|
||||
// Figure(3D,Big,VPD=310,NoScales): Using `except=BACK` removes the four edges surrounding the back face if they are present in the edge set. In the first example only one edge needs to be removed. In the second example we remove two of the Z-aligned edges. The third example removes all four back edges from the default edge set of all edges. You can explicitly give `edges="ALL"` but it is not necessary, since this is the default. In the fourth example, the edge set of Y-aligned edges contains no back edges, so the `except` parameter has no effect.
|
||||
// xdistribute(43){
|
||||
// _show_edges(_edges(BTM,BACK), toplabel=["edges=BTM","except=BACK"]);
|
||||
// _show_edges(_edges("Z",BACK), toplabel=["edges=\"Z\"", "except=BACK"]);
|
||||
// _show_edges(_edges("ALL",BACK), toplabel=["(edges=\"ALL\")", "except=BACK"]);
|
||||
// _show_edges(_edges("Y",BACK), toplabel=["edges=\"Y\"","except=BACK"]);
|
||||
// }
|
||||
// Figure(3D,Big,NoScales,VPD=310): On the left `except` is a list to remove two edges. In the center we show a corner edge set defined by a numerical vector, and at the right we remove that same corner edge set with named direction vectors.
|
||||
// xdistribute(52){
|
||||
// _show_edges(_edges("ALL",[FRONT+RIGHT,FRONT+LEFT]),
|
||||
// toplabel=["except=[FRONT+RIGHT,"," FRONT+LEFT]"]);
|
||||
// _show_edges(_edges([1,-1,1]),toplabel=["edges=[1,-1,1]"]);
|
||||
// _show_edges(_edges([TOP,BOT], TOP+RIGHT+FRONT),toplabel=["edges=[TOP,BOT]","except=TOP+RIGHT+FRONT"]);
|
||||
// }
|
||||
// Section: Specifying Corners
|
||||
// Modules operating on corners use two arguments to describe the corner set they will use: The `corners` argument
|
||||
// is a list of corner set descriptors to include in the corner set, and the `except` argument is a list of
|
||||
// corner set descriptors to remove from the corner set. If either argument is just a single corner set
|
||||
// descriptor it can be passed directly rather than in a singleton list.
|
||||
// Each corner set descriptor must be one of:
|
||||
// - A vector pointing towards a corner, indicating that corner.
|
||||
// - A vector pointing towards an edge indicating both corners at the ends of that edge.
|
||||
// - A vector pointing towards a face, indicating all the corners of that face.
|
||||
// - The string `"ALL"`, indicating all corners.
|
||||
// - The string `"NONE"`, indicating no corners at all.
|
||||
// - A length 8 vector where each entry corresponds to a corner and is 1 if the corner is included and 0 if it is excluded. The corner ordering is
|
||||
// ```
|
||||
// [X-Y-Z-, X+Y-Z-, X-Y+Z-, X+Y+Z-, X-Y-Z+, X+Y-Z+, X-Y+Z+, X+Y+Z+]
|
||||
// ```
|
||||
// You can specify corner descriptors directly by giving a vector, or you can use sums of the
|
||||
// named direction vectors described above. Below we show all of the corner sets you can
|
||||
// describe with sums of the direction vectors.
|
||||
// Figure(3D,Big,NoScales,VPD=300): Vectors pointing toward a corner select that corner.
|
||||
// ydistribute(55) {
|
||||
// xdistribute(35) {
|
||||
// _show_corners(corners=FRONT+LEFT+TOP);
|
||||
// _show_corners(corners=FRONT+RIGHT+TOP);
|
||||
// _show_corners(corners=FRONT+LEFT+BOT);
|
||||
// _show_corners(corners=FRONT+RIGHT+BOT);
|
||||
// }
|
||||
// xdistribute(35) {
|
||||
// _show_corners(corners=TOP+LEFT+BACK);
|
||||
// _show_corners(corners=TOP+RIGHT+BACK);
|
||||
// _show_corners(corners=BOT+LEFT+BACK);
|
||||
// _show_corners(corners=BOT+RIGHT+BACK);
|
||||
// }
|
||||
// }
|
||||
// Figure(3D,Big,NoScales,VPD=300): Vectors pointing toward an edge select the corners and the ends of the edge.
|
||||
// ydistribute(55) {
|
||||
// xdistribute(35) {
|
||||
// _show_corners(corners=BOT+RIGHT);
|
||||
// _show_corners(corners=BOT+BACK);
|
||||
// _show_corners(corners=BOT+LEFT);
|
||||
// _show_corners(corners=BOT+FRONT);
|
||||
// }
|
||||
// xdistribute(35) {
|
||||
// _show_corners(corners=FWD+RIGHT);
|
||||
// _show_corners(corners=BACK+RIGHT);
|
||||
// _show_corners(corners=BACK+LEFT);
|
||||
// _show_corners(corners=FWD+LEFT);
|
||||
// }
|
||||
// xdistribute(35) {
|
||||
// _show_corners(corners=TOP+RIGHT);
|
||||
// _show_corners(corners=TOP+BACK);
|
||||
// _show_corners(corners=TOP+LEFT);
|
||||
// _show_corners(corners=TOP+FRONT);
|
||||
// }
|
||||
// }
|
||||
// Figure(3D,Med,NoScales,VPD=225): Vectors pointing toward a face select the corners of the face.
|
||||
// ydistribute(55) {
|
||||
// xdistribute(35) {
|
||||
// _show_corners(corners=LEFT);
|
||||
// _show_corners(corners=FRONT);
|
||||
// _show_corners(corners=RIGHT);
|
||||
// }
|
||||
// xdistribute(35) {
|
||||
// _show_corners(corners=TOP);
|
||||
// _show_corners(corners=BACK);
|
||||
// _show_corners(corners=BOTTOM);
|
||||
// }
|
||||
// }
|
||||
// Figure(3D,Med,NoScales,VPD=200): Corners by name
|
||||
// xdistribute(35) {
|
||||
// _show_corners(corners="ALL");
|
||||
// _show_corners(corners="NONE");
|
||||
// }
|
||||
// Figure(3D,Big,NoScales,VPD=300): Next are some examples showing how you can combine corner descriptors to obtain different corner sets. The default value for `corners` is `"ALL"`, the set of all corners. The default value for `except` is the empty set, meaning no corners are removed. You can specify corner sets numerically or by adding together named directions. The third example shows a list of two corner specifications, giving all the corners on the front face or the right face.
|
||||
// xdistribute(52){
|
||||
// _show_corners(_corners([1,-1,-1]),toplabel=["corners=[1,-1,-1]"]);
|
||||
// _show_corners(_corners(BOT+RIGHT+FRONT),toplabel=["corners=BOT+RIGHT+FRONT"]);
|
||||
// _show_corners(_corners([FRONT,RIGHT]), toplabel=["corners=[FRONT,RIGHT]"]);
|
||||
// }
|
||||
// Figure(3D,Big,NoScales,VPD=300): Corners for one edge, two edges, and all the edges except the two on one edge. Note that since the default is all edges, you only need to give the except argument in this case:
|
||||
// xdistribute(52){
|
||||
// _show_corners(_corners(FRONT+TOP), toplabel=["corners=FRONT+TOP"]);
|
||||
// _show_corners(_corners([FRONT+TOP,BOT+BACK]), toplabel=["corners=[FRONT+TOP,"," BOT+BACK]"]);
|
||||
// _show_corners(_corners("ALL",FRONT+TOP), toplabel=["(corners=\"ALL\")","except=FRONT+TOP"]);
|
||||
// }
|
||||
// Figure(3D,Big,NoScales,VPD=300): The first example shows a single corner removed from the top corners using a numerical vector. The second one shows removing a set of two corner descriptors from the implied set of all corners.
|
||||
// xdistribute(58){
|
||||
// _show_corners(_corners(TOP,[1,1,1]), toplabel=["corners=TOP","except=[1,1,1]"]);
|
||||
// _show_corners(_corners("ALL",[FRONT+RIGHT+TOP,FRONT+LEFT+BOT]),
|
||||
// toplabel=["except=[FRONT+RIGHT+TOP,"," FRONT+LEFT+BOT]"]);
|
||||
// }
|
||||
module _edges_text3d(txt,size=3) {
|
||||
if (is_list(txt)) {
|
||||
for (i=idx(txt)) {
|
||||
|
@ -59,34 +304,32 @@ function _edges_text(edges) =
|
|||
|
||||
|
||||
|
||||
// Section: Edge Constants
|
||||
|
||||
// Constant: EDGES_NONE
|
||||
// Topics: Edges
|
||||
// See Also: EDGES_ALL, edges()
|
||||
// Description:
|
||||
// The set of no edges.
|
||||
// Figure(3D):
|
||||
// show_edges(edges="NONE");
|
||||
/// Internal Constant: EDGES_NONE
|
||||
/// Topics: Edges
|
||||
/// See Also: EDGES_ALL, edges()
|
||||
/// Description:
|
||||
/// The set of no edges.
|
||||
/// Figure(3D):
|
||||
/// _show_edges(edges="NONE");
|
||||
EDGES_NONE = [[0,0,0,0], [0,0,0,0], [0,0,0,0]];
|
||||
|
||||
|
||||
// Constant: EDGES_ALL
|
||||
// Topics: Edges
|
||||
// See Also: EDGES_NONE, edges()
|
||||
// Description:
|
||||
// The set of all edges.
|
||||
// Figure(3D):
|
||||
// show_edges(edges="ALL");
|
||||
/// Internal Constant: EDGES_ALL
|
||||
/// Topics: Edges
|
||||
/// See Also: EDGES_NONE, edges()
|
||||
/// Description:
|
||||
/// The set of all edges.
|
||||
/// Figure(3D):
|
||||
/// _show_edges(edges="ALL");
|
||||
EDGES_ALL = [[1,1,1,1], [1,1,1,1], [1,1,1,1]];
|
||||
|
||||
|
||||
// Constant: EDGES_OFFSETS
|
||||
// Topics: Edges
|
||||
// See Also: EDGES_NONE, EDGES_ALL, edges()
|
||||
// Description:
|
||||
// The vectors pointing to the center of each edge of a unit sized cube.
|
||||
// Each item in an edge array will have a corresponding vector in this array.
|
||||
/// Internal Constant: EDGES_OFFSETS
|
||||
/// Topics: Edges
|
||||
/// See Also: EDGES_NONE, EDGES_ALL, edges()
|
||||
/// Description:
|
||||
/// The vectors pointing to the center of each edge of a unit sized cube.
|
||||
/// Each item in an edge array will have a corresponding vector in this array.
|
||||
EDGE_OFFSETS = [
|
||||
[
|
||||
[ 0,-1,-1],
|
||||
|
@ -107,7 +350,6 @@ EDGE_OFFSETS = [
|
|||
];
|
||||
|
||||
|
||||
// Section: Edge Helpers
|
||||
|
||||
/// Internal Function: _is_edge_array()
|
||||
/// Topics: Edges, Type Checking
|
||||
|
@ -164,127 +406,26 @@ function _edge_set(v) =
|
|||
function _normalize_edges(v) = [for (ax=v) [for (edge=ax) edge>0? 1 : 0]];
|
||||
|
||||
|
||||
// Function: edges()
|
||||
// Topics: Edges
|
||||
// Usage:
|
||||
// edgs = edges(v);
|
||||
// edgs = edges(v, except);
|
||||
//
|
||||
// Description:
|
||||
// Takes a list of edge set descriptors, and returns a normalized edges array
|
||||
// that represents all those given edges. If the `except` argument is given
|
||||
// a list of edge set descriptors, then all those edges will be removed
|
||||
// from the returned edges array. If either argument only has a single edge
|
||||
// set descriptor, you do not have to pass it in a list.
|
||||
// Each edge set descriptor can be any of:
|
||||
// - A vector pointing towards an edge.
|
||||
// - A vector pointing towards a face, indicating all edges surrounding that face.
|
||||
// - A vector pointing towards a corner, indicating all edges touching that corner.
|
||||
// - The string `"X"`, indicating all X axis aligned edges.
|
||||
// - The string `"Y"`, indicating all Y axis aligned edges.
|
||||
// - The string `"Z"`, indicating all Z axis aligned edges.
|
||||
// - The string `"ALL"`, indicating all edges.
|
||||
// - The string `"NONE"`, indicating no edges at all.
|
||||
// - A raw edges array, where each edge is represented by a 1 or a 0. The edge ordering is:
|
||||
// ```
|
||||
// [
|
||||
// [Y-Z-, Y+Z-, Y-Z+, Y+Z+],
|
||||
// [X-Z-, X+Z-, X-Z+, X+Z+],
|
||||
// [X-Y-, X+Y-, X-Y+, X+Y+]
|
||||
// ]
|
||||
// ```
|
||||
// Figure(3D,Big): Edge Vectors
|
||||
// ydistribute(50) {
|
||||
// xdistribute(30) {
|
||||
// show_edges(edges=BOT+RIGHT);
|
||||
// show_edges(edges=BOT+BACK);
|
||||
// show_edges(edges=BOT+LEFT);
|
||||
// show_edges(edges=BOT+FRONT);
|
||||
// }
|
||||
// xdistribute(30) {
|
||||
// show_edges(edges=FWD+RIGHT);
|
||||
// show_edges(edges=BACK+RIGHT);
|
||||
// show_edges(edges=BACK+LEFT);
|
||||
// show_edges(edges=FWD+LEFT);
|
||||
// }
|
||||
// xdistribute(30) {
|
||||
// show_edges(edges=TOP+RIGHT);
|
||||
// show_edges(edges=TOP+BACK);
|
||||
// show_edges(edges=TOP+LEFT);
|
||||
// show_edges(edges=TOP+FRONT);
|
||||
// }
|
||||
// }
|
||||
// Figure(3D,Big): Corner Vector Edge Sets
|
||||
// ydistribute(50) {
|
||||
// xdistribute(30) {
|
||||
// show_edges(edges=FRONT+LEFT+TOP);
|
||||
// show_edges(edges=FRONT+RIGHT+TOP);
|
||||
// show_edges(edges=FRONT+LEFT+BOT);
|
||||
// show_edges(edges=FRONT+RIGHT+BOT);
|
||||
// }
|
||||
// xdistribute(30) {
|
||||
// show_edges(edges=TOP+LEFT+BACK);
|
||||
// show_edges(edges=TOP+RIGHT+BACK);
|
||||
// show_edges(edges=BOT+LEFT+BACK);
|
||||
// show_edges(edges=BOT+RIGHT+BACK);
|
||||
// }
|
||||
// }
|
||||
// Figure(3D,Med): Face Vector Edge Sets
|
||||
// ydistribute(50) {
|
||||
// xdistribute(30) {
|
||||
// show_edges(edges=LEFT);
|
||||
// show_edges(edges=FRONT);
|
||||
// show_edges(edges=RIGHT);
|
||||
// }
|
||||
// xdistribute(30) {
|
||||
// show_edges(edges=TOP);
|
||||
// show_edges(edges=BACK);
|
||||
// show_edges(edges=BOTTOM);
|
||||
// }
|
||||
// }
|
||||
// Figure(3D,Med): Named Edge Sets
|
||||
// ydistribute(50) {
|
||||
// xdistribute(30) {
|
||||
// show_edges(edges="X");
|
||||
// show_edges(edges="Y");
|
||||
// show_edges(edges="Z");
|
||||
// }
|
||||
// xdistribute(30) {
|
||||
// show_edges(edges="ALL");
|
||||
// show_edges(edges="NONE");
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Arguments:
|
||||
// v = The edge set to include.
|
||||
// except = The edge set to specifically exclude, even if they are in `v`.
|
||||
//
|
||||
// See Also: EDGES_NONE, EDGES_ALL
|
||||
//
|
||||
// Example(3D): Just the front-top edge
|
||||
// edg = edges(FRONT+TOP);
|
||||
// show_edges(edges=edg);
|
||||
// Example(3D): All edges surrounding either the front or top faces
|
||||
// edg = edges([FRONT,TOP]);
|
||||
// show_edges(edges=edg);
|
||||
// Example(3D): All edges around the bottom face, except any that are also on the front
|
||||
// edg = edges(BTM, except=FRONT);
|
||||
// show_edges(edges=edg);
|
||||
// Example(3D): All edges except those around the bottom face.
|
||||
// edg = edges("ALL", except=BOTTOM);
|
||||
// show_edges(edges=edg);
|
||||
// Example(3D): All Z-aligned edges except those around the back face.
|
||||
// edg = edges("Z", except=BACK);
|
||||
// show_edges(edges=edg);
|
||||
// Example(3D): All edges around the bottom or front faces, except the bottom-front edge.
|
||||
// edg = edges([BOTTOM,FRONT], except=BOTTOM+FRONT);
|
||||
// show_edges(edges=edg);
|
||||
// Example(3D): All edges, except Z-aligned edges on the front.
|
||||
// edg = edges("ALL", except=edges("Z", except=BACK));
|
||||
// show_edges(edges=edg);
|
||||
function edges(v, except=[]) =
|
||||
(is_string(v) || is_vector(v) || _is_edge_array(v))? edges([v], except=except) :
|
||||
(is_string(except) || is_vector(except) || _is_edge_array(except))? edges(v, except=[except]) :
|
||||
|
||||
|
||||
/// Internal Function: _edges()
|
||||
/// Topics: Edges
|
||||
/// Usage:
|
||||
/// edgs = _edges(v);
|
||||
/// edgs = _edges(v, except);
|
||||
///
|
||||
/// Description:
|
||||
/// Takes a list of edge set descriptors, and returns a normalized edges array
|
||||
/// that represents all those given edges.
|
||||
/// Arguments:
|
||||
/// v = The edge set to include.
|
||||
/// except = The edge set to specifically exclude, even if they are in `v`.
|
||||
///
|
||||
/// See Also: EDGES_NONE, EDGES_ALL
|
||||
///
|
||||
function _edges(v, except=[]) =
|
||||
(is_string(v) || is_vector(v) || _is_edge_array(v))? _edges([v], except=except) :
|
||||
(is_string(except) || is_vector(except) || _is_edge_array(except))? _edges(v, except=[except]) :
|
||||
except==[]? _normalize_edges(sum([for (x=v) _edge_set(x)])) :
|
||||
_normalize_edges(
|
||||
_normalize_edges(sum([for (x=v) _edge_set(x)])) -
|
||||
|
@ -292,22 +433,22 @@ function edges(v, except=[]) =
|
|||
);
|
||||
|
||||
|
||||
// Module: show_edges()
|
||||
// Topics: Edges, Debugging
|
||||
// Usage:
|
||||
// show_edges(edges, [size=], [text=], [txtsize=]);
|
||||
// Description:
|
||||
// Draws a semi-transparent cube with the given edges highlighted in red.
|
||||
// Arguments:
|
||||
// edges = The edges to highlight.
|
||||
// size = The scalar size of the cube.
|
||||
// text = The text to show on the front of the cube.
|
||||
// txtsize = The size of the text.
|
||||
// See Also: edges(), EDGES_NONE, EDGES_ALL
|
||||
// Example:
|
||||
// show_edges(size=30, edges=["X","Y"]);
|
||||
module show_edges(edges="ALL", size=20, text, txtsize=3) {
|
||||
edge_set = edges(edges);
|
||||
/// Internal Module: _show_edges()
|
||||
/// Topics: Edges, Debugging
|
||||
/// Usage:
|
||||
/// _show_edges(edges, [size=], [text=], [txtsize=]);
|
||||
/// Description:
|
||||
/// Draws a semi-transparent cube with the given edges highlighted in red.
|
||||
/// Arguments:
|
||||
/// edges = The edges to highlight.
|
||||
/// size = The scalar size of the cube.
|
||||
/// text = The text to show on the front of the cube.
|
||||
/// txtsize = The size of the text.
|
||||
/// See Also: _edges(), EDGES_NONE, EDGES_ALL
|
||||
/// Example:
|
||||
/// _show_edges(size=30, edges=["X","Y"]);
|
||||
module _show_edges(edges="ALL", size=20, text, txtsize=3,toplabel) {
|
||||
edge_set = _edges(edges);
|
||||
text = !is_undef(text) ? text : _edges_text(edges);
|
||||
color("red") {
|
||||
for (axis=[0:2], i=[0:3]) {
|
||||
|
@ -322,40 +463,40 @@ module show_edges(edges="ALL", size=20, text, txtsize=3) {
|
|||
}
|
||||
fwd(size/2) _edges_text3d(text, size=txtsize);
|
||||
color("yellow",0.7) cuboid(size=size);
|
||||
color("black")
|
||||
if (is_def(toplabel))
|
||||
for(h=idx(toplabel)) up(21+6*h)rot($vpr)atext(select(toplabel,-h-1),size=3.3,h=.1,orient=UP,anchor=FRONT);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Section: Corner Constants
|
||||
// Constants for working with corners.
|
||||
|
||||
|
||||
// Constant: CORNERS_NONE
|
||||
// Topics: Corners
|
||||
// Description:
|
||||
// The set of no corners.
|
||||
// Figure(3D):
|
||||
// show_corners(corners="NONE");
|
||||
// See Also: CORNERS_ALL, corners()
|
||||
/// Internal Constant: CORNERS_NONE
|
||||
/// Topics: Corners
|
||||
/// Description:
|
||||
/// The set of no corners.
|
||||
/// Figure(3D):
|
||||
/// _show_corners(corners="NONE");
|
||||
/// See Also: CORNERS_ALL, corners()
|
||||
CORNERS_NONE = [0,0,0,0,0,0,0,0]; // No corners.
|
||||
|
||||
|
||||
// Constant: CORNERS_ALL
|
||||
// Topics: Corners
|
||||
// Description:
|
||||
// The set of all corners.
|
||||
// Figure(3D):
|
||||
// show_corners(corners="ALL");
|
||||
// See Also: CORNERS_NONE, corners()
|
||||
/// Internal Constant: CORNERS_ALL
|
||||
/// Topics: Corners
|
||||
/// Description:
|
||||
/// The set of all corners.
|
||||
/// Figure(3D):
|
||||
/// _show_corners(corners="ALL");
|
||||
/// See Also: CORNERS_NONE, _corners()
|
||||
CORNERS_ALL = [1,1,1,1,1,1,1,1];
|
||||
|
||||
|
||||
// Constant: CORNER_OFFSETS
|
||||
// Topics: Corners
|
||||
// Description:
|
||||
// The vectors pointing to each corner of a unit sized cube.
|
||||
// Each item in a corner array will have a corresponding vector in this array.
|
||||
// See Also: CORNERS_NONE, CORNERS_ALL, corners()
|
||||
/// Internal Constant: CORNER_OFFSETS
|
||||
/// Topics: Corners
|
||||
/// Description:
|
||||
/// The vectors pointing to each corner of a unit sized cube.
|
||||
/// Each item in a corner array will have a corresponding vector in this array.
|
||||
/// See Also: CORNERS_NONE, CORNERS_ALL, _corners()
|
||||
CORNER_OFFSETS = [
|
||||
[-1,-1,-1], [ 1,-1,-1], [-1, 1,-1], [ 1, 1,-1],
|
||||
[-1,-1, 1], [ 1,-1, 1], [-1, 1, 1], [ 1, 1, 1]
|
||||
|
@ -363,7 +504,6 @@ CORNER_OFFSETS = [
|
|||
|
||||
|
||||
|
||||
// Section: Corner Helpers
|
||||
|
||||
/// Internal Function: _is_corner_array()
|
||||
/// Topics: Corners, Type Checking
|
||||
|
@ -371,7 +511,7 @@ CORNER_OFFSETS = [
|
|||
/// bool = _is_corner_array(x)
|
||||
/// Description:
|
||||
/// Returns true if the given value has the form of a corner array.
|
||||
/// See Also: CORNERS_NONE, CORNERS_ALL, corners()
|
||||
/// See Also: CORNERS_NONE, CORNERS_ALL, _corners()
|
||||
function _is_corner_array(x) = is_vector(x) && len(x)==8 && all([for (xx=x) xx==1||xx==0]);
|
||||
|
||||
|
||||
|
@ -382,7 +522,7 @@ function _is_corner_array(x) = is_vector(x) && len(x)==8 && all([for (xx=x) xx==
|
|||
/// Description:
|
||||
/// Normalizes all values in a corner array to be `1`, if it was originally greater than `0`,
|
||||
/// or `0`, if it was originally less than or equal to `0`.
|
||||
/// See Also: CORNERS_NONE, CORNERS_ALL, corners()
|
||||
/// See Also: CORNERS_NONE, CORNERS_ALL, _corners()
|
||||
function _normalize_corners(v) = [for (x=v) x>0? 1 : 0];
|
||||
|
||||
|
||||
|
@ -405,100 +545,20 @@ function _corner_set(v) =
|
|||
];
|
||||
|
||||
|
||||
// Function: corners()
|
||||
// Topics: Corners
|
||||
// Usage:
|
||||
// corns = corners(v);
|
||||
// corns = corners(v, except);
|
||||
// Description:
|
||||
// Takes a list of corner set descriptors, and returns a normalized corners array
|
||||
// that represents all those given corners. If the `except` argument is given
|
||||
// a list of corner set descriptors, then all those corners will be removed
|
||||
// from the returned corners array. If either argument only has a single corner
|
||||
// set descriptor, you do not have to pass it in a list.
|
||||
// Each corner set descriptor can be any of:
|
||||
// - A vector pointing towards an edge indicating both corners at the ends of that edge.
|
||||
// - A vector pointing towards a face, indicating all the corners of that face.
|
||||
// - A vector pointing towards a corner, indicating just that corner.
|
||||
// - The string `"ALL"`, indicating all corners.
|
||||
// - The string `"NONE"`, indicating no corners at all.
|
||||
// - A raw corners array, where each corner is represented by a 1 or a 0. The corner ordering is:
|
||||
// ```
|
||||
// [X-Y-Z-, X+Y-Z-, X-Y+Z-, X+Y+Z-, X-Y-Z+, X+Y-Z+, X-Y+Z+, X+Y+Z+]
|
||||
// ```
|
||||
// Figure(3D,Big): Corners by Corner Vector
|
||||
// ydistribute(55) {
|
||||
// xdistribute(35) {
|
||||
// show_corners(corners=FRONT+LEFT+TOP);
|
||||
// show_corners(corners=FRONT+RIGHT+TOP);
|
||||
// show_corners(corners=FRONT+LEFT+BOT);
|
||||
// show_corners(corners=FRONT+RIGHT+BOT);
|
||||
// }
|
||||
// xdistribute(35) {
|
||||
// show_corners(corners=TOP+LEFT+BACK);
|
||||
// show_corners(corners=TOP+RIGHT+BACK);
|
||||
// show_corners(corners=BOT+LEFT+BACK);
|
||||
// show_corners(corners=BOT+RIGHT+BACK);
|
||||
// }
|
||||
// }
|
||||
// Figure(3D,Big): Corners by Edge Vectors
|
||||
// ydistribute(55) {
|
||||
// xdistribute(35) {
|
||||
// show_corners(corners=BOT+RIGHT);
|
||||
// show_corners(corners=BOT+BACK);
|
||||
// show_corners(corners=BOT+LEFT);
|
||||
// show_corners(corners=BOT+FRONT);
|
||||
// }
|
||||
// xdistribute(35) {
|
||||
// show_corners(corners=FWD+RIGHT);
|
||||
// show_corners(corners=BACK+RIGHT);
|
||||
// show_corners(corners=BACK+LEFT);
|
||||
// show_corners(corners=FWD+LEFT);
|
||||
// }
|
||||
// xdistribute(35) {
|
||||
// show_corners(corners=TOP+RIGHT);
|
||||
// show_corners(corners=TOP+BACK);
|
||||
// show_corners(corners=TOP+LEFT);
|
||||
// show_corners(corners=TOP+FRONT);
|
||||
// }
|
||||
// }
|
||||
// Figure(3D,Med): Corners by Face Vectors
|
||||
// ydistribute(55) {
|
||||
// xdistribute(35) {
|
||||
// show_corners(corners=LEFT);
|
||||
// show_corners(corners=FRONT);
|
||||
// show_corners(corners=RIGHT);
|
||||
// }
|
||||
// xdistribute(35) {
|
||||
// show_corners(corners=TOP);
|
||||
// show_corners(corners=BACK);
|
||||
// show_corners(corners=BOTTOM);
|
||||
// }
|
||||
// }
|
||||
// Figure(3D,Med): Corners by Name
|
||||
// xdistribute(35) {
|
||||
// show_corners(corners="ALL");
|
||||
// show_corners(corners="NONE");
|
||||
// }
|
||||
// See Also: CORNERS_NONE, CORNERS_ALL
|
||||
// Example(3D): Just the front-top-right corner
|
||||
// crn = corners(FRONT+TOP+RIGHT);
|
||||
// show_corners(corners=crn);
|
||||
// Example(3D): All corners surrounding either the front or top faces
|
||||
// crn = corners([FRONT,TOP]);
|
||||
// show_corners(corners=crn);
|
||||
// Example(3D): All corners around the bottom face, except any that are also on the front
|
||||
// crn = corners(BTM, except=FRONT);
|
||||
// show_corners(corners=crn);
|
||||
// Example(3D): All corners except those around the bottom face.
|
||||
// crn = corners("ALL", except=BOTTOM);
|
||||
// show_corners(corners=crn);
|
||||
// Example(3D): All corners around the bottom or front faces, except those on the bottom-front edge.
|
||||
// crn = corners([BOTTOM,FRONT], except=BOTTOM+FRONT);
|
||||
// show_corners(corners=crn);
|
||||
function corners(v, except=[]) =
|
||||
(is_string(v) || is_vector(v) || _is_corner_array(v))? corners([v], except=except) :
|
||||
(is_string(except) || is_vector(except) || _is_corner_array(except))? corners(v, except=[except]) :
|
||||
/// Function: _corners()
|
||||
/// Topics: Corners
|
||||
/// Usage:
|
||||
/// corns = _corners(v);
|
||||
/// corns = _corners(v, except);
|
||||
/// Description:
|
||||
/// Takes a list of corner set descriptors, and returns a normalized corners array
|
||||
/// that represents all those given corners. If the `except` argument is given
|
||||
/// a list of corner set descriptors, then all those corners will be removed
|
||||
/// from the returned corners array. If either argument only has a single corner
|
||||
/// set descriptor, you do not have to pass it in a list.
|
||||
function _corners(v, except=[]) =
|
||||
(is_string(v) || is_vector(v) || _is_corner_array(v))? _corners([v], except=except) :
|
||||
(is_string(except) || is_vector(except) || _is_corner_array(except))? _corners(v, except=[except]) :
|
||||
except==[]? _normalize_corners(sum([for (x=v) _corner_set(x)])) :
|
||||
let(
|
||||
a = _normalize_corners(sum([for (x=v) _corner_set(x)])),
|
||||
|
@ -514,7 +574,7 @@ function corners(v, except=[]) =
|
|||
/// Arguments:
|
||||
/// edges = Standard edges array.
|
||||
/// v = Vector pointing to the corner to count edge intersections at.
|
||||
/// See Also: CORNERS_NONE, CORNERS_ALL, corners()
|
||||
/// See Also: CORNERS_NONE, CORNERS_ALL, _corners()
|
||||
function _corner_edges(edges, v) =
|
||||
let(u = (v+[1,1,1])/2) [edges[0][u.y+u.z*2], edges[1][u.x+u.z*2], edges[2][u.x+u.y*2]];
|
||||
|
||||
|
@ -526,7 +586,7 @@ function _corner_edges(edges, v) =
|
|||
/// Arguments:
|
||||
/// edges = Standard edges array.
|
||||
/// v = Vector pointing to the corner to count edge intersections at.
|
||||
/// See Also: CORNERS_NONE, CORNERS_ALL, corners()
|
||||
/// See Also: CORNERS_NONE, CORNERS_ALL, _corners()
|
||||
function _corner_edge_count(edges, v) =
|
||||
let(u = (v+[1,1,1])/2) edges[0][u.y+u.z*2] + edges[1][u.x+u.z*2] + edges[2][u.x+u.y*2];
|
||||
|
||||
|
@ -552,30 +612,46 @@ function _corners_text(corners) =
|
|||
[""];
|
||||
|
||||
|
||||
// Module: show_corners()
|
||||
// Topics: Corners, Debugging
|
||||
// Usage:
|
||||
// show_corners(corners, [size=], [text=], [txtsize=]);
|
||||
// Description:
|
||||
// Draws a semi-transparent cube with the given corners highlighted in red.
|
||||
// Arguments:
|
||||
// corners = The corners to highlight.
|
||||
// size = The scalar size of the cube.
|
||||
// text = If given, overrides the text to be shown on the front of the cube.
|
||||
// txtsize = The size of the text.
|
||||
// See Also: CORNERS_NONE, CORNERS_ALL, corners()
|
||||
// Example:
|
||||
// show_corners(corners=FWD+RIGHT, size=30);
|
||||
module show_corners(corners="ALL", size=20, text, txtsize=3) {
|
||||
corner_set = corners(corners);
|
||||
/// Internal Module: _show_corners()
|
||||
/// Topics: Corners, Debugging
|
||||
/// Usage:
|
||||
/// _show_corners(corners, [size=], [text=], [txtsize=]);
|
||||
/// Description:
|
||||
/// Draws a semi-transparent cube with the given corners highlighted in red.
|
||||
/// Arguments:
|
||||
/// corners = The corners to highlight.
|
||||
/// size = The scalar size of the cube.
|
||||
/// text = If given, overrides the text to be shown on the front of the cube.
|
||||
/// txtsize = The size of the text.
|
||||
/// See Also: CORNERS_NONE, CORNERS_ALL, corners()
|
||||
/// Example:
|
||||
/// _show_corners(corners=FWD+RIGHT, size=30);
|
||||
module _show_corners(corners="ALL", size=20, text, txtsize=3,toplabel) {
|
||||
corner_set = _corners(corners);
|
||||
text = !is_undef(text) ? text : _corners_text(corners);
|
||||
for (i=[0:7]) if (corner_set[i]>0)
|
||||
translate(CORNER_OFFSETS[i]*size/2)
|
||||
color("red") sphere(d=2, $fn=16);
|
||||
fwd(size/2) _edges_text3d(text, size=txtsize);
|
||||
color("yellow",0.7) cuboid(size=size);
|
||||
color("black")
|
||||
if (is_def(toplabel))
|
||||
for(h=idx(toplabel)) up(21+6*h)rot($vpr)atext(select(toplabel,-h-1),size=3.3,h=.1,orient=UP,anchor=FRONT);
|
||||
}
|
||||
|
||||
|
||||
module _show_cube_faces(faces, size=20, toplabel,botlabel) {
|
||||
color("red")
|
||||
for(f=faces){
|
||||
move(f*size/2) rot(from=UP,to=f)
|
||||
cuboid([size,size,.1]);
|
||||
}
|
||||
color("black"){
|
||||
if (is_def(toplabel))
|
||||
for(h=idx(toplabel)) up(21+6*h)rot($vpr)atext(select(toplabel,-h-1),size=3.3,h=.1,orient=UP,anchor=FRONT);
|
||||
if (is_def(botlabel))
|
||||
for(h=idx(botlabel)) down(26+6*h)rot($vpr)atext(botlabel[h],size=3.3,h=.1,orient=UP,anchor=FRONT);
|
||||
}
|
||||
color("yellow",0.7) cuboid(size=size);
|
||||
}
|
||||
|
||||
// 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
|
||||
|
|
|
@ -89,31 +89,32 @@ function cube(size=1, center, anchor, spin=0, orient=UP) =
|
|||
// cuboid(size, p1=, ...);
|
||||
// cuboid(p1=, p2=, ...);
|
||||
// Usage: Chamfered Cubes
|
||||
// cuboid(size, [chamfer=], [edges=], [except_edges=], [trimcorners=], ...);
|
||||
// cuboid(size, [chamfer=], [edges=], [except=], [trimcorners=], ...);
|
||||
// Usage: Rounded Cubes
|
||||
// cuboid(size, [rounding=], [edges=], [except_edges=], [trimcorners=], ...);
|
||||
// cuboid(size, [rounding=], [edges=], [except=], [trimcorners=], ...);
|
||||
// Usage: Attaching children
|
||||
// cuboid(size, [anchor=], ...) [attachments];
|
||||
//
|
||||
// Description:
|
||||
// Creates a cube or cuboid object, with optional chamfering or rounding.
|
||||
// Negative chamfers and roundings can be applied to create external masks,
|
||||
// but only apply to edges around the top or bottom faces.
|
||||
//
|
||||
// Creates a cube or cuboid object, with optional chamfering or rounding of edges and corners.
|
||||
// You cannot mix chamfering and rounding: just one edge treatment with the same size applies to all selected edges.
|
||||
// Negative chamfers and roundings can be applied to create external fillets, but they
|
||||
// but only apply to edges around the top or bottom faces. If you specify an edge set other than "ALL"
|
||||
// with such roundings or chamfers then you will get an error. See
|
||||
// [Specifying Edges](edges.scad#section-specifying-edges) for information on how to specify edge sets.
|
||||
// Arguments:
|
||||
// size = The size of the cube.
|
||||
// size = The size of the cube, a number or length 3 vector.
|
||||
// ---
|
||||
// chamfer = Size of chamfer, inset from sides. Default: No chamfering.
|
||||
// rounding = Radius of the edge rounding. Default: No rounding.
|
||||
// edges = Edges to chamfer/round. See the docs for [`edges()`](edges.scad#edges) to see acceptable values. Default: All edges.
|
||||
// except_edges = Edges to explicitly NOT chamfer/round. See the docs for [`edges()`](edges.scad#edges) to see acceptable values. Default: No edges.
|
||||
// edges = Edges to mask. See [Specifying Edges](edges.scad#section-specifying-edges). Default: all edges.
|
||||
// except = Edges to explicitly NOT mask. See [Specifying Edges](edges.scad#section-specifying-edges). Default: No edges.
|
||||
// trimcorners = If true, rounds or chamfers corners where three chamfered/rounded edges meet. Default: `true`
|
||||
// p1 = Align the cuboid's corner at `p1`, if given. Forces `anchor=ALLNEG`.
|
||||
// p2 = If given with `p1`, defines the cornerpoints of the cuboid.
|
||||
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#anchor). Default: `CENTER`
|
||||
// spin = Rotate this many degrees around the Z axis. See [spin](attachments.scad#spin). Default: `0`
|
||||
// orient = Vector to rotate top towards. See [orient](attachments.scad#orient). Default: `UP`
|
||||
//
|
||||
// Example: Simple regular cube.
|
||||
// cuboid(40);
|
||||
// Example: Cube with minimum cornerpoint given.
|
||||
|
@ -145,25 +146,25 @@ function cube(size=1, center, anchor, spin=0, orient=UP) =
|
|||
// Example: Negative Chamferring
|
||||
// cuboid(
|
||||
// [30,40,50], chamfer=-5,
|
||||
// edges=[TOP,BOT], except_edges=RIGHT,
|
||||
// edges=[TOP,BOT], except=RIGHT,
|
||||
// $fn=24
|
||||
// );
|
||||
// Example: Negative Chamferring, Untrimmed Corners
|
||||
// cuboid(
|
||||
// [30,40,50], chamfer=-5,
|
||||
// edges=[TOP,BOT], except_edges=RIGHT,
|
||||
// edges=[TOP,BOT], except=RIGHT,
|
||||
// trimcorners=false, $fn=24
|
||||
// );
|
||||
// Example: Negative Rounding
|
||||
// cuboid(
|
||||
// [30,40,50], rounding=-5,
|
||||
// edges=[TOP,BOT], except_edges=RIGHT,
|
||||
// edges=[TOP,BOT], except=RIGHT,
|
||||
// $fn=24
|
||||
// );
|
||||
// Example: Negative Rounding, Untrimmed Corners
|
||||
// cuboid(
|
||||
// [30,40,50], rounding=-5,
|
||||
// edges=[TOP,BOT], except_edges=RIGHT,
|
||||
// edges=[TOP,BOT], except=RIGHT,
|
||||
// trimcorners=false, $fn=24
|
||||
// );
|
||||
// Example: Standard Connectors
|
||||
|
@ -174,7 +175,8 @@ module cuboid(
|
|||
chamfer,
|
||||
rounding,
|
||||
edges=EDGES_ALL,
|
||||
except_edges=[],
|
||||
except=[],
|
||||
except_edges,
|
||||
trimcorners=true,
|
||||
anchor=CENTER,
|
||||
spin=0,
|
||||
|
@ -226,11 +228,11 @@ module cuboid(
|
|||
}
|
||||
|
||||
size = scalar_vec3(size);
|
||||
edges = edges(edges, except=except_edges);
|
||||
edges = _edges(edges, except=first_defined([except_edges,except]));
|
||||
assert(is_vector(size,3));
|
||||
assert(all_positive(size));
|
||||
assert(is_undef(chamfer) || is_finite(chamfer));
|
||||
assert(is_undef(rounding) || is_finite(rounding));
|
||||
assert(is_undef(chamfer) || is_finite(chamfer),"chamfer must be a finite value");
|
||||
assert(is_undef(rounding) || is_finite(rounding),"rounding must be a finite value");
|
||||
assert(is_undef(p1) || is_vector(p1));
|
||||
assert(is_undef(p2) || is_vector(p2));
|
||||
assert(is_bool(trimcorners));
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ module test__is_edge_array() {
|
|||
assert(!_is_edge_array("foo"));
|
||||
assert(!_is_edge_array(42));
|
||||
assert(!_is_edge_array(true));
|
||||
assert(_is_edge_array(edges(["X","Y"])));
|
||||
assert(_is_edge_array(_edges(["X","Y"])));
|
||||
}
|
||||
test__is_edge_array();
|
||||
|
||||
|
@ -72,26 +72,26 @@ module test__normalize_edges() {
|
|||
test__normalize_edges();
|
||||
|
||||
|
||||
module test_edges() {
|
||||
assert(edges("X")==[[1,1,1,1],[0,0,0,0],[0,0,0,0]]);
|
||||
assert(edges("Y")==[[0,0,0,0],[1,1,1,1],[0,0,0,0]]);
|
||||
assert(edges("Z")==[[0,0,0,0],[0,0,0,0],[1,1,1,1]]);
|
||||
assert(edges(["X"])==[[1,1,1,1],[0,0,0,0],[0,0,0,0]]);
|
||||
assert(edges(["Y"])==[[0,0,0,0],[1,1,1,1],[0,0,0,0]]);
|
||||
assert(edges(["Z"])==[[0,0,0,0],[0,0,0,0],[1,1,1,1]]);
|
||||
assert(edges(["X","Y"])==[[1,1,1,1],[1,1,1,1],[0,0,0,0]]);
|
||||
assert(edges(["X","Z"])==[[1,1,1,1],[0,0,0,0],[1,1,1,1]]);
|
||||
assert(edges(["Y","Z"])==[[0,0,0,0],[1,1,1,1],[1,1,1,1]]);
|
||||
assert(edges("ALL",except="X")==[[0,0,0,0],[1,1,1,1],[1,1,1,1]]);
|
||||
assert(edges("ALL",except="Y")==[[1,1,1,1],[0,0,0,0],[1,1,1,1]]);
|
||||
assert(edges("ALL",except="Z")==[[1,1,1,1],[1,1,1,1],[0,0,0,0]]);
|
||||
assert(edges(["Y","Z"],except=[FRONT+RIGHT,FRONT+LEFT])==[[0,0,0,0],[1,1,1,1],[0,0,1,1]]);
|
||||
module test__edges() {
|
||||
assert(_edges("X")==[[1,1,1,1],[0,0,0,0],[0,0,0,0]]);
|
||||
assert(_edges("Y")==[[0,0,0,0],[1,1,1,1],[0,0,0,0]]);
|
||||
assert(_edges("Z")==[[0,0,0,0],[0,0,0,0],[1,1,1,1]]);
|
||||
assert(_edges(["X"])==[[1,1,1,1],[0,0,0,0],[0,0,0,0]]);
|
||||
assert(_edges(["Y"])==[[0,0,0,0],[1,1,1,1],[0,0,0,0]]);
|
||||
assert(_edges(["Z"])==[[0,0,0,0],[0,0,0,0],[1,1,1,1]]);
|
||||
assert(_edges(["X","Y"])==[[1,1,1,1],[1,1,1,1],[0,0,0,0]]);
|
||||
assert(_edges(["X","Z"])==[[1,1,1,1],[0,0,0,0],[1,1,1,1]]);
|
||||
assert(_edges(["Y","Z"])==[[0,0,0,0],[1,1,1,1],[1,1,1,1]]);
|
||||
assert(_edges("ALL",except="X")==[[0,0,0,0],[1,1,1,1],[1,1,1,1]]);
|
||||
assert(_edges("ALL",except="Y")==[[1,1,1,1],[0,0,0,0],[1,1,1,1]]);
|
||||
assert(_edges("ALL",except="Z")==[[1,1,1,1],[1,1,1,1],[0,0,0,0]]);
|
||||
assert(_edges(["Y","Z"],except=[FRONT+RIGHT,FRONT+LEFT])==[[0,0,0,0],[1,1,1,1],[0,0,1,1]]);
|
||||
}
|
||||
test_edges();
|
||||
test__edges();
|
||||
|
||||
|
||||
module test__corner_edge_count() {
|
||||
edges = edges([TOP,FRONT+RIGHT]);
|
||||
edges = _edges([TOP,FRONT+RIGHT]);
|
||||
assert(_corner_edge_count(edges,TOP+FRONT+RIGHT) == 3);
|
||||
assert(_corner_edge_count(edges,TOP+FRONT+LEFT) == 2);
|
||||
assert(_corner_edge_count(edges,BOTTOM+FRONT+RIGHT) == 1);
|
||||
|
@ -101,7 +101,7 @@ test__corner_edge_count();
|
|||
|
||||
|
||||
module test__corner_edges() {
|
||||
edges = edges([TOP,FRONT+RIGHT]);
|
||||
edges = _edges([TOP,FRONT+RIGHT]);
|
||||
assert_equal(_corner_edges(edges,TOP+FRONT+RIGHT), [1,1,1]);
|
||||
assert_equal(_corner_edges(edges,TOP+FRONT+LEFT), [1,1,0]);
|
||||
assert_equal(_corner_edges(edges,BOTTOM+FRONT+RIGHT), [0,0,1]);
|
||||
|
@ -110,73 +110,73 @@ module test__corner_edges() {
|
|||
test__corner_edges();
|
||||
|
||||
|
||||
module test_corners() {
|
||||
assert_equal(corners(BOT + FRONT + LEFT ), [1,0,0,0,0,0,0,0]);
|
||||
assert_equal(corners(BOT + FRONT + RIGHT), [0,1,0,0,0,0,0,0]);
|
||||
assert_equal(corners(BOT + BACK + LEFT ), [0,0,1,0,0,0,0,0]);
|
||||
assert_equal(corners(BOT + BACK + RIGHT), [0,0,0,1,0,0,0,0]);
|
||||
assert_equal(corners(TOP + FRONT + LEFT ), [0,0,0,0,1,0,0,0]);
|
||||
assert_equal(corners(TOP + FRONT + RIGHT), [0,0,0,0,0,1,0,0]);
|
||||
assert_equal(corners(TOP + BACK + LEFT ), [0,0,0,0,0,0,1,0]);
|
||||
assert_equal(corners(TOP + BACK + RIGHT), [0,0,0,0,0,0,0,1]);
|
||||
module test__corners() {
|
||||
assert_equal(_corners(BOT + FRONT + LEFT ), [1,0,0,0,0,0,0,0]);
|
||||
assert_equal(_corners(BOT + FRONT + RIGHT), [0,1,0,0,0,0,0,0]);
|
||||
assert_equal(_corners(BOT + BACK + LEFT ), [0,0,1,0,0,0,0,0]);
|
||||
assert_equal(_corners(BOT + BACK + RIGHT), [0,0,0,1,0,0,0,0]);
|
||||
assert_equal(_corners(TOP + FRONT + LEFT ), [0,0,0,0,1,0,0,0]);
|
||||
assert_equal(_corners(TOP + FRONT + RIGHT), [0,0,0,0,0,1,0,0]);
|
||||
assert_equal(_corners(TOP + BACK + LEFT ), [0,0,0,0,0,0,1,0]);
|
||||
assert_equal(_corners(TOP + BACK + RIGHT), [0,0,0,0,0,0,0,1]);
|
||||
|
||||
assert_equal(corners(BOT + FRONT), [1,1,0,0,0,0,0,0]);
|
||||
assert_equal(corners(BOT + BACK ), [0,0,1,1,0,0,0,0]);
|
||||
assert_equal(corners(TOP + FRONT), [0,0,0,0,1,1,0,0]);
|
||||
assert_equal(corners(TOP + BACK ), [0,0,0,0,0,0,1,1]);
|
||||
assert_equal(corners(BOT + LEFT ), [1,0,1,0,0,0,0,0]);
|
||||
assert_equal(corners(BOT + RIGHT), [0,1,0,1,0,0,0,0]);
|
||||
assert_equal(corners(TOP + LEFT ), [0,0,0,0,1,0,1,0]);
|
||||
assert_equal(corners(TOP + RIGHT), [0,0,0,0,0,1,0,1]);
|
||||
assert_equal(corners(FRONT + LEFT ), [1,0,0,0,1,0,0,0]);
|
||||
assert_equal(corners(FRONT + RIGHT), [0,1,0,0,0,1,0,0]);
|
||||
assert_equal(corners(BACK + LEFT ), [0,0,1,0,0,0,1,0]);
|
||||
assert_equal(corners(BACK + RIGHT), [0,0,0,1,0,0,0,1]);
|
||||
assert_equal(_corners(BOT + FRONT), [1,1,0,0,0,0,0,0]);
|
||||
assert_equal(_corners(BOT + BACK ), [0,0,1,1,0,0,0,0]);
|
||||
assert_equal(_corners(TOP + FRONT), [0,0,0,0,1,1,0,0]);
|
||||
assert_equal(_corners(TOP + BACK ), [0,0,0,0,0,0,1,1]);
|
||||
assert_equal(_corners(BOT + LEFT ), [1,0,1,0,0,0,0,0]);
|
||||
assert_equal(_corners(BOT + RIGHT), [0,1,0,1,0,0,0,0]);
|
||||
assert_equal(_corners(TOP + LEFT ), [0,0,0,0,1,0,1,0]);
|
||||
assert_equal(_corners(TOP + RIGHT), [0,0,0,0,0,1,0,1]);
|
||||
assert_equal(_corners(FRONT + LEFT ), [1,0,0,0,1,0,0,0]);
|
||||
assert_equal(_corners(FRONT + RIGHT), [0,1,0,0,0,1,0,0]);
|
||||
assert_equal(_corners(BACK + LEFT ), [0,0,1,0,0,0,1,0]);
|
||||
assert_equal(_corners(BACK + RIGHT), [0,0,0,1,0,0,0,1]);
|
||||
|
||||
assert_equal(corners(LEFT), [1,0,1,0,1,0,1,0]);
|
||||
assert_equal(corners(RIGHT), [0,1,0,1,0,1,0,1]);
|
||||
assert_equal(corners(FRONT), [1,1,0,0,1,1,0,0]);
|
||||
assert_equal(corners(BACK), [0,0,1,1,0,0,1,1]);
|
||||
assert_equal(corners(BOT), [1,1,1,1,0,0,0,0]);
|
||||
assert_equal(corners(TOP), [0,0,0,0,1,1,1,1]);
|
||||
assert_equal(_corners(LEFT), [1,0,1,0,1,0,1,0]);
|
||||
assert_equal(_corners(RIGHT), [0,1,0,1,0,1,0,1]);
|
||||
assert_equal(_corners(FRONT), [1,1,0,0,1,1,0,0]);
|
||||
assert_equal(_corners(BACK), [0,0,1,1,0,0,1,1]);
|
||||
assert_equal(_corners(BOT), [1,1,1,1,0,0,0,0]);
|
||||
assert_equal(_corners(TOP), [0,0,0,0,1,1,1,1]);
|
||||
|
||||
assert_equal(corners([BOT + FRONT + LEFT ]), [1,0,0,0,0,0,0,0]);
|
||||
assert_equal(corners([BOT + FRONT + RIGHT]), [0,1,0,0,0,0,0,0]);
|
||||
assert_equal(corners([BOT + BACK + LEFT ]), [0,0,1,0,0,0,0,0]);
|
||||
assert_equal(corners([BOT + BACK + RIGHT]), [0,0,0,1,0,0,0,0]);
|
||||
assert_equal(corners([TOP + FRONT + LEFT ]), [0,0,0,0,1,0,0,0]);
|
||||
assert_equal(corners([TOP + FRONT + RIGHT]), [0,0,0,0,0,1,0,0]);
|
||||
assert_equal(corners([TOP + BACK + LEFT ]), [0,0,0,0,0,0,1,0]);
|
||||
assert_equal(corners([TOP + BACK + RIGHT]), [0,0,0,0,0,0,0,1]);
|
||||
assert_equal(_corners([BOT + FRONT + LEFT ]), [1,0,0,0,0,0,0,0]);
|
||||
assert_equal(_corners([BOT + FRONT + RIGHT]), [0,1,0,0,0,0,0,0]);
|
||||
assert_equal(_corners([BOT + BACK + LEFT ]), [0,0,1,0,0,0,0,0]);
|
||||
assert_equal(_corners([BOT + BACK + RIGHT]), [0,0,0,1,0,0,0,0]);
|
||||
assert_equal(_corners([TOP + FRONT + LEFT ]), [0,0,0,0,1,0,0,0]);
|
||||
assert_equal(_corners([TOP + FRONT + RIGHT]), [0,0,0,0,0,1,0,0]);
|
||||
assert_equal(_corners([TOP + BACK + LEFT ]), [0,0,0,0,0,0,1,0]);
|
||||
assert_equal(_corners([TOP + BACK + RIGHT]), [0,0,0,0,0,0,0,1]);
|
||||
|
||||
assert_equal(corners([BOT + FRONT]), [1,1,0,0,0,0,0,0]);
|
||||
assert_equal(corners([BOT + BACK ]), [0,0,1,1,0,0,0,0]);
|
||||
assert_equal(corners([TOP + FRONT]), [0,0,0,0,1,1,0,0]);
|
||||
assert_equal(corners([TOP + BACK ]), [0,0,0,0,0,0,1,1]);
|
||||
assert_equal(corners([BOT + LEFT ]), [1,0,1,0,0,0,0,0]);
|
||||
assert_equal(corners([BOT + RIGHT]), [0,1,0,1,0,0,0,0]);
|
||||
assert_equal(corners([TOP + LEFT ]), [0,0,0,0,1,0,1,0]);
|
||||
assert_equal(corners([TOP + RIGHT]), [0,0,0,0,0,1,0,1]);
|
||||
assert_equal(corners([FRONT + LEFT ]), [1,0,0,0,1,0,0,0]);
|
||||
assert_equal(corners([FRONT + RIGHT]), [0,1,0,0,0,1,0,0]);
|
||||
assert_equal(corners([BACK + LEFT ]), [0,0,1,0,0,0,1,0]);
|
||||
assert_equal(corners([BACK + RIGHT]), [0,0,0,1,0,0,0,1]);
|
||||
assert_equal(_corners([BOT + FRONT]), [1,1,0,0,0,0,0,0]);
|
||||
assert_equal(_corners([BOT + BACK ]), [0,0,1,1,0,0,0,0]);
|
||||
assert_equal(_corners([TOP + FRONT]), [0,0,0,0,1,1,0,0]);
|
||||
assert_equal(_corners([TOP + BACK ]), [0,0,0,0,0,0,1,1]);
|
||||
assert_equal(_corners([BOT + LEFT ]), [1,0,1,0,0,0,0,0]);
|
||||
assert_equal(_corners([BOT + RIGHT]), [0,1,0,1,0,0,0,0]);
|
||||
assert_equal(_corners([TOP + LEFT ]), [0,0,0,0,1,0,1,0]);
|
||||
assert_equal(_corners([TOP + RIGHT]), [0,0,0,0,0,1,0,1]);
|
||||
assert_equal(_corners([FRONT + LEFT ]), [1,0,0,0,1,0,0,0]);
|
||||
assert_equal(_corners([FRONT + RIGHT]), [0,1,0,0,0,1,0,0]);
|
||||
assert_equal(_corners([BACK + LEFT ]), [0,0,1,0,0,0,1,0]);
|
||||
assert_equal(_corners([BACK + RIGHT]), [0,0,0,1,0,0,0,1]);
|
||||
|
||||
assert_equal(corners([LEFT]), [1,0,1,0,1,0,1,0]);
|
||||
assert_equal(corners([RIGHT]), [0,1,0,1,0,1,0,1]);
|
||||
assert_equal(corners([FRONT]), [1,1,0,0,1,1,0,0]);
|
||||
assert_equal(corners([BACK]), [0,0,1,1,0,0,1,1]);
|
||||
assert_equal(corners([BOT]), [1,1,1,1,0,0,0,0]);
|
||||
assert_equal(corners([TOP]), [0,0,0,0,1,1,1,1]);
|
||||
assert_equal(_corners([LEFT]), [1,0,1,0,1,0,1,0]);
|
||||
assert_equal(_corners([RIGHT]), [0,1,0,1,0,1,0,1]);
|
||||
assert_equal(_corners([FRONT]), [1,1,0,0,1,1,0,0]);
|
||||
assert_equal(_corners([BACK]), [0,0,1,1,0,0,1,1]);
|
||||
assert_equal(_corners([BOT]), [1,1,1,1,0,0,0,0]);
|
||||
assert_equal(_corners([TOP]), [0,0,0,0,1,1,1,1]);
|
||||
|
||||
assert_equal(corners([TOP,FRONT+RIGHT]), [0,1,0,0,1,1,1,1]);
|
||||
assert_equal(_corners([TOP,FRONT+RIGHT]), [0,1,0,0,1,1,1,1]);
|
||||
}
|
||||
test_corners();
|
||||
test__corners();
|
||||
|
||||
|
||||
module test__is_corner_array() {
|
||||
edges = edges([TOP,FRONT+RIGHT]);
|
||||
corners = corners([TOP,FRONT+RIGHT]);
|
||||
edges = _edges([TOP,FRONT+RIGHT]);
|
||||
corners = _corners([TOP,FRONT+RIGHT]);
|
||||
assert(!_is_corner_array(undef));
|
||||
assert(!_is_corner_array(true));
|
||||
assert(!_is_corner_array(false));
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
||||
|
||||
|
|
121
vectors.scad
121
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()
|
||||
// Usage:
|
||||
// theta = v_theta([X,Y]);
|
||||
|
||||
// Section: Scalar operations on vectors
|
||||
|
||||
// Function: add_scalar()
|
||||
// Usage:
|
||||
// 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