mirror of
https://github.com/BelfrySCAD/BOSL2.git
synced 2025-01-04 03:09:45 +00:00
commit
45c6e7bbbd
16 changed files with 518 additions and 509 deletions
|
@ -117,7 +117,7 @@ module pco1810_neck(wall=2, anchor="support-ring", spin=0, orient=UP)
|
||||||
pitch=thread_pitch,
|
pitch=thread_pitch,
|
||||||
thread_depth=thread_h+0.1,
|
thread_depth=thread_h+0.1,
|
||||||
flank_angle=flank_angle,
|
flank_angle=flank_angle,
|
||||||
twist=810,
|
turns=810/360,
|
||||||
higbee=thread_h*2,
|
higbee=thread_h*2,
|
||||||
anchor=TOP
|
anchor=TOP
|
||||||
);
|
);
|
||||||
|
@ -195,7 +195,7 @@ module pco1810_cap(wall=2, texture="none", anchor=BOTTOM, spin=0, orient=UP)
|
||||||
}
|
}
|
||||||
up(wall) cyl(d=cap_id, h=tamper_ring_h+wall, anchor=BOTTOM);
|
up(wall) cyl(d=cap_id, h=tamper_ring_h+wall, anchor=BOTTOM);
|
||||||
}
|
}
|
||||||
up(wall+2) thread_helix(d=thread_od-thread_depth*2, pitch=thread_pitch, thread_depth=thread_depth, flank_angle=flank_angle, twist=810, higbee=thread_depth, internal=true, anchor=BOTTOM);
|
up(wall+2) thread_helix(d=thread_od-thread_depth*2, pitch=thread_pitch, thread_depth=thread_depth, flank_angle=flank_angle, turns=810/360, higbee=thread_depth, internal=true, anchor=BOTTOM);
|
||||||
}
|
}
|
||||||
children();
|
children();
|
||||||
}
|
}
|
||||||
|
@ -310,7 +310,7 @@ module pco1881_neck(wall=2, anchor="support-ring", spin=0, orient=UP)
|
||||||
pitch=thread_pitch,
|
pitch=thread_pitch,
|
||||||
thread_depth=thread_h+0.1,
|
thread_depth=thread_h+0.1,
|
||||||
flank_angle=flank_angle,
|
flank_angle=flank_angle,
|
||||||
twist=650,
|
turns=650/360,
|
||||||
higbee=thread_h*2,
|
higbee=thread_h*2,
|
||||||
anchor=TOP
|
anchor=TOP
|
||||||
);
|
);
|
||||||
|
@ -379,7 +379,7 @@ module pco1881_cap(wall=2, texture="none", anchor=BOTTOM, spin=0, orient=UP)
|
||||||
}
|
}
|
||||||
up(wall) cyl(d=28.58, h=11.2+wall, anchor=BOTTOM);
|
up(wall) cyl(d=28.58, h=11.2+wall, anchor=BOTTOM);
|
||||||
}
|
}
|
||||||
up(wall+2) thread_helix(d=25.5, pitch=2.7, thread_depth=1.6, flank_angle=15, twist=650, higbee=1.6, internal=true, anchor=BOTTOM);
|
up(wall+2) thread_helix(d=25.5, pitch=2.7, thread_depth=1.6, flank_angle=15, turns=650/360, higbee=1.6, internal=true, anchor=BOTTOM);
|
||||||
}
|
}
|
||||||
children();
|
children();
|
||||||
}
|
}
|
||||||
|
@ -482,7 +482,7 @@ module generic_bottle_neck(
|
||||||
pitch = thread_pitch,
|
pitch = thread_pitch,
|
||||||
thread_depth = thread_h + 0.1 * diamMagMult,
|
thread_depth = thread_h + 0.1 * diamMagMult,
|
||||||
flank_angle = flank_angle,
|
flank_angle = flank_angle,
|
||||||
twist = 360 * (height - pitch - lip_roundover_r) * .6167 / pitch,
|
turns = (height - pitch - lip_roundover_r) * .6167 / pitch,
|
||||||
higbee = thread_h * 2,
|
higbee = thread_h * 2,
|
||||||
anchor = TOP
|
anchor = TOP
|
||||||
);
|
);
|
||||||
|
@ -590,7 +590,7 @@ module generic_bottle_cap(
|
||||||
}
|
}
|
||||||
difference(){
|
difference(){
|
||||||
up(wall + pitch / 2) {
|
up(wall + pitch / 2) {
|
||||||
thread_helix(d = neckOuterDTol, pitch = pitch, thread_depth = threadDepth, flank_angle = flank_angle, twist = 360 * ((height - pitch) / pitch), higbee = threadDepth, internal = true, anchor = BOTTOM);
|
thread_helix(d = neckOuterDTol, pitch = pitch, thread_depth = threadDepth, flank_angle = flank_angle, turns = ((height - pitch) / pitch), higbee = threadDepth, internal = true, anchor = BOTTOM);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1130,7 +1130,7 @@ module sp_neck(diam,type,wall,id,style="L",bead=false, anchor, spin, orient)
|
||||||
up((H+extra_bot)/2){
|
up((H+extra_bot)/2){
|
||||||
difference(){
|
difference(){
|
||||||
union(){
|
union(){
|
||||||
thread_helix(d=T-.01, profile=profile, pitch = INCH/tpi, twist=twist+2*higang, higbee=higlen, anchor=TOP);
|
thread_helix(d=T-.01, profile=profile, pitch = INCH/tpi, turns=(twist+2*higang)/360, higbee=higlen, anchor=TOP);
|
||||||
cylinder(d=T-depth*2,l=H,anchor=TOP);
|
cylinder(d=T-depth*2,l=H,anchor=TOP);
|
||||||
if (bead)
|
if (bead)
|
||||||
down(bead_shift)
|
down(bead_shift)
|
||||||
|
|
|
@ -52,7 +52,7 @@ _UNDEF="LRG+HX7dy89RyHvDlAKvb9Y04OTuaikpx205CTh8BSI";
|
||||||
// cuboid([holesize.x + 2*s, holesize.y + 2*s, h+0.2]);
|
// cuboid([holesize.x + 2*s, holesize.y + 2*s, h+0.2]);
|
||||||
// fwd(w/2-1) xrot(90) linear_extrude(1.1) {
|
// fwd(w/2-1) xrot(90) linear_extrude(1.1) {
|
||||||
// text(
|
// text(
|
||||||
// text=fmt_fixed(s,2),
|
// text=format_fixed(s,2),
|
||||||
// size=0.4*holesize.x,
|
// size=0.4*holesize.x,
|
||||||
// halign="center",
|
// halign="center",
|
||||||
// valign="center"
|
// valign="center"
|
||||||
|
|
|
@ -2171,23 +2171,23 @@ function _are_polygons_equal(poly1, poly2, eps, st) =
|
||||||
max([for(d=poly1-select(poly2,st,st-1)) d*d])<eps*eps;
|
max([for(d=poly1-select(poly2,st,st-1)) d*d])<eps*eps;
|
||||||
|
|
||||||
|
|
||||||
// Function: is_polygon_in_list()
|
/// Function: _is_polygon_in_list()
|
||||||
// Topics: Polygons, Comparators
|
/// Topics: Polygons, Comparators
|
||||||
// See Also: are_polygons_equal(), are_regions_equal()
|
/// See Also: are_polygons_equal(), are_regions_equal()
|
||||||
// Usage:
|
/// Usage:
|
||||||
// bool = is_polygon_in_list(poly, polys);
|
/// bool = _is_polygon_in_list(poly, polys);
|
||||||
// Description:
|
/// Description:
|
||||||
// Returns true if one of the polygons in `polys` is equivalent to the polygon `poly`.
|
/// Returns true if one of the polygons in `polys` is equivalent to the polygon `poly`.
|
||||||
// Arguments:
|
/// Arguments:
|
||||||
// poly = The polygon to search for.
|
/// poly = The polygon to search for.
|
||||||
// polys = The list of polygons to look for the polygon in.
|
/// polys = The list of polygons to look for the polygon in.
|
||||||
function is_polygon_in_list(poly, polys) =
|
function _is_polygon_in_list(poly, polys) =
|
||||||
__is_polygon_in_list(poly, polys, 0);
|
___is_polygon_in_list(poly, polys, 0);
|
||||||
|
|
||||||
function __is_polygon_in_list(poly, polys, i) =
|
function ___is_polygon_in_list(poly, polys, i) =
|
||||||
i >= len(polys)? false :
|
i >= len(polys)? false :
|
||||||
are_polygons_equal(poly, polys[i])? true :
|
are_polygons_equal(poly, polys[i])? true :
|
||||||
__is_polygon_in_list(poly, polys, i+1);
|
___is_polygon_in_list(poly, polys, i+1);
|
||||||
|
|
||||||
|
|
||||||
// Section: Convex Hull
|
// Section: Convex Hull
|
||||||
|
|
|
@ -73,9 +73,9 @@ function is_matrix_symmetric(A,eps=1e-12) =
|
||||||
function echo_matrix(M,description,sig=4,eps=1e-9) =
|
function echo_matrix(M,description,sig=4,eps=1e-9) =
|
||||||
let(
|
let(
|
||||||
horiz_line = chr(8213),
|
horiz_line = chr(8213),
|
||||||
matstr = matrix_strings(M,sig=sig,eps=eps),
|
matstr = _format_matrix(M,sig=sig,eps=eps),
|
||||||
separator = str_join(repeat(horiz_line,10)),
|
separator = str_join(repeat(horiz_line,10)),
|
||||||
dummy=echo(str(separator," ",is_def(description) ? description : ""))
|
dummy=echo(str(separator,is_def(description) ? str(" ",description) : ""))
|
||||||
[for(row=matstr) echo(row)]
|
[for(row=matstr) echo(row)]
|
||||||
)
|
)
|
||||||
echo(separator);
|
echo(separator);
|
||||||
|
|
|
@ -348,99 +348,6 @@ module extrude_from_to(pt1, pt2, convexity, twist, scale, slices) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Module: spiral_sweep()
|
|
||||||
// Description:
|
|
||||||
// Takes a closed 2D polygon path, centered on the XY plane, and sweeps/extrudes it along a 3D spiral path
|
|
||||||
// of a given radius, height and twist. The origin in the profile traces out the helix of the specified radius.
|
|
||||||
// If twist is positive the path will be right-handed; if twist is negative the path will be left-handed.
|
|
||||||
// .
|
|
||||||
// Higbee specifies tapering applied to the ends of the extrusion and is given as the linear distance
|
|
||||||
// over which to taper.
|
|
||||||
// Arguments:
|
|
||||||
// poly = Array of points of a polygon path, to be extruded.
|
|
||||||
// h = height of the spiral to extrude along.
|
|
||||||
// r = Radius of the spiral to extrude along. Default: 50
|
|
||||||
// twist = number of degrees of rotation to spiral up along height.
|
|
||||||
// ---
|
|
||||||
// d = Diameter of the spiral to extrude along.
|
|
||||||
// higbee = Length to taper thread ends over.
|
|
||||||
// higbee1 = Taper length at start
|
|
||||||
// higbee2 = Taper length at end
|
|
||||||
// internal = direction to taper the threads with higbee. If true threads taper outward; if false they taper inward. Default: false
|
|
||||||
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
|
|
||||||
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
|
|
||||||
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP`
|
|
||||||
// center = If given, overrides `anchor`. A true value sets `anchor=CENTER`, false sets `anchor=BOTTOM`.
|
|
||||||
// Example:
|
|
||||||
// poly = [[-10,0], [-3,-5], [3,-5], [10,0], [0,-30]];
|
|
||||||
// spiral_sweep(poly, h=200, r=50, twist=1080, $fn=36);
|
|
||||||
module spiral_sweep(poly, h, r, twist=360, higbee, center, r1, r2, d, d1, d2, higbee1, higbee2, internal=false, anchor, spin=0, orient=UP) {
|
|
||||||
higsample = 10; // Oversample factor for higbee tapering
|
|
||||||
dummy1=assert(is_num(twist) && twist != 0);
|
|
||||||
bounds = pointlist_bounds(poly);
|
|
||||||
yctr = (bounds[0].y+bounds[1].y)/2;
|
|
||||||
xmin = bounds[0].x;
|
|
||||||
xmax = bounds[1].x;
|
|
||||||
poly = path3d(clockwise_polygon(poly));
|
|
||||||
anchor = get_anchor(anchor,center,BOT,BOT);
|
|
||||||
r1 = get_radius(r1=r1, r=r, d1=d1, d=d, dflt=50);
|
|
||||||
r2 = get_radius(r1=r2, r=r, d1=d2, d=d, dflt=50);
|
|
||||||
sides = segs(max(r1,r2));
|
|
||||||
dir = sign(twist);
|
|
||||||
ang_step = 360/sides*dir;
|
|
||||||
anglist = [for(ang = [0:ang_step:twist-EPSILON]) ang,
|
|
||||||
twist];
|
|
||||||
higbee1 = first_defined([higbee1, higbee, 0]);
|
|
||||||
higbee2 = first_defined([higbee2, higbee, 0]);
|
|
||||||
higang1 = 360 * higbee1 / (2 * r1 * PI);
|
|
||||||
higang2 = 360 * higbee2 / (2 * r2 * PI);
|
|
||||||
dummy2=assert(higbee1>=0 && higbee2>=0)
|
|
||||||
assert(higang1 < dir*twist/2,"Higbee1 is more than half the threads")
|
|
||||||
assert(higang2 < dir*twist/2,"Higbee2 is more than half the threads");
|
|
||||||
function polygon_r(N,theta) =
|
|
||||||
let( alpha = 360/N )
|
|
||||||
cos(alpha/2)/(cos(posmod(theta,alpha)-alpha/2));
|
|
||||||
higofs = pow(0.05,2); // Smallest hig scale is the square root of this value
|
|
||||||
function taperfunc(x) = sqrt((1-higofs)*x+higofs);
|
|
||||||
interp_ang = [
|
|
||||||
for(i=idx(anglist,e=-2))
|
|
||||||
each lerpn(anglist[i],anglist[i+1],
|
|
||||||
(higang1>0 && higang1>dir*anglist[i+1]
|
|
||||||
|| (higang2>0 && higang2>dir*(twist-anglist[i]))) ? ceil((anglist[i+1]-anglist[i])/ang_step*higsample)
|
|
||||||
: 1,
|
|
||||||
endpoint=false),
|
|
||||||
last(anglist)
|
|
||||||
];
|
|
||||||
skewmat = affine3d_skew_xz(xa=atan2(r2-r1,h));
|
|
||||||
points = [
|
|
||||||
for (a = interp_ang) let (
|
|
||||||
hsc = dir*a<higang1 ? taperfunc(dir*a/higang1)
|
|
||||||
: dir*(twist-a)<higang2 ? taperfunc(dir*(twist-a)/higang2)
|
|
||||||
: 1,
|
|
||||||
u = a/twist,
|
|
||||||
r = lerp(r1,r2,u),
|
|
||||||
mat = affine3d_zrot(a)
|
|
||||||
* affine3d_translate([polygon_r(sides,a)*r, 0, h * (u-0.5)])
|
|
||||||
* affine3d_xrot(90)
|
|
||||||
* skewmat
|
|
||||||
* scale([hsc,lerp(hsc,1,0.25),1], cp=[internal ? xmax : xmin, yctr, 0]),
|
|
||||||
pts = apply(mat, poly)
|
|
||||||
) pts
|
|
||||||
];
|
|
||||||
|
|
||||||
vnf = vnf_vertex_array(
|
|
||||||
points, col_wrap=true, caps=true, reverse=dir>0?true:false,
|
|
||||||
style=higbee1>0 || higbee2>0 ? "quincunx" : "alt"
|
|
||||||
);
|
|
||||||
|
|
||||||
attachable(anchor,spin,orient, r1=r1, r2=r2, l=h) {
|
|
||||||
vnf_polyhedron(vnf, convexity=ceil(2*dir*twist/360));
|
|
||||||
children();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Module: path_extrude()
|
// Module: path_extrude()
|
||||||
// Description:
|
// Description:
|
||||||
// Extrudes 2D children along a 3D path. This may be slow.
|
// Extrudes 2D children along a 3D path. This may be slow.
|
||||||
|
|
122
regions.scad
122
regions.scad
|
@ -398,7 +398,7 @@ function are_regions_equal(region1, region2, either_winding=false) =
|
||||||
|
|
||||||
function __are_regions_equal(region1, region2, i) =
|
function __are_regions_equal(region1, region2, i) =
|
||||||
i >= len(region1)? true :
|
i >= len(region1)? true :
|
||||||
!is_polygon_in_list(region1[i], region2)? false :
|
!_is_polygon_in_list(region1[i], region2)? false :
|
||||||
__are_regions_equal(region1, region2, i+1);
|
__are_regions_equal(region1, region2, i+1);
|
||||||
|
|
||||||
|
|
||||||
|
@ -591,126 +591,6 @@ function region_parts(region) =
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
// Section: Region Extrusion and VNFs
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Function&Module: linear_sweep()
|
|
||||||
// Usage:
|
|
||||||
// linear_sweep(region, height, [center], [slices], [twist], [scale], [style], [convexity]) {attachments};
|
|
||||||
// Description:
|
|
||||||
// If called as a module, creates a polyhedron that is the linear extrusion of the given 2D region or polygon.
|
|
||||||
// If called as a function, returns a VNF that can be used to generate a polyhedron of the linear extrusion
|
|
||||||
// of the given 2D region or polygon. The benefit of using this, over using `linear_extrude region(rgn)` is
|
|
||||||
// that it supports `anchor`, `spin`, `orient` and attachments. You can also make more refined
|
|
||||||
// twisted extrusions by using `maxseg` to subsample flat faces.
|
|
||||||
// Note that the center option centers vertically using the named anchor "zcenter" whereas
|
|
||||||
// `anchor=CENTER` centers the entire shape relative to
|
|
||||||
// the shape's centroid, or other centerpoint you specify. The centerpoint can be "centroid", "mean", "box" or
|
|
||||||
// a custom point location.
|
|
||||||
// Arguments:
|
|
||||||
// region = The 2D [Region](regions.scad) or polygon that is to be extruded.
|
|
||||||
// height = The height to extrude the region. Default: 1
|
|
||||||
// center = If true, the created polyhedron will be vertically centered. If false, it will be extruded upwards from the XY plane. Default: `false`
|
|
||||||
// slices = The number of slices to divide the shape into along the Z axis, to allow refinement of detail, especially when working with a twist. Default: `twist/5`
|
|
||||||
// maxseg = If given, then any long segments of the region will be subdivided to be shorter than this length. This can refine twisting flat faces a lot. Default: `undef` (no subsampling)
|
|
||||||
// twist = The number of degrees to rotate the shape clockwise around the Z axis, as it rises from bottom to top. Default: 0
|
|
||||||
// scale = The amount to scale the shape, from bottom to top. Default: 1
|
|
||||||
// style = The style to use when triangulating the surface of the object. Valid values are `"default"`, `"alt"`, or `"quincunx"`.
|
|
||||||
// convexity = Max number of surfaces any single ray could pass through. Module use only.
|
|
||||||
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `"origin"`
|
|
||||||
// atype = Set to "hull" or "intersect" to select anchor type. Default: "hull"
|
|
||||||
// cp = Centerpoint for determining intersection anchors or centering the shape. Determintes the base of the anchor vector. Can be "centroid", "mean", "box" or a 3D point. Default: "centroid"
|
|
||||||
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
|
|
||||||
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP`
|
|
||||||
// Example: Extruding a Compound Region.
|
|
||||||
// rgn1 = [for (d=[10:10:60]) circle(d=d,$fn=8)];
|
|
||||||
// rgn2 = [square(30,center=false)];
|
|
||||||
// rgn3 = [for (size=[10:10:20]) move([15,15],p=square(size=size, center=true))];
|
|
||||||
// mrgn = union(rgn1,rgn2);
|
|
||||||
// orgn = difference(mrgn,rgn3);
|
|
||||||
// linear_sweep(orgn,height=20,convexity=16);
|
|
||||||
// Example: With Twist, Scale, Slices and Maxseg.
|
|
||||||
// rgn1 = [for (d=[10:10:60]) circle(d=d,$fn=8)];
|
|
||||||
// rgn2 = [square(30,center=false)];
|
|
||||||
// rgn3 = [for (size=[10:10:20]) move([15,15],p=square(size=size, center=true))];
|
|
||||||
// mrgn = union(rgn1,rgn2);
|
|
||||||
// orgn = difference(mrgn,rgn3);
|
|
||||||
// linear_sweep(orgn,height=50,maxseg=2,slices=40,twist=180,scale=0.5,convexity=16);
|
|
||||||
// Example: Anchors on an Extruded Region
|
|
||||||
// rgn1 = [for (d=[10:10:60]) circle(d=d,$fn=8)];
|
|
||||||
// rgn2 = [square(30,center=false)];
|
|
||||||
// rgn3 = [for (size=[10:10:20]) move([15,15],p=square(size=size, center=true))];
|
|
||||||
// mrgn = union(rgn1,rgn2);
|
|
||||||
// orgn = difference(mrgn,rgn3);
|
|
||||||
// linear_sweep(orgn,height=20,convexity=16) show_anchors();
|
|
||||||
module linear_sweep(region, height=1, center, twist=0, scale=1, slices, maxseg, style="default", convexity,
|
|
||||||
spin=0, orient=UP, cp="centroid", anchor="origin", atype="hull") {
|
|
||||||
region = force_region(region);
|
|
||||||
dummy=assert(is_region(region),"Input is not a region");
|
|
||||||
anchor = center ? "zcenter" : anchor;
|
|
||||||
anchors = [named_anchor("zcenter", [0,0,height/2], UP)];
|
|
||||||
vnf = linear_sweep(
|
|
||||||
region, height=height,
|
|
||||||
twist=twist, scale=scale,
|
|
||||||
slices=slices, maxseg=maxseg,
|
|
||||||
style=style
|
|
||||||
);
|
|
||||||
attachable(anchor,spin,orient, cp=cp, region=region, h=height, extent=atype=="hull", anchors=anchors) {
|
|
||||||
vnf_polyhedron(vnf, convexity=convexity);
|
|
||||||
children();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function linear_sweep(region, height=1, center, twist=0, scale=1, slices,
|
|
||||||
maxseg, style="default", cp="centroid", atype="hull", anchor, spin=0, orient=UP) =
|
|
||||||
let(
|
|
||||||
region = force_region(region)
|
|
||||||
)
|
|
||||||
assert(is_region(region), "Input is not a region")
|
|
||||||
let(
|
|
||||||
anchor = center ? "zcenter" : anchor,
|
|
||||||
anchors = [named_anchor("zcenter", [0,0,height/2], UP)],
|
|
||||||
regions = region_parts(region),
|
|
||||||
slices = default(slices, floor(twist/5+1)),
|
|
||||||
step = twist/slices,
|
|
||||||
hstep = height/slices,
|
|
||||||
trgns = [
|
|
||||||
for (rgn=regions) [
|
|
||||||
for (path=rgn) let(
|
|
||||||
p = cleanup_path(path),
|
|
||||||
path = is_undef(maxseg)? p : [
|
|
||||||
for (seg=pair(p,true)) each
|
|
||||||
let(steps=ceil(norm(seg.y-seg.x)/maxseg))
|
|
||||||
lerpn(seg.x, seg.y, steps, false)
|
|
||||||
]
|
|
||||||
)
|
|
||||||
rot(twist, p=scale([scale,scale],p=path))
|
|
||||||
]
|
|
||||||
],
|
|
||||||
vnf = vnf_join([
|
|
||||||
for (rgn = regions)
|
|
||||||
for (pathnum = idx(rgn)) let(
|
|
||||||
p = cleanup_path(rgn[pathnum]),
|
|
||||||
path = is_undef(maxseg)? p : [
|
|
||||||
for (seg=pair(p,true)) each
|
|
||||||
let(steps=ceil(norm(seg.y-seg.x)/maxseg))
|
|
||||||
lerpn(seg.x, seg.y, steps, false)
|
|
||||||
],
|
|
||||||
verts = [
|
|
||||||
for (i=[0:1:slices]) let(
|
|
||||||
sc = lerp(1, scale, i/slices),
|
|
||||||
ang = i * step,
|
|
||||||
h = i * hstep //- height/2
|
|
||||||
) scale([sc,sc,1], p=rot(ang, p=path3d(path,h)))
|
|
||||||
]
|
|
||||||
) vnf_vertex_array(verts, caps=false, col_wrap=true, style=style),
|
|
||||||
for (rgn = regions) vnf_from_region(rgn, ident(4), reverse=true),
|
|
||||||
for (rgn = trgns) vnf_from_region(rgn, up(height), reverse=false)
|
|
||||||
])
|
|
||||||
) reorient(anchor,spin,orient, cp=cp, vnf=vnf, extent=atype=="hull", p=vnf, anchors=anchors);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Section: Offset and 2D Boolean Set Operations
|
// Section: Offset and 2D Boolean Set Operations
|
||||||
|
|
20
screws.scad
20
screws.scad
|
@ -30,16 +30,16 @@ Torx values: https://www.stanleyengineeredfastening.com/-/media/web/sef/resourc
|
||||||
|
|
||||||
function _parse_screw_name(name) =
|
function _parse_screw_name(name) =
|
||||||
let( commasplit = str_split(name,","),
|
let( commasplit = str_split(name,","),
|
||||||
length = str_num(commasplit[1]),
|
length = parse_num(commasplit[1]),
|
||||||
xdash = str_split(commasplit[0], "-x"),
|
xdash = str_split(commasplit[0], "-x"),
|
||||||
type = xdash[0],
|
type = xdash[0],
|
||||||
thread = str_float(xdash[1])
|
thread = parse_float(xdash[1])
|
||||||
)
|
)
|
||||||
type[0] == "M" || type[0] == "m" ? ["metric", str_float(substr(type,1)), thread, length] :
|
type[0] == "M" || type[0] == "m" ? ["metric", parse_float(substr(type,1)), thread, length] :
|
||||||
let(
|
let(
|
||||||
diam = type[0] == "#" ? type :
|
diam = type[0] == "#" ? type :
|
||||||
suffix(type,2)=="''" ? str_float(substr(type,0,len(type)-2)) :
|
suffix(type,2)=="''" ? parse_float(substr(type,0,len(type)-2)) :
|
||||||
let(val=str_num(type))
|
let(val=parse_num(type))
|
||||||
val == floor(val) && val>=0 && val<=12 ? str("#",type) : val
|
val == floor(val) && val>=0 && val<=12 ? str("#",type) : val
|
||||||
)
|
)
|
||||||
["english", diam, thread, u_mul(25.4,length)];
|
["english", diam, thread, u_mul(25.4,length)];
|
||||||
|
@ -51,8 +51,8 @@ function _parse_drive(drive=undef, drive_size=undef) =
|
||||||
is_undef(drive) ? ["none",undef] :
|
is_undef(drive) ? ["none",undef] :
|
||||||
let(drive = downcase(drive))
|
let(drive = downcase(drive))
|
||||||
in_list(drive,["hex","phillips", "slot", "torx", "phillips", "none"]) ? [drive, drive_size] :
|
in_list(drive,["hex","phillips", "slot", "torx", "phillips", "none"]) ? [drive, drive_size] :
|
||||||
drive[0]=="t" ? ["torx", str_int(substr(drive,1))] :
|
drive[0]=="t" ? ["torx", parse_int(substr(drive,1))] :
|
||||||
substr(drive,0,2)=="ph" ? ["phillips", str_int(substr(drive,2))] :
|
substr(drive,0,2)=="ph" ? ["phillips", parse_int(substr(drive,2))] :
|
||||||
assert(str("Unknown screw drive type ",drive));
|
assert(str("Unknown screw drive type ",drive));
|
||||||
|
|
||||||
|
|
||||||
|
@ -178,7 +178,7 @@ function screw_info(name, head, thread="coarse", drive, drive_size=undef, oversi
|
||||||
|
|
||||||
function _screw_info_english(diam, threadcount, head, thread, drive) =
|
function _screw_info_english(diam, threadcount, head, thread, drive) =
|
||||||
let(
|
let(
|
||||||
diameter = is_string(diam) ? str_int(substr(diam,1))*0.013 +0.06 :
|
diameter = is_string(diam) ? parse_int(substr(diam,1))*0.013 +0.06 :
|
||||||
diam,
|
diam,
|
||||||
pitch =
|
pitch =
|
||||||
is_def(threadcount) ? INCH/threadcount :
|
is_def(threadcount) ? INCH/threadcount :
|
||||||
|
@ -1121,8 +1121,8 @@ function _ISO_thread_tolerance(diameter, pitch, internal=false, tolerance=undef)
|
||||||
assert(internalok,str("Invalid internal thread tolerance, ",tolerance,". Must have form <digit><letter>"))
|
assert(internalok,str("Invalid internal thread tolerance, ",tolerance,". Must have form <digit><letter>"))
|
||||||
assert(externalok,str("invalid external thread tolerance, ",tolerance,". Must have form <digit><letter> or <digit><letter><digit><letter>"))
|
assert(externalok,str("invalid external thread tolerance, ",tolerance,". Must have form <digit><letter> or <digit><letter><digit><letter>"))
|
||||||
let(
|
let(
|
||||||
tol_num_pitch = str_num(tol_str[0]),
|
tol_num_pitch = parse_num(tol_str[0]),
|
||||||
tol_num_crest = str_num(tol_str[2]),
|
tol_num_crest = parse_num(tol_str[2]),
|
||||||
tol_letter = tol_str[1]
|
tol_letter = tol_str[1]
|
||||||
)
|
)
|
||||||
assert(tol_letter==tol_str[3],str("Invalid tolerance, ",tolerance,". Cannot mix different letters"))
|
assert(tol_letter==tol_str[3],str("Invalid tolerance, ",tolerance,". Cannot mix different letters"))
|
||||||
|
|
|
@ -2083,7 +2083,7 @@ module atext(text, h=1, size=9, font="Courier", anchor="baseline", spin=0, orien
|
||||||
anch = !any([for (c=anchor) c=="["])? anchor :
|
anch = !any([for (c=anchor) c=="["])? anchor :
|
||||||
let(
|
let(
|
||||||
parts = str_split(str_split(str_split(anchor,"]")[0],"[")[1],","),
|
parts = str_split(str_split(str_split(anchor,"]")[0],"[")[1],","),
|
||||||
vec = [for (p=parts) str_float(str_strip(p," ",start=true))]
|
vec = [for (p=parts) parse_float(str_strip(p," ",start=true))]
|
||||||
) vec;
|
) vec;
|
||||||
ha = anchor=="baseline"? "left" :
|
ha = anchor=="baseline"? "left" :
|
||||||
anchor==anch && is_string(anchor)? "center" :
|
anchor==anch && is_string(anchor)? "center" :
|
||||||
|
|
227
skin.scad
227
skin.scad
|
@ -501,6 +501,233 @@ function skin(profiles, slices, refine=1, method="direct", sampling, caps, close
|
||||||
reorient(anchor,spin,orient,vnf=vnf,p=vnf,extent=atype=="hull",cp=cp);
|
reorient(anchor,spin,orient,vnf=vnf,p=vnf,extent=atype=="hull",cp=cp);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Function&Module: linear_sweep()
|
||||||
|
// Usage:
|
||||||
|
// linear_sweep(region, height, [center], [slices], [twist], [scale], [style], [convexity]) {attachments};
|
||||||
|
// Description:
|
||||||
|
// If called as a module, creates a polyhedron that is the linear extrusion of the given 2D region or polygon.
|
||||||
|
// If called as a function, returns a VNF that can be used to generate a polyhedron of the linear extrusion
|
||||||
|
// of the given 2D region or polygon. The benefit of using this, over using `linear_extrude region(rgn)` is
|
||||||
|
// that it supports `anchor`, `spin`, `orient` and attachments. You can also make more refined
|
||||||
|
// twisted extrusions by using `maxseg` to subsample flat faces.
|
||||||
|
// Note that the center option centers vertically using the named anchor "zcenter" whereas
|
||||||
|
// `anchor=CENTER` centers the entire shape relative to
|
||||||
|
// the shape's centroid, or other centerpoint you specify. The centerpoint can be "centroid", "mean", "box" or
|
||||||
|
// a custom point location.
|
||||||
|
// Arguments:
|
||||||
|
// region = The 2D [Region](regions.scad) or polygon that is to be extruded.
|
||||||
|
// height = The height to extrude the region. Default: 1
|
||||||
|
// center = If true, the created polyhedron will be vertically centered. If false, it will be extruded upwards from the XY plane. Default: `false`
|
||||||
|
// slices = The number of slices to divide the shape into along the Z axis, to allow refinement of detail, especially when working with a twist. Default: `twist/5`
|
||||||
|
// maxseg = If given, then any long segments of the region will be subdivided to be shorter than this length. This can refine twisting flat faces a lot. Default: `undef` (no subsampling)
|
||||||
|
// twist = The number of degrees to rotate the shape clockwise around the Z axis, as it rises from bottom to top. Default: 0
|
||||||
|
// scale = The amount to scale the shape, from bottom to top. Default: 1
|
||||||
|
// style = The style to use when triangulating the surface of the object. Valid values are `"default"`, `"alt"`, or `"quincunx"`.
|
||||||
|
// convexity = Max number of surfaces any single ray could pass through. Module use only.
|
||||||
|
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `"origin"`
|
||||||
|
// atype = Set to "hull" or "intersect" to select anchor type. Default: "hull"
|
||||||
|
// cp = Centerpoint for determining intersection anchors or centering the shape. Determintes the base of the anchor vector. Can be "centroid", "mean", "box" or a 3D point. Default: "centroid"
|
||||||
|
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
|
||||||
|
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP`
|
||||||
|
// Example: Extruding a Compound Region.
|
||||||
|
// rgn1 = [for (d=[10:10:60]) circle(d=d,$fn=8)];
|
||||||
|
// rgn2 = [square(30,center=false)];
|
||||||
|
// rgn3 = [for (size=[10:10:20]) move([15,15],p=square(size=size, center=true))];
|
||||||
|
// mrgn = union(rgn1,rgn2);
|
||||||
|
// orgn = difference(mrgn,rgn3);
|
||||||
|
// linear_sweep(orgn,height=20,convexity=16);
|
||||||
|
// Example: With Twist, Scale, Slices and Maxseg.
|
||||||
|
// rgn1 = [for (d=[10:10:60]) circle(d=d,$fn=8)];
|
||||||
|
// rgn2 = [square(30,center=false)];
|
||||||
|
// rgn3 = [for (size=[10:10:20]) move([15,15],p=square(size=size, center=true))];
|
||||||
|
// mrgn = union(rgn1,rgn2);
|
||||||
|
// orgn = difference(mrgn,rgn3);
|
||||||
|
// linear_sweep(orgn,height=50,maxseg=2,slices=40,twist=180,scale=0.5,convexity=16);
|
||||||
|
// Example: Anchors on an Extruded Region
|
||||||
|
// rgn1 = [for (d=[10:10:60]) circle(d=d,$fn=8)];
|
||||||
|
// rgn2 = [square(30,center=false)];
|
||||||
|
// rgn3 = [for (size=[10:10:20]) move([15,15],p=square(size=size, center=true))];
|
||||||
|
// mrgn = union(rgn1,rgn2);
|
||||||
|
// orgn = difference(mrgn,rgn3);
|
||||||
|
// linear_sweep(orgn,height=20,convexity=16) show_anchors();
|
||||||
|
module linear_sweep(region, height=1, center, twist=0, scale=1, slices, maxseg, style="default", convexity,
|
||||||
|
spin=0, orient=UP, cp="centroid", anchor="origin", atype="hull") {
|
||||||
|
region = force_region(region);
|
||||||
|
dummy=assert(is_region(region),"Input is not a region");
|
||||||
|
anchor = center ? "zcenter" : anchor;
|
||||||
|
anchors = [named_anchor("zcenter", [0,0,height/2], UP)];
|
||||||
|
vnf = linear_sweep(
|
||||||
|
region, height=height,
|
||||||
|
twist=twist, scale=scale,
|
||||||
|
slices=slices, maxseg=maxseg,
|
||||||
|
style=style
|
||||||
|
);
|
||||||
|
attachable(anchor,spin,orient, cp=cp, region=region, h=height, extent=atype=="hull", anchors=anchors) {
|
||||||
|
vnf_polyhedron(vnf, convexity=convexity);
|
||||||
|
children();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function linear_sweep(region, height=1, center, twist=0, scale=1, slices,
|
||||||
|
maxseg, style="default", cp="centroid", atype="hull", anchor, spin=0, orient=UP) =
|
||||||
|
let(
|
||||||
|
region = force_region(region)
|
||||||
|
)
|
||||||
|
assert(is_region(region), "Input is not a region")
|
||||||
|
let(
|
||||||
|
anchor = center ? "zcenter" : anchor,
|
||||||
|
anchors = [named_anchor("zcenter", [0,0,height/2], UP)],
|
||||||
|
regions = region_parts(region),
|
||||||
|
slices = default(slices, floor(twist/5+1)),
|
||||||
|
step = twist/slices,
|
||||||
|
hstep = height/slices,
|
||||||
|
trgns = [
|
||||||
|
for (rgn=regions) [
|
||||||
|
for (path=rgn) let(
|
||||||
|
p = cleanup_path(path),
|
||||||
|
path = is_undef(maxseg)? p : [
|
||||||
|
for (seg=pair(p,true)) each
|
||||||
|
let(steps=ceil(norm(seg.y-seg.x)/maxseg))
|
||||||
|
lerpn(seg.x, seg.y, steps, false)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
rot(twist, p=scale([scale,scale],p=path))
|
||||||
|
]
|
||||||
|
],
|
||||||
|
vnf = vnf_join([
|
||||||
|
for (rgn = regions)
|
||||||
|
for (pathnum = idx(rgn)) let(
|
||||||
|
p = cleanup_path(rgn[pathnum]),
|
||||||
|
path = is_undef(maxseg)? p : [
|
||||||
|
for (seg=pair(p,true)) each
|
||||||
|
let(steps=ceil(norm(seg.y-seg.x)/maxseg))
|
||||||
|
lerpn(seg.x, seg.y, steps, false)
|
||||||
|
],
|
||||||
|
verts = [
|
||||||
|
for (i=[0:1:slices]) let(
|
||||||
|
sc = lerp(1, scale, i/slices),
|
||||||
|
ang = i * step,
|
||||||
|
h = i * hstep //- height/2
|
||||||
|
) scale([sc,sc,1], p=rot(ang, p=path3d(path,h)))
|
||||||
|
]
|
||||||
|
) vnf_vertex_array(verts, caps=false, col_wrap=true, style=style),
|
||||||
|
for (rgn = regions) vnf_from_region(rgn, ident(4), reverse=true),
|
||||||
|
for (rgn = trgns) vnf_from_region(rgn, up(height), reverse=false)
|
||||||
|
])
|
||||||
|
) reorient(anchor,spin,orient, cp=cp, vnf=vnf, extent=atype=="hull", p=vnf, anchors=anchors);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Function&Module: spiral_sweep()
|
||||||
|
// Usage:
|
||||||
|
// spiral_sweep(poly, h, r, turns, [higbee], [center], [r1], [r2], [d], [d1], [d2], [higbee1], [higbee2], [internal], [anchor], [spin], [orient]);
|
||||||
|
// vnf = spiral_sweep(poly, h, r, turns, ...);
|
||||||
|
// Description:
|
||||||
|
// Takes a closed 2D polygon path, centered on the XY plane, and sweeps/extrudes it along a 3D spiral path
|
||||||
|
// of a given radius, height and degrees of rotation. The origin in the profile traces out the helix of the specified radius.
|
||||||
|
// If turns is positive the path will be right-handed; if turns is negative the path will be left-handed.
|
||||||
|
// .
|
||||||
|
// Higbee specifies tapering applied to the ends of the extrusion and is given as the linear distance
|
||||||
|
// over which to taper.
|
||||||
|
// Arguments:
|
||||||
|
// poly = Array of points of a polygon path, to be extruded.
|
||||||
|
// h = height of the spiral to extrude along.
|
||||||
|
// r = Radius of the spiral to extrude along. Default: 50
|
||||||
|
// turns = number of revolutions to spiral up along the height.
|
||||||
|
// ---
|
||||||
|
// d = Diameter of the spiral to extrude along.
|
||||||
|
// higbee = Length to taper thread ends over.
|
||||||
|
// higbee1 = Taper length at start
|
||||||
|
// higbee2 = Taper length at end
|
||||||
|
// internal = direction to taper the threads with higbee. If true threads taper outward; if false they taper inward. Default: false
|
||||||
|
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: `CENTER`
|
||||||
|
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). Default: `0`
|
||||||
|
// orient = Vector to rotate top towards, after spin. See [orient](attachments.scad#subsection-orient). Default: `UP`
|
||||||
|
// center = If given, overrides `anchor`. A true value sets `anchor=CENTER`, false sets `anchor=BOTTOM`.
|
||||||
|
// Example:
|
||||||
|
// poly = [[-10,0], [-3,-5], [3,-5], [10,0], [0,-30]];
|
||||||
|
// spiral_sweep(poly, h=200, r=50, turns=3, $fn=36);
|
||||||
|
function _taperfunc(x) =
|
||||||
|
let(higofs = pow(0.05,2)) // Smallest hig scale is the square root of this value
|
||||||
|
sqrt((1-higofs)*x+higofs);
|
||||||
|
function _ss_polygon_r(N,theta) =
|
||||||
|
let( alpha = 360/N )
|
||||||
|
cos(alpha/2)/(cos(posmod(theta,alpha)-alpha/2));
|
||||||
|
function spiral_sweep(poly, h, r, turns=1, higbee, center, r1, r2, d, d1, d2, higbee1, higbee2, internal=false, anchor=CENTER, spin=0, orient=UP) =
|
||||||
|
assert(is_num(turns) && turns != 0)
|
||||||
|
let(
|
||||||
|
twist = 360*turns,
|
||||||
|
higsample = 10, // Oversample factor for higbee tapering
|
||||||
|
bounds = pointlist_bounds(poly),
|
||||||
|
yctr = (bounds[0].y+bounds[1].y)/2,
|
||||||
|
xmin = bounds[0].x,
|
||||||
|
xmax = bounds[1].x,
|
||||||
|
poly = path3d(clockwise_polygon(poly)),
|
||||||
|
anchor = get_anchor(anchor,center,BOT,BOT),
|
||||||
|
r1 = get_radius(r1=r1, r=r, d1=d1, d=d, dflt=50),
|
||||||
|
r2 = get_radius(r1=r2, r=r, d1=d2, d=d, dflt=50),
|
||||||
|
sides = segs(max(r1,r2)),
|
||||||
|
dir = sign(twist),
|
||||||
|
ang_step = 360/sides*dir,
|
||||||
|
anglist = [for(ang = [0:ang_step:twist-EPSILON]) ang,
|
||||||
|
twist],
|
||||||
|
higbee1 = first_defined([higbee1, higbee, 0]),
|
||||||
|
higbee2 = first_defined([higbee2, higbee, 0]),
|
||||||
|
higang1 = 360 * higbee1 / (2 * r1 * PI),
|
||||||
|
higang2 = 360 * higbee2 / (2 * r2 * PI)
|
||||||
|
)
|
||||||
|
assert(higbee1>=0 && higbee2>=0)
|
||||||
|
assert(higang1 < dir*twist/2,"Higbee1 is more than half the threads")
|
||||||
|
assert(higang2 < dir*twist/2,"Higbee2 is more than half the threads")
|
||||||
|
let(
|
||||||
|
interp_ang = [
|
||||||
|
for(i=idx(anglist,e=-2))
|
||||||
|
each lerpn(anglist[i],anglist[i+1],
|
||||||
|
(higang1>0 && higang1>dir*anglist[i+1]
|
||||||
|
|| (higang2>0 && higang2>dir*(twist-anglist[i]))) ? ceil((anglist[i+1]-anglist[i])/ang_step*higsample)
|
||||||
|
: 1,
|
||||||
|
endpoint=false),
|
||||||
|
last(anglist)
|
||||||
|
],
|
||||||
|
skewmat = affine3d_skew_xz(xa=atan2(r2-r1,h)),
|
||||||
|
points = [
|
||||||
|
for (a = interp_ang) let (
|
||||||
|
hsc = dir*a<higang1 ? _taperfunc(dir*a/higang1)
|
||||||
|
: dir*(twist-a)<higang2 ? _taperfunc(dir*(twist-a)/higang2)
|
||||||
|
: 1,
|
||||||
|
u = a/twist,
|
||||||
|
r = lerp(r1,r2,u),
|
||||||
|
mat = affine3d_zrot(a)
|
||||||
|
* affine3d_translate([_ss_polygon_r(sides,a)*r, 0, h * (u-0.5)])
|
||||||
|
* affine3d_xrot(90)
|
||||||
|
* skewmat
|
||||||
|
* scale([hsc,lerp(hsc,1,0.25),1], cp=[internal ? xmax : xmin, yctr, 0]),
|
||||||
|
pts = apply(mat, poly)
|
||||||
|
) pts
|
||||||
|
],
|
||||||
|
vnf = vnf_vertex_array(
|
||||||
|
points, col_wrap=true, caps=true, reverse=dir>0?true:false,
|
||||||
|
style=higbee1>0 || higbee2>0 ? "quincunx" : "alt"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
reorient(anchor,spin,orient, vnf=vnf, r1=r1, r2=r2, l=h, p=vnf);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
module spiral_sweep(poly, h, r, turns=1, higbee, center, r1, r2, d, d1, d2, higbee1, higbee2, internal=false, anchor=CENTER, spin=0, orient=UP) {
|
||||||
|
vnf = spiral_sweep(poly, h, r, turns, higbee, center, r1, r2, d, d1, d2, higbee1, higbee2, internal);
|
||||||
|
r1 = get_radius(r1=r1, r=r, d1=d1, d=d, dflt=50);
|
||||||
|
r2 = get_radius(r1=r2, r=r, d1=d2, d=d, dflt=50);
|
||||||
|
attachable(anchor,spin,orient, r1=r1, r2=r2, l=h) {
|
||||||
|
vnf_polyhedron(vnf, convexity=ceil(abs(2*turns)));
|
||||||
|
children();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Function&Module: path_sweep()
|
// Function&Module: path_sweep()
|
||||||
// Usage: As module
|
// Usage: As module
|
||||||
// path_sweep(shape, path, [method], [normal=], [closed=], [twist=], [twist_by_length=], [symmetry=], [last_normal=], [tangent=], [relaxed=], [caps=], [style=], [convexity=], [anchor=], [cp=], [spin=], [orient=], [atype=]) {attachments};
|
// path_sweep(shape, path, [method], [normal=], [closed=], [twist=], [twist_by_length=], [symmetry=], [last_normal=], [tangent=], [relaxed=], [caps=], [style=], [convexity=], [anchor=], [cp=], [spin=], [orient=], [atype=]) {attachments};
|
||||||
|
|
255
strings.scad
255
strings.scad
|
@ -334,11 +334,11 @@ function upcase(str) =
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Section: Converting strings to numbers
|
// Section: Parsing strings into numbers
|
||||||
|
|
||||||
// Function: str_int()
|
// Function: parse_int()
|
||||||
// Usage:
|
// Usage:
|
||||||
// str_int(str, [base])
|
// parse_int(str, [base])
|
||||||
// Description:
|
// Description:
|
||||||
// Converts a string into an integer with any base up to 16. Returns NaN if
|
// Converts a string into an integer with any base up to 16. Returns NaN if
|
||||||
// conversion fails. Digits above 9 are represented using letters A-F in either
|
// conversion fails. Digits above 9 are represented using letters A-F in either
|
||||||
|
@ -347,62 +347,62 @@ function upcase(str) =
|
||||||
// str = String to convert.
|
// str = String to convert.
|
||||||
// base = Base for conversion, from 2-16. Default: 10
|
// base = Base for conversion, from 2-16. Default: 10
|
||||||
// Example:
|
// Example:
|
||||||
// str_int("349"); // Returns 349
|
// parse_int("349"); // Returns 349
|
||||||
// str_int("-37"); // Returns -37
|
// parse_int("-37"); // Returns -37
|
||||||
// str_int("+97"); // Returns 97
|
// parse_int("+97"); // Returns 97
|
||||||
// str_int("43.9"); // Returns nan
|
// parse_int("43.9"); // Returns nan
|
||||||
// str_int("1011010",2); // Returns 90
|
// parse_int("1011010",2); // Returns 90
|
||||||
// str_int("13",2); // Returns nan
|
// parse_int("13",2); // Returns nan
|
||||||
// str_int("dead",16); // Returns 57005
|
// parse_int("dead",16); // Returns 57005
|
||||||
// str_int("CEDE", 16); // Returns 52958
|
// parse_int("CEDE", 16); // Returns 52958
|
||||||
// str_int(""); // Returns 0
|
// parse_int(""); // Returns 0
|
||||||
function str_int(str,base=10) =
|
function parse_int(str,base=10) =
|
||||||
str==undef ? undef :
|
str==undef ? undef :
|
||||||
len(str)==0 ? 0 :
|
len(str)==0 ? 0 :
|
||||||
let(str=downcase(str))
|
let(str=downcase(str))
|
||||||
str[0] == "-" ? -_str_int_recurse(substr(str,1),base,len(str)-2) :
|
str[0] == "-" ? -_parse_int_recurse(substr(str,1),base,len(str)-2) :
|
||||||
str[0] == "+" ? _str_int_recurse(substr(str,1),base,len(str)-2) :
|
str[0] == "+" ? _parse_int_recurse(substr(str,1),base,len(str)-2) :
|
||||||
_str_int_recurse(str,base,len(str)-1);
|
_parse_int_recurse(str,base,len(str)-1);
|
||||||
|
|
||||||
function _str_int_recurse(str,base,i) =
|
function _parse_int_recurse(str,base,i) =
|
||||||
let(
|
let(
|
||||||
digit = search(str[i],"0123456789abcdef"),
|
digit = search(str[i],"0123456789abcdef"),
|
||||||
last_digit = digit == [] || digit[0] >= base ? (0/0) : digit[0]
|
last_digit = digit == [] || digit[0] >= base ? (0/0) : digit[0]
|
||||||
) i==0 ? last_digit :
|
) i==0 ? last_digit :
|
||||||
_str_int_recurse(str,base,i-1)*base + last_digit;
|
_parse_int_recurse(str,base,i-1)*base + last_digit;
|
||||||
|
|
||||||
|
|
||||||
// Function: str_float()
|
// Function: parse_float()
|
||||||
// Usage:
|
// Usage:
|
||||||
// str_float(str)
|
// parse_float(str)
|
||||||
// Description:
|
// Description:
|
||||||
// Converts a string to a floating point number. Returns NaN if the
|
// Converts a string to a floating point number. Returns NaN if the
|
||||||
// conversion fails.
|
// conversion fails.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// str = String to convert.
|
// str = String to convert.
|
||||||
// Example:
|
// Example:
|
||||||
// str_float("44"); // Returns 44
|
// parse_float("44"); // Returns 44
|
||||||
// str_float("3.4"); // Returns 3.4
|
// parse_float("3.4"); // Returns 3.4
|
||||||
// str_float("-99.3332"); // Returns -99.3332
|
// parse_float("-99.3332"); // Returns -99.3332
|
||||||
// str_float("3.483e2"); // Returns 348.3
|
// parse_float("3.483e2"); // Returns 348.3
|
||||||
// str_float("-44.9E2"); // Returns -4490
|
// parse_float("-44.9E2"); // Returns -4490
|
||||||
// str_float("7.342e-4"); // Returns 0.0007342
|
// parse_float("7.342e-4"); // Returns 0.0007342
|
||||||
// str_float(""); // Returns 0
|
// parse_float(""); // Returns 0
|
||||||
function str_float(str) =
|
function parse_float(str) =
|
||||||
str==undef ? undef :
|
str==undef ? undef :
|
||||||
len(str) == 0 ? 0 :
|
len(str) == 0 ? 0 :
|
||||||
in_list(str[1], ["+","-"]) ? (0/0) : // Don't allow --3, or +-3
|
in_list(str[1], ["+","-"]) ? (0/0) : // Don't allow --3, or +-3
|
||||||
str[0]=="-" ? -str_float(substr(str,1)) :
|
str[0]=="-" ? -parse_float(substr(str,1)) :
|
||||||
str[0]=="+" ? str_float(substr(str,1)) :
|
str[0]=="+" ? parse_float(substr(str,1)) :
|
||||||
let(esplit = str_split(str,"eE") )
|
let(esplit = str_split(str,"eE") )
|
||||||
len(esplit)==2 ? str_float(esplit[0]) * pow(10,str_int(esplit[1])) :
|
len(esplit)==2 ? parse_float(esplit[0]) * pow(10,parse_int(esplit[1])) :
|
||||||
let( dsplit = str_split(str,["."]))
|
let( dsplit = str_split(str,["."]))
|
||||||
str_int(dsplit[0])+str_int(dsplit[1])/pow(10,len(dsplit[1]));
|
parse_int(dsplit[0])+parse_int(dsplit[1])/pow(10,len(dsplit[1]));
|
||||||
|
|
||||||
|
|
||||||
// Function: str_frac()
|
// Function: parse_frac()
|
||||||
// Usage:
|
// Usage:
|
||||||
// str_frac(str,[mixed],[improper],[signed])
|
// parse_frac(str,[mixed],[improper],[signed])
|
||||||
// Description:
|
// Description:
|
||||||
// Converts a string fraction to a floating point number. A string fraction has the form `[-][# ][#/#]` where each `#` is one or more of the
|
// Converts a string fraction to a floating point number. A string fraction has the form `[-][# ][#/#]` where each `#` is one or more of the
|
||||||
// digits 0-9, and there is an optional sign character at the beginning.
|
// digits 0-9, and there is an optional sign character at the beginning.
|
||||||
|
@ -418,64 +418,64 @@ function str_float(str) =
|
||||||
// improper = set to true to accept improper fractions, false to reject them. Default: true
|
// improper = set to true to accept improper fractions, false to reject them. Default: true
|
||||||
// signed = set to true to accept a leading sign character, false to reject. Default: true
|
// signed = set to true to accept a leading sign character, false to reject. Default: true
|
||||||
// Example:
|
// Example:
|
||||||
// str_frac("3/4"); // Returns 0.75
|
// parse_frac("3/4"); // Returns 0.75
|
||||||
// str_frac("-77/9"); // Returns -8.55556
|
// parse_frac("-77/9"); // Returns -8.55556
|
||||||
// str_frac("+1/3"); // Returns 0.33333
|
// parse_frac("+1/3"); // Returns 0.33333
|
||||||
// str_frac("19"); // Returns 19
|
// parse_frac("19"); // Returns 19
|
||||||
// str_frac("2 3/4"); // Returns 2.75
|
// parse_frac("2 3/4"); // Returns 2.75
|
||||||
// str_frac("-2 12/4"); // Returns -5
|
// parse_frac("-2 12/4"); // Returns -5
|
||||||
// str_frac(""); // Returns 0
|
// parse_frac(""); // Returns 0
|
||||||
// str_frac("3/0"); // Returns inf
|
// parse_frac("3/0"); // Returns inf
|
||||||
// str_frac("0/0"); // Returns nan
|
// parse_frac("0/0"); // Returns nan
|
||||||
// str_frac("-77/9",improper=false); // Returns nan
|
// parse_frac("-77/9",improper=false); // Returns nan
|
||||||
// str_frac("-2 12/4",improper=false); // Returns nan
|
// parse_frac("-2 12/4",improper=false); // Returns nan
|
||||||
// str_frac("-2 12/4",signed=false); // Returns nan
|
// parse_frac("-2 12/4",signed=false); // Returns nan
|
||||||
// str_frac("-2 12/4",mixed=false); // Returns nan
|
// parse_frac("-2 12/4",mixed=false); // Returns nan
|
||||||
// str_frac("2 1/4",mixed=false); // Returns nan
|
// parse_frac("2 1/4",mixed=false); // Returns nan
|
||||||
function str_frac(str,mixed=true,improper=true,signed=true) =
|
function parse_frac(str,mixed=true,improper=true,signed=true) =
|
||||||
str == undef ? undef :
|
str == undef ? undef :
|
||||||
len(str)==0 ? 0 :
|
len(str)==0 ? 0 :
|
||||||
signed && str[0]=="-" ? -str_frac(substr(str,1),mixed=mixed,improper=improper,signed=false) :
|
signed && str[0]=="-" ? -parse_frac(substr(str,1),mixed=mixed,improper=improper,signed=false) :
|
||||||
signed && str[0]=="+" ? str_frac(substr(str,1),mixed=mixed,improper=improper,signed=false) :
|
signed && str[0]=="+" ? parse_frac(substr(str,1),mixed=mixed,improper=improper,signed=false) :
|
||||||
mixed ? (
|
mixed ? (
|
||||||
!in_list(str_find(str," "), [undef,0]) || is_undef(str_find(str,"/"))? (
|
!in_list(str_find(str," "), [undef,0]) || is_undef(str_find(str,"/"))? (
|
||||||
let(whole = str_split(str,[" "]))
|
let(whole = str_split(str,[" "]))
|
||||||
_str_int_recurse(whole[0],10,len(whole[0])-1) + str_frac(whole[1], mixed=false, improper=improper, signed=false)
|
_parse_int_recurse(whole[0],10,len(whole[0])-1) + parse_frac(whole[1], mixed=false, improper=improper, signed=false)
|
||||||
) : str_frac(str,mixed=false, improper=improper)
|
) : parse_frac(str,mixed=false, improper=improper)
|
||||||
) : (
|
) : (
|
||||||
let(split = str_split(str,"/"))
|
let(split = str_split(str,"/"))
|
||||||
len(split)!=2 ? (0/0) :
|
len(split)!=2 ? (0/0) :
|
||||||
let(
|
let(
|
||||||
numerator = _str_int_recurse(split[0],10,len(split[0])-1),
|
numerator = _parse_int_recurse(split[0],10,len(split[0])-1),
|
||||||
denominator = _str_int_recurse(split[1],10,len(split[1])-1)
|
denominator = _parse_int_recurse(split[1],10,len(split[1])-1)
|
||||||
) !improper && numerator>=denominator? (0/0) :
|
) !improper && numerator>=denominator? (0/0) :
|
||||||
denominator<0 ? (0/0) : numerator/denominator
|
denominator<0 ? (0/0) : numerator/denominator
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
// Function: str_num()
|
// Function: parse_num()
|
||||||
// Usage:
|
// Usage:
|
||||||
// str_num(str)
|
// parse_num(str)
|
||||||
// Description:
|
// Description:
|
||||||
// Converts a string to a number. The string can be either a fraction (two integers separated by a "/") or a floating point number.
|
// Converts a string to a number. The string can be either a fraction (two integers separated by a "/") or a floating point number.
|
||||||
// Returns NaN if the conversion fails.
|
// Returns NaN if the conversion fails.
|
||||||
// Example:
|
// Example:
|
||||||
// str_num("3/4"); // Returns 0.75
|
// parse_num("3/4"); // Returns 0.75
|
||||||
// str_num("3.4e-2"); // Returns 0.034
|
// parse_num("3.4e-2"); // Returns 0.034
|
||||||
function str_num(str) =
|
function parse_num(str) =
|
||||||
str == undef ? undef :
|
str == undef ? undef :
|
||||||
let( val = str_frac(str) )
|
let( val = parse_frac(str) )
|
||||||
val == val ? val :
|
val == val ? val :
|
||||||
str_float(str);
|
parse_float(str);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Section: Formatting data
|
// Section: Formatting numbers into strings
|
||||||
|
|
||||||
// Function: fmt_int()
|
// Function: format_int()
|
||||||
// Usage:
|
// Usage:
|
||||||
// fmt_int(i, [mindigits]);
|
// format_int(i, [mindigits]);
|
||||||
// Description:
|
// Description:
|
||||||
// Formats an integer number into a string. This can handle larger numbers than `str()`.
|
// Formats an integer number into a string. This can handle larger numbers than `str()`.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
|
@ -483,10 +483,10 @@ function str_num(str) =
|
||||||
// mindigits = If the number has fewer than this many digits, pad the front with zeros until it does. Default: 1.
|
// mindigits = If the number has fewer than this many digits, pad the front with zeros until it does. Default: 1.
|
||||||
// Example:
|
// Example:
|
||||||
// str(123456789012345); // Returns "1.23457e+14"
|
// str(123456789012345); // Returns "1.23457e+14"
|
||||||
// fmt_int(123456789012345); // Returns "123456789012345"
|
// format_int(123456789012345); // Returns "123456789012345"
|
||||||
// fmt_int(-123456789012345); // Returns "-123456789012345"
|
// format_int(-123456789012345); // Returns "-123456789012345"
|
||||||
function fmt_int(i,mindigits=1) =
|
function format_int(i,mindigits=1) =
|
||||||
i<0? str("-", fmt_int(-i,mindigits)) :
|
i<0? str("-", format_int(-i,mindigits)) :
|
||||||
let(i=floor(i), e=floor(log(i)))
|
let(i=floor(i), e=floor(log(i)))
|
||||||
i==0? str_join([for (j=[0:1:mindigits-1]) "0"]) :
|
i==0? str_join([for (j=[0:1:mindigits-1]) "0"]) :
|
||||||
str_join(
|
str_join(
|
||||||
|
@ -497,33 +497,33 @@ function fmt_int(i,mindigits=1) =
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
// Function: fmt_fixed()
|
// Function: format_fixed()
|
||||||
// Usage:
|
// Usage:
|
||||||
// s = fmt_fixed(f, [digits]);
|
// s = format_fixed(f, [digits]);
|
||||||
// Description:
|
// Description:
|
||||||
// Given a floating point number, formats it into a string with the given number of digits after the decimal point.
|
// Given a floating point number, formats it into a string with the given number of digits after the decimal point.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// f = The floating point number to format.
|
// f = The floating point number to format.
|
||||||
// digits = The number of digits after the decimal to show. Default: 6
|
// digits = The number of digits after the decimal to show. Default: 6
|
||||||
function fmt_fixed(f,digits=6) =
|
function format_fixed(f,digits=6) =
|
||||||
assert(is_int(digits))
|
assert(is_int(digits))
|
||||||
assert(digits>0)
|
assert(digits>0)
|
||||||
is_list(f)? str("[",str_join(sep=", ", [for (g=f) fmt_fixed(g,digits=digits)]),"]") :
|
is_list(f)? str("[",str_join(sep=", ", [for (g=f) format_fixed(g,digits=digits)]),"]") :
|
||||||
str(f)=="nan"? "nan" :
|
str(f)=="nan"? "nan" :
|
||||||
str(f)=="inf"? "inf" :
|
str(f)=="inf"? "inf" :
|
||||||
f<0? str("-",fmt_fixed(-f,digits=digits)) :
|
f<0? str("-",format_fixed(-f,digits=digits)) :
|
||||||
assert(is_num(f))
|
assert(is_num(f))
|
||||||
let(
|
let(
|
||||||
sc = pow(10,digits),
|
sc = pow(10,digits),
|
||||||
scaled = floor(f * sc + 0.5),
|
scaled = floor(f * sc + 0.5),
|
||||||
whole = floor(scaled/sc),
|
whole = floor(scaled/sc),
|
||||||
part = floor(scaled-(whole*sc))
|
part = floor(scaled-(whole*sc))
|
||||||
) str(fmt_int(whole),".",fmt_int(part,digits));
|
) str(format_int(whole),".",format_int(part,digits));
|
||||||
|
|
||||||
|
|
||||||
// Function: fmt_float()
|
// Function: format_float()
|
||||||
// Usage:
|
// Usage:
|
||||||
// fmt_float(f,[sig]);
|
// format_float(f,[sig]);
|
||||||
// Description:
|
// Description:
|
||||||
// Formats the given floating point number `f` into a string with `sig` significant digits.
|
// Formats the given floating point number `f` into a string with `sig` significant digits.
|
||||||
// Strips trailing `0`s after the decimal point. Strips trailing decimal point.
|
// Strips trailing `0`s after the decimal point. Strips trailing decimal point.
|
||||||
|
@ -533,22 +533,22 @@ function fmt_fixed(f,digits=6) =
|
||||||
// f = The floating point number to format.
|
// f = The floating point number to format.
|
||||||
// sig = The number of significant digits to display. Default: 12
|
// sig = The number of significant digits to display. Default: 12
|
||||||
// Example:
|
// Example:
|
||||||
// fmt_float(PI,12); // Returns: "3.14159265359"
|
// format_float(PI,12); // Returns: "3.14159265359"
|
||||||
// fmt_float([PI,-16.75],12); // Returns: "[3.14159265359, -16.75]"
|
// format_float([PI,-16.75],12); // Returns: "[3.14159265359, -16.75]"
|
||||||
function fmt_float(f,sig=12) =
|
function format_float(f,sig=12) =
|
||||||
assert(is_int(sig))
|
assert(is_int(sig))
|
||||||
assert(sig>0)
|
assert(sig>0)
|
||||||
is_list(f)? str("[",str_join(sep=", ", [for (g=f) fmt_float(g,sig=sig)]),"]") :
|
is_list(f)? str("[",str_join(sep=", ", [for (g=f) format_float(g,sig=sig)]),"]") :
|
||||||
f==0? "0" :
|
f==0? "0" :
|
||||||
str(f)=="nan"? "nan" :
|
str(f)=="nan"? "nan" :
|
||||||
str(f)=="inf"? "inf" :
|
str(f)=="inf"? "inf" :
|
||||||
f<0? str("-",fmt_float(-f,sig=sig)) :
|
f<0? str("-",format_float(-f,sig=sig)) :
|
||||||
assert(is_num(f))
|
assert(is_num(f))
|
||||||
let(
|
let(
|
||||||
e = floor(log(f)),
|
e = floor(log(f)),
|
||||||
mv = sig - e - 1
|
mv = sig - e - 1
|
||||||
) mv == 0? fmt_int(floor(f + 0.5)) :
|
) mv == 0? format_int(floor(f + 0.5)) :
|
||||||
(e<-sig/2||mv<0)? str(fmt_float(f*pow(10,-e),sig=sig),"e",e) :
|
(e<-sig/2||mv<0)? str(format_float(f*pow(10,-e),sig=sig),"e",e) :
|
||||||
let(
|
let(
|
||||||
ff = f + pow(10,-mv)*0.5,
|
ff = f + pow(10,-mv)*0.5,
|
||||||
whole = floor(ff),
|
whole = floor(ff),
|
||||||
|
@ -559,26 +559,26 @@ function fmt_float(f,sig=12) =
|
||||||
str_strip(end=true,
|
str_strip(end=true,
|
||||||
str_join([
|
str_join([
|
||||||
".",
|
".",
|
||||||
fmt_int(part, mindigits=mv)
|
format_int(part, mindigits=mv)
|
||||||
]),
|
]),
|
||||||
"0."
|
"0."
|
||||||
)
|
)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
||||||
// Function: matrix_strings()
|
/// Function: _format_matrix()
|
||||||
// Usage:
|
/// Usage:
|
||||||
// matrix_strings(M, [sig], [eps])
|
/// _format_matrix(M, [sig], [eps])
|
||||||
// Description:
|
/// Description:
|
||||||
// Convert a numerical matrix into a matrix of strings where every column
|
/// Convert a numerical matrix into a matrix of strings where every column
|
||||||
// is the same width so it will display in neat columns when printed.
|
/// is the same width so it will display in neat columns when printed.
|
||||||
// Values below eps will display as zero. The matrix can include nans, infs
|
/// Values below eps will display as zero. The matrix can include nans, infs
|
||||||
// or undefs and the rows can be different lengths.
|
/// or undefs and the rows can be different lengths.
|
||||||
// Arguments:
|
/// Arguments:
|
||||||
// M = numerical matrix to convert
|
/// M = numerical matrix to convert
|
||||||
// sig = significant digits to display. Default: 4
|
/// sig = significant digits to display. Default: 4
|
||||||
// eps = values smaller than this are shown as zero. Default: 1e-9
|
/// eps = values smaller than this are shown as zero. Default: 1e-9
|
||||||
function matrix_strings(M, sig=4, eps=1e-9) =
|
function _format_matrix(M, sig=4, eps=1e-9) =
|
||||||
let(
|
let(
|
||||||
columngap = 1,
|
columngap = 1,
|
||||||
figure_dash = chr(8210),
|
figure_dash = chr(8210),
|
||||||
|
@ -590,7 +590,7 @@ function matrix_strings(M, sig=4, eps=1e-9) =
|
||||||
let(
|
let(
|
||||||
text = is_undef(entry) ? "und"
|
text = is_undef(entry) ? "und"
|
||||||
: abs(entry) < eps ? "0" // Replace hyphens with figure dashes
|
: abs(entry) < eps ? "0" // Replace hyphens with figure dashes
|
||||||
: str_replace_char(fmt_float(entry, sig),"-",figure_dash),
|
: str_replace_char(format_float(entry, sig),"-",figure_dash),
|
||||||
have_dot = is_def(str_find(text, "."))
|
have_dot = is_def(str_find(text, "."))
|
||||||
)
|
)
|
||||||
// If the text lacks a dot we add a space the same width as a dot to
|
// If the text lacks a dot we add a space the same width as a dot to
|
||||||
|
@ -616,9 +616,9 @@ function matrix_strings(M, sig=4, eps=1e-9) =
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Function: str_format()
|
// Function: format()
|
||||||
// Usage:
|
// Usage:
|
||||||
// s = str_format(fmt, vals);
|
// s = format(fmt, vals);
|
||||||
// Description:
|
// Description:
|
||||||
// Given a format string and a list of values, inserts the values into the placeholders in the format string and returns it.
|
// Given a format string and a list of values, inserts the values into the placeholders in the format string and returns it.
|
||||||
// Formatting placeholders have the following syntax:
|
// Formatting placeholders have the following syntax:
|
||||||
|
@ -645,13 +645,13 @@ function matrix_strings(M, sig=4, eps=1e-9) =
|
||||||
// fmt = The formatting string, with placeholders to format the values into.
|
// fmt = The formatting string, with placeholders to format the values into.
|
||||||
// vals = The list of values to format.
|
// vals = The list of values to format.
|
||||||
// Example(NORENDER):
|
// Example(NORENDER):
|
||||||
// str_format("The value of {} is {:.14f}.", ["pi", PI]); // Returns: "The value of pi is 3.14159265358979."
|
// format("The value of {} is {:.14f}.", ["pi", PI]); // Returns: "The value of pi is 3.14159265358979."
|
||||||
// str_format("The value {1:f} is known as {0}.", ["pi", PI]); // Returns: "The value 3.141593 is known as pi."
|
// format("The value {1:f} is known as {0}.", ["pi", PI]); // Returns: "The value 3.141593 is known as pi."
|
||||||
// str_format("We use a very small value {1:.6g} as {0}.", ["EPSILON", EPSILON]); // Returns: "We use a very small value 1e-9 as EPSILON."
|
// format("We use a very small value {1:.6g} as {0}.", ["EPSILON", EPSILON]); // Returns: "We use a very small value 1e-9 as EPSILON."
|
||||||
// str_format("{:-5s}{:i}{:b}", ["foo", 12e3, 5]); // Returns: "foo 12000true"
|
// format("{:-5s}{:i}{:b}", ["foo", 12e3, 5]); // Returns: "foo 12000true"
|
||||||
// str_format("{:-10s}{:.3f}", ["plecostamus",27.43982]); // Returns: "plecostamus27.440"
|
// format("{:-10s}{:.3f}", ["plecostamus",27.43982]); // Returns: "plecostamus27.440"
|
||||||
// str_format("{:-10.9s}{:.3f}", ["plecostamus",27.43982]); // Returns: "plecostam 27.440"
|
// format("{:-10.9s}{:.3f}", ["plecostamus",27.43982]); // Returns: "plecostam 27.440"
|
||||||
function str_format(fmt, vals) =
|
function format(fmt, vals) =
|
||||||
let(
|
let(
|
||||||
parts = str_split(fmt,"{")
|
parts = str_split(fmt,"{")
|
||||||
) str_join([
|
) str_join([
|
||||||
|
@ -666,7 +666,7 @@ function str_format(fmt, vals) =
|
||||||
assert(i<99)
|
assert(i<99)
|
||||||
is_undef(fmta)? "" : let(
|
is_undef(fmta)? "" : let(
|
||||||
fmtb = str_split(fmta,":"),
|
fmtb = str_split(fmta,":"),
|
||||||
num = is_digit(fmtb[0])? str_int(fmtb[0]) : (i-1),
|
num = is_digit(fmtb[0])? parse_int(fmtb[0]) : (i-1),
|
||||||
left = fmtb[1][0] == "-",
|
left = fmtb[1][0] == "-",
|
||||||
fmtb1 = default(fmtb[1],""),
|
fmtb1 = default(fmtb[1],""),
|
||||||
fmtc = left? substr(fmtb1,1) : fmtb1,
|
fmtc = left? substr(fmtb1,1) : fmtb1,
|
||||||
|
@ -676,21 +676,21 @@ function str_format(fmt, vals) =
|
||||||
typ = hastyp? lch : "s",
|
typ = hastyp? lch : "s",
|
||||||
fmtd = hastyp? substr(fmtc,0,len(fmtc)-1) : fmtc,
|
fmtd = hastyp? substr(fmtc,0,len(fmtc)-1) : fmtc,
|
||||||
fmte = str_split((zero? substr(fmtd,1) : fmtd), "."),
|
fmte = str_split((zero? substr(fmtd,1) : fmtd), "."),
|
||||||
wid = str_int(fmte[0]),
|
wid = parse_int(fmte[0]),
|
||||||
prec = str_int(fmte[1]),
|
prec = parse_int(fmte[1]),
|
||||||
val = assert(num>=0&&num<len(vals)) vals[num],
|
val = assert(num>=0&&num<len(vals)) vals[num],
|
||||||
unpad = typ=="s"? (
|
unpad = typ=="s"? (
|
||||||
let( sval = str(val) )
|
let( sval = str(val) )
|
||||||
is_undef(prec)? sval :
|
is_undef(prec)? sval :
|
||||||
substr(sval, 0, min(len(sval)-1, prec))
|
substr(sval, 0, min(len(sval)-1, prec))
|
||||||
) :
|
) :
|
||||||
(typ=="d" || typ=="i")? fmt_int(val) :
|
(typ=="d" || typ=="i")? format_int(val) :
|
||||||
typ=="b"? (val? "true" : "false") :
|
typ=="b"? (val? "true" : "false") :
|
||||||
typ=="B"? (val? "TRUE" : "FALSE") :
|
typ=="B"? (val? "TRUE" : "FALSE") :
|
||||||
typ=="f"? downcase(fmt_fixed(val,default(prec,6))) :
|
typ=="f"? downcase(format_fixed(val,default(prec,6))) :
|
||||||
typ=="F"? upcase(fmt_fixed(val,default(prec,6))) :
|
typ=="F"? upcase(format_fixed(val,default(prec,6))) :
|
||||||
typ=="g"? downcase(fmt_float(val,default(prec,6))) :
|
typ=="g"? downcase(format_float(val,default(prec,6))) :
|
||||||
typ=="G"? upcase(fmt_float(val,default(prec,6))) :
|
typ=="G"? upcase(format_float(val,default(prec,6))) :
|
||||||
assert(false,str("Unknown format type: ",typ)),
|
assert(false,str("Unknown format type: ",typ)),
|
||||||
padlen = max(0,wid-len(unpad)),
|
padlen = max(0,wid-len(unpad)),
|
||||||
padfill = str_join([for (i=[0:1:padlen-1]) zero? "0" : " "]),
|
padfill = str_join([for (i=[0:1:padlen-1]) zero? "0" : " "]),
|
||||||
|
@ -701,29 +701,6 @@ function str_format(fmt, vals) =
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
||||||
// Function&Module: echofmt()
|
|
||||||
// Usage:
|
|
||||||
// echofmt(fmt,vals);
|
|
||||||
// Description:
|
|
||||||
// Formats the given `vals` with the given format string `fmt` using [`str_format()`](#str_format), and echos the resultant string.
|
|
||||||
// Arguments:
|
|
||||||
// fmt = The formatting string, with placeholders to format the values into.
|
|
||||||
// vals = The list of values to format.
|
|
||||||
// Example(NORENDER):
|
|
||||||
// echofmt("The value of {} is {:.14f}.", ["pi", PI]); // ECHO: "The value of pi is 3.14159265358979."
|
|
||||||
// echofmt("The value {1:f} is known as {0}.", ["pi", PI]); // ECHO: "The value 3.141593 is known as pi."
|
|
||||||
// echofmt("We use a very small value {1:.6g} as {0}.", ["EPSILON", EPSILON]); // ECHO: "We use a ver small value 1e-9 as EPSILON."
|
|
||||||
// echofmt("{:-5s}{:i}{:b}", ["foo", 12e3, 5]); // ECHO: "foo 12000true"
|
|
||||||
// echofmt("{:-10s}{:.3f}", ["plecostamus",27.43982]); // ECHO: "plecostamus27.440"
|
|
||||||
// echofmt("{:-10.9s}{:.3f}", ["plecostamus",27.43982]); // ECHO: "plecostam 27.440"
|
|
||||||
function echofmt(fmt, vals) = echo(str_format(fmt,vals));
|
|
||||||
module echofmt(fmt, vals) {
|
|
||||||
no_children($children);
|
|
||||||
echo(str_format(fmt,vals));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Section: Checking character class
|
// Section: Checking character class
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ module test_HSL() {
|
||||||
h<=300? [x,0,c] :
|
h<=300? [x,0,c] :
|
||||||
[c,0,x]
|
[c,0,x]
|
||||||
);
|
);
|
||||||
assert_approx(HSL(h,s,l), rgb, str_format("h={}, s={}, l={}", [h,s,l]));
|
assert_approx(HSL(h,s,l), rgb, format("h={}, s={}, l={}", [h,s,l]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ module test_HSV() {
|
||||||
h<=300? [x,0,c] :
|
h<=300? [x,0,c] :
|
||||||
[c,0,x]
|
[c,0,x]
|
||||||
);
|
);
|
||||||
assert_approx(HSV(h,s,v), rgb, str_format("h={}, s={}, v={}", [h,s,v]));
|
assert_approx(HSV(h,s,v), rgb, format("h={}, s={}, v={}", [h,s,v]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,50 +46,50 @@ module test_ends_with() {
|
||||||
test_ends_with();
|
test_ends_with();
|
||||||
|
|
||||||
|
|
||||||
module test_fmt_int() {
|
module test_format_int() {
|
||||||
assert(fmt_int(0,6) == "000000");
|
assert(format_int(0,6) == "000000");
|
||||||
assert(fmt_int(3,6) == "000003");
|
assert(format_int(3,6) == "000003");
|
||||||
assert(fmt_int(98765,6) == "098765");
|
assert(format_int(98765,6) == "098765");
|
||||||
assert(fmt_int(-3,6) == "-000003");
|
assert(format_int(-3,6) == "-000003");
|
||||||
assert(fmt_int(-98765,6) == "-098765");
|
assert(format_int(-98765,6) == "-098765");
|
||||||
}
|
}
|
||||||
test_fmt_int();
|
test_format_int();
|
||||||
|
|
||||||
|
|
||||||
module test_fmt_fixed() {
|
module test_format_fixed() {
|
||||||
assert(fmt_fixed(-PI*100,8) == "-314.15926536");
|
assert(format_fixed(-PI*100,8) == "-314.15926536");
|
||||||
assert(fmt_fixed(-PI,8) == "-3.14159265");
|
assert(format_fixed(-PI,8) == "-3.14159265");
|
||||||
assert(fmt_fixed(-3,8) == "-3.00000000");
|
assert(format_fixed(-3,8) == "-3.00000000");
|
||||||
assert(fmt_fixed(3,8) == "3.00000000");
|
assert(format_fixed(3,8) == "3.00000000");
|
||||||
assert(fmt_fixed(PI*100,8) == "314.15926536");
|
assert(format_fixed(PI*100,8) == "314.15926536");
|
||||||
assert(fmt_fixed(PI,8) == "3.14159265");
|
assert(format_fixed(PI,8) == "3.14159265");
|
||||||
assert(fmt_fixed(0,8) == "0.00000000");
|
assert(format_fixed(0,8) == "0.00000000");
|
||||||
assert(fmt_fixed(-PI*100,3) == "-314.159");
|
assert(format_fixed(-PI*100,3) == "-314.159");
|
||||||
assert(fmt_fixed(-PI,3) == "-3.142");
|
assert(format_fixed(-PI,3) == "-3.142");
|
||||||
assert(fmt_fixed(-3,3) == "-3.000");
|
assert(format_fixed(-3,3) == "-3.000");
|
||||||
assert(fmt_fixed(3,3) == "3.000");
|
assert(format_fixed(3,3) == "3.000");
|
||||||
assert(fmt_fixed(PI*100,3) == "314.159");
|
assert(format_fixed(PI*100,3) == "314.159");
|
||||||
assert(fmt_fixed(PI,3) == "3.142");
|
assert(format_fixed(PI,3) == "3.142");
|
||||||
}
|
}
|
||||||
test_fmt_fixed();
|
test_format_fixed();
|
||||||
|
|
||||||
|
|
||||||
module test_fmt_float() {
|
module test_format_float() {
|
||||||
assert(fmt_float(-PI*100,8) == "-314.15927");
|
assert(format_float(-PI*100,8) == "-314.15927");
|
||||||
assert(fmt_float(-PI,8) == "-3.1415927");
|
assert(format_float(-PI,8) == "-3.1415927");
|
||||||
assert(fmt_float(-3,8) == "-3");
|
assert(format_float(-3,8) == "-3");
|
||||||
assert(fmt_float(3,8) == "3");
|
assert(format_float(3,8) == "3");
|
||||||
assert(fmt_float(PI*100,8) == "314.15927");
|
assert(format_float(PI*100,8) == "314.15927");
|
||||||
assert(fmt_float(PI,8) == "3.1415927");
|
assert(format_float(PI,8) == "3.1415927");
|
||||||
assert(fmt_float(0,8) == "0");
|
assert(format_float(0,8) == "0");
|
||||||
assert(fmt_float(-PI*100,3) == "-314");
|
assert(format_float(-PI*100,3) == "-314");
|
||||||
assert(fmt_float(-PI,3) == "-3.14");
|
assert(format_float(-PI,3) == "-3.14");
|
||||||
assert(fmt_float(-3,3) == "-3");
|
assert(format_float(-3,3) == "-3");
|
||||||
assert(fmt_float(3,3) == "3");
|
assert(format_float(3,3) == "3");
|
||||||
assert(fmt_float(PI*100,3) == "314");
|
assert(format_float(PI*100,3) == "314");
|
||||||
assert(fmt_float(PI,3) == "3.14");
|
assert(format_float(PI,3) == "3.14");
|
||||||
}
|
}
|
||||||
test_fmt_float();
|
test_format_float();
|
||||||
|
|
||||||
|
|
||||||
module test_is_digit() {
|
module test_is_digit() {
|
||||||
|
@ -173,78 +173,78 @@ module test_is_upper() {
|
||||||
test_is_upper();
|
test_is_upper();
|
||||||
|
|
||||||
|
|
||||||
module test_str_float() {
|
module test_parse_float() {
|
||||||
assert(str_float("3.1416") == 3.1416);
|
assert(parse_float("3.1416") == 3.1416);
|
||||||
assert(str_float("-3.1416") == -3.1416);
|
assert(parse_float("-3.1416") == -3.1416);
|
||||||
assert(str_float("3.000") == 3.0);
|
assert(parse_float("3.000") == 3.0);
|
||||||
assert(str_float("-3.000") == -3.0);
|
assert(parse_float("-3.000") == -3.0);
|
||||||
assert(str_float("3") == 3.0);
|
assert(parse_float("3") == 3.0);
|
||||||
assert(str_float("0") == 0.0);
|
assert(parse_float("0") == 0.0);
|
||||||
}
|
}
|
||||||
test_str_float();
|
test_parse_float();
|
||||||
|
|
||||||
|
|
||||||
module test_str_frac() {
|
module test_parse_frac() {
|
||||||
assert(str_frac("") == 0);
|
assert(parse_frac("") == 0);
|
||||||
assert(str_frac("1/2") == 1/2);
|
assert(parse_frac("1/2") == 1/2);
|
||||||
assert(str_frac("+1/2") == 1/2);
|
assert(parse_frac("+1/2") == 1/2);
|
||||||
assert(str_frac("-1/2") == -1/2);
|
assert(parse_frac("-1/2") == -1/2);
|
||||||
assert(str_frac("7/8") == 7/8);
|
assert(parse_frac("7/8") == 7/8);
|
||||||
assert(str_frac("+7/8") == 7/8);
|
assert(parse_frac("+7/8") == 7/8);
|
||||||
assert(str_frac("-7/8") == -7/8);
|
assert(parse_frac("-7/8") == -7/8);
|
||||||
assert(str_frac("1 1/2") == 1 + 1/2);
|
assert(parse_frac("1 1/2") == 1 + 1/2);
|
||||||
assert(str_frac("+1 1/2") == 1 + 1/2);
|
assert(parse_frac("+1 1/2") == 1 + 1/2);
|
||||||
assert(str_frac("-1 1/2") == -(1 + 1/2));
|
assert(parse_frac("-1 1/2") == -(1 + 1/2));
|
||||||
assert(str_frac("768 3/4") == 768 + 3/4);
|
assert(parse_frac("768 3/4") == 768 + 3/4);
|
||||||
assert(str_frac("+768 3/4") == 768 + 3/4);
|
assert(parse_frac("+768 3/4") == 768 + 3/4);
|
||||||
assert(str_frac("-768 3/4") == -(768 + 3/4));
|
assert(parse_frac("-768 3/4") == -(768 + 3/4));
|
||||||
assert(str_frac("19") == 19);
|
assert(parse_frac("19") == 19);
|
||||||
assert(str_frac("+19") == 19);
|
assert(parse_frac("+19") == 19);
|
||||||
assert(str_frac("-19") == -19);
|
assert(parse_frac("-19") == -19);
|
||||||
assert(str_frac("3/0") == INF);
|
assert(parse_frac("3/0") == INF);
|
||||||
assert(str_frac("-3/0") == -INF);
|
assert(parse_frac("-3/0") == -INF);
|
||||||
assert(is_nan(str_frac("0/0")));
|
assert(is_nan(parse_frac("0/0")));
|
||||||
}
|
}
|
||||||
test_str_frac();
|
test_parse_frac();
|
||||||
|
|
||||||
|
|
||||||
module test_str_num() {
|
module test_parse_num() {
|
||||||
assert(str_num("") == 0);
|
assert(parse_num("") == 0);
|
||||||
assert(str_num("1/2") == 1/2);
|
assert(parse_num("1/2") == 1/2);
|
||||||
assert(str_num("+1/2") == 1/2);
|
assert(parse_num("+1/2") == 1/2);
|
||||||
assert(str_num("-1/2") == -1/2);
|
assert(parse_num("-1/2") == -1/2);
|
||||||
assert(str_num("7/8") == 7/8);
|
assert(parse_num("7/8") == 7/8);
|
||||||
assert(str_num("+7/8") == 7/8);
|
assert(parse_num("+7/8") == 7/8);
|
||||||
assert(str_num("-7/8") == -7/8);
|
assert(parse_num("-7/8") == -7/8);
|
||||||
assert(str_num("1 1/2") == 1 + 1/2);
|
assert(parse_num("1 1/2") == 1 + 1/2);
|
||||||
assert(str_num("+1 1/2") == 1 + 1/2);
|
assert(parse_num("+1 1/2") == 1 + 1/2);
|
||||||
assert(str_num("-1 1/2") == -(1 + 1/2));
|
assert(parse_num("-1 1/2") == -(1 + 1/2));
|
||||||
assert(str_num("768 3/4") == 768 + 3/4);
|
assert(parse_num("768 3/4") == 768 + 3/4);
|
||||||
assert(str_num("+768 3/4") == 768 + 3/4);
|
assert(parse_num("+768 3/4") == 768 + 3/4);
|
||||||
assert(str_num("-768 3/4") == -(768 + 3/4));
|
assert(parse_num("-768 3/4") == -(768 + 3/4));
|
||||||
assert(str_num("19") == 19);
|
assert(parse_num("19") == 19);
|
||||||
assert(str_num("+19") == 19);
|
assert(parse_num("+19") == 19);
|
||||||
assert(str_num("-19") == -19);
|
assert(parse_num("-19") == -19);
|
||||||
assert(str_num("3/0") == INF);
|
assert(parse_num("3/0") == INF);
|
||||||
assert(str_num("-3/0") == -INF);
|
assert(parse_num("-3/0") == -INF);
|
||||||
assert(str_num("3.14159") == 3.14159);
|
assert(parse_num("3.14159") == 3.14159);
|
||||||
assert(str_num("-3.14159") == -3.14159);
|
assert(parse_num("-3.14159") == -3.14159);
|
||||||
assert(is_nan(str_num("0/0")));
|
assert(is_nan(parse_num("0/0")));
|
||||||
}
|
}
|
||||||
test_str_num();
|
test_parse_num();
|
||||||
|
|
||||||
|
|
||||||
module test_str_int() {
|
module test_parse_int() {
|
||||||
assert(str_int("0") == 0);
|
assert(parse_int("0") == 0);
|
||||||
assert(str_int("3") == 3);
|
assert(parse_int("3") == 3);
|
||||||
assert(str_int("7655") == 7655);
|
assert(parse_int("7655") == 7655);
|
||||||
assert(str_int("+3") == 3);
|
assert(parse_int("+3") == 3);
|
||||||
assert(str_int("+7655") == 7655);
|
assert(parse_int("+7655") == 7655);
|
||||||
assert(str_int("-3") == -3);
|
assert(parse_int("-3") == -3);
|
||||||
assert(str_int("-7655") == -7655);
|
assert(parse_int("-7655") == -7655);
|
||||||
assert(str_int("ffff",16) == 65535);
|
assert(parse_int("ffff",16) == 65535);
|
||||||
}
|
}
|
||||||
test_str_int();
|
test_parse_int();
|
||||||
|
|
||||||
|
|
||||||
module test_str_join() {
|
module test_str_join() {
|
||||||
|
@ -342,15 +342,15 @@ module test_str_find() {
|
||||||
test_str_find();
|
test_str_find();
|
||||||
|
|
||||||
|
|
||||||
module test_str_format() {
|
module test_format() {
|
||||||
assert(str_format("The value of {} is {:.14f}.", ["pi", PI]) == "The value of pi is 3.14159265358979.");
|
assert(format("The value of {} is {:.14f}.", ["pi", PI]) == "The value of pi is 3.14159265358979.");
|
||||||
assert(str_format("The value {1:f} is known as {0}.", ["pi", PI]) == "The value 3.141593 is known as pi.");
|
assert(format("The value {1:f} is known as {0}.", ["pi", PI]) == "The value 3.141593 is known as pi.");
|
||||||
assert(str_format("We use a very small value {1:.6g} as {0}.", ["EPSILON", EPSILON]) == "We use a very small value 1e-9 as EPSILON.");
|
assert(format("We use a very small value {1:.6g} as {0}.", ["EPSILON", EPSILON]) == "We use a very small value 1e-9 as EPSILON.");
|
||||||
assert(str_format("{:-5s}{:i}{:b}", ["foo", 12e3, 5]) == "foo 12000true");
|
assert(format("{:-5s}{:i}{:b}", ["foo", 12e3, 5]) == "foo 12000true");
|
||||||
assert(str_format("{:-10s}{:.3f}", ["plecostamus",27.43982]) == "plecostamus27.440");
|
assert(format("{:-10s}{:.3f}", ["plecostamus",27.43982]) == "plecostamus27.440");
|
||||||
assert(str_format("{:-10.9s}{:.3f}", ["plecostamus",27.43982]) == "plecostam 27.440");
|
assert(format("{:-10.9s}{:.3f}", ["plecostamus",27.43982]) == "plecostam 27.440");
|
||||||
}
|
}
|
||||||
test_str_format();
|
test_format();
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -23,6 +23,10 @@ module test_move() {
|
||||||
// Verify that module at least doesn't crash.
|
// Verify that module at least doesn't crash.
|
||||||
move(x=-5) move(y=-5) move(z=-5) move([-5,-5,-5]) union(){};
|
move(x=-5) move(y=-5) move(z=-5) move([-5,-5,-5]) union(){};
|
||||||
move(x=5) move(y=5) move(z=5) move([5,5,5]) union(){};
|
move(x=5) move(y=5) move(z=5) move([5,5,5]) union(){};
|
||||||
|
sq = square(10);
|
||||||
|
assert_equal(move("centroid", sq), move(-centroid(sq),sq));
|
||||||
|
assert_equal(move("mean", vals), move(-mean(vals), vals));
|
||||||
|
assert_equal(move("box", vals), move(-mean(pointlist_bounds(vals)),vals));
|
||||||
}
|
}
|
||||||
test_move();
|
test_move();
|
||||||
|
|
||||||
|
|
|
@ -1154,7 +1154,7 @@ module generic_threaded_nut(
|
||||||
// pitch = Distance between threads. Default: 2mm/thread
|
// pitch = Distance between threads. Default: 2mm/thread
|
||||||
// thread_depth = Depth of threads from top to bottom.
|
// thread_depth = Depth of threads from top to bottom.
|
||||||
// flank_angle = Angle of thread faces to plane perpendicular to screw. Default: 15 degrees.
|
// flank_angle = Angle of thread faces to plane perpendicular to screw. Default: 15 degrees.
|
||||||
// twist = Number of degrees to rotate thread around. Default: 720 degrees.
|
// turns = Number of revolutions to rotate thread around. Default: 2.
|
||||||
// ---
|
// ---
|
||||||
// profile = If an asymmetrical thread profile is needed, it can be specified here.
|
// profile = If an asymmetrical thread profile is needed, it can be specified here.
|
||||||
// starts = The number of thread starts. Default: 1
|
// starts = The number of thread starts. Default: 1
|
||||||
|
@ -1203,18 +1203,18 @@ module generic_threaded_nut(
|
||||||
// right(14)back(14)text("angle",size=4,halign="center");
|
// right(14)back(14)text("angle",size=4,halign="center");
|
||||||
// }
|
// }
|
||||||
// Examples:
|
// Examples:
|
||||||
// thread_helix(d=10, pitch=2, thread_depth=0.75, flank_angle=15, twist=900, $fn=72);
|
// thread_helix(d=10, pitch=2, thread_depth=0.75, flank_angle=15, turns=2.5, $fn=72);
|
||||||
// thread_helix(d=10, pitch=2, thread_depth=0.75, flank_angle=15, twist=900, higbee=1, $fn=72);
|
// thread_helix(d=10, pitch=2, thread_depth=0.75, flank_angle=15, turns=2.5, higbee=1, $fn=72);
|
||||||
// thread_helix(d=10, pitch=2, thread_depth=0.75, flank_angle=15, twist=720, higbee=2, internal=true, $fn=72);
|
// thread_helix(d=10, pitch=2, thread_depth=0.75, flank_angle=15, turns=2, higbee=2, internal=true, $fn=72);
|
||||||
// thread_helix(d=10, pitch=2, thread_depth=0.75, flank_angle=15, twist=360, left_handed=true, higbee=1, $fn=36);
|
// thread_helix(d=10, pitch=2, thread_depth=0.75, flank_angle=15, turns=1, left_handed=true, higbee=1, $fn=36);
|
||||||
module thread_helix(
|
module thread_helix(
|
||||||
d, pitch, thread_depth, flank_angle, twist=720,
|
d, pitch, thread_depth, flank_angle, turns=2,
|
||||||
profile, starts=1, left_handed=false, internal=false,
|
profile, starts=1, left_handed=false, internal=false,
|
||||||
d1, d2, higbee, higbee1, higbee2,
|
d1, d2, higbee, higbee1, higbee2,
|
||||||
anchor, spin, orient
|
anchor, spin, orient
|
||||||
) {
|
) {
|
||||||
dummy1=assert(is_undef(profile) || !any_defined([thread_depth, flank_angle]),"Cannot give thread_depth or flank_angle with a profile");
|
dummy1=assert(is_undef(profile) || !any_defined([thread_depth, flank_angle]),"Cannot give thread_depth or flank_angle with a profile");
|
||||||
h = pitch*starts*twist/360;
|
h = pitch*starts*turns;
|
||||||
r1 = get_radius(d1=d1, d=d, dflt=10);
|
r1 = get_radius(d1=d1, d=d, dflt=10);
|
||||||
r2 = get_radius(d1=d2, d=d, dflt=10);
|
r2 = get_radius(d1=d2, d=d, dflt=10);
|
||||||
profile = is_def(profile) ? profile :
|
profile = is_def(profile) ? profile :
|
||||||
|
@ -1241,7 +1241,7 @@ module thread_helix(
|
||||||
dir = left_handed? -1 : 1;
|
dir = left_handed? -1 : 1;
|
||||||
attachable(anchor,spin,orient, r1=r1, r2=r2, l=h) {
|
attachable(anchor,spin,orient, r1=r1, r2=r2, l=h) {
|
||||||
zrot_copies(n=starts) {
|
zrot_copies(n=starts) {
|
||||||
spiral_sweep(pline, h=h, r1=r1, r2=r2, twist=twist*dir, higbee=higbee, higbee1=higbee1, higbee2=higbee2, internal=internal, anchor=CENTER);
|
spiral_sweep(pline, h=h, r1=r1, r2=r2, turns=turns*dir, higbee=higbee, higbee1=higbee1, higbee2=higbee2, internal=internal, anchor=CENTER);
|
||||||
}
|
}
|
||||||
children();
|
children();
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,9 +77,10 @@ _NO_ARG = [true,[123232345],false];
|
||||||
// Usage: As Module
|
// Usage: As Module
|
||||||
// move([x=], [y=], [z=]) ...
|
// move([x=], [y=], [z=]) ...
|
||||||
// move(v) ...
|
// move(v) ...
|
||||||
// Usage: Translate Points
|
// Usage: As a function to translate points, VNF, or Bezier patch
|
||||||
// pts = move(v, p);
|
// pts = move(v, p);
|
||||||
// pts = move([x=], [y=], [z=], p=);
|
// pts = move([x=], [y=], [z=], p=);
|
||||||
|
// pts = move(STRING, p);
|
||||||
// Usage: Get Translation Matrix
|
// Usage: Get Translation Matrix
|
||||||
// mat = move(v);
|
// mat = move(v);
|
||||||
// mat = move([x=], [y=], [z=]);
|
// mat = move([x=], [y=], [z=]);
|
||||||
|
@ -95,11 +96,12 @@ _NO_ARG = [true,[123232345],false];
|
||||||
// * Called as a function with a [bezier patch](beziers.scad) in the `p` argument, returns the translated patch.
|
// * Called as a function with a [bezier patch](beziers.scad) in the `p` argument, returns the translated patch.
|
||||||
// * Called as a function with a [VNF structure](vnf.scad) in the `p` argument, returns the translated VNF.
|
// * Called as a function with a [VNF structure](vnf.scad) in the `p` argument, returns the translated VNF.
|
||||||
// * Called as a function with the `p` argument, returns the translated point or list of points.
|
// * Called as a function with the `p` argument, returns the translated point or list of points.
|
||||||
|
// * Called as a function with the `p` argument set to a VNF or a polygon and `v` set to "centroid", "mean" or "box", translates the argument to the centroid, mean, or bounding box center respectively.
|
||||||
// * Called as a function without a `p` argument, with a 2D offset vector `v`, returns an affine2d translation matrix.
|
// * Called as a function without a `p` argument, with a 2D offset vector `v`, returns an affine2d translation matrix.
|
||||||
// * Called as a function without a `p` argument, with a 3D offset vector `v`, returns an affine3d translation matrix.
|
// * Called as a function without a `p` argument, with a 3D offset vector `v`, returns an affine3d translation matrix.
|
||||||
//
|
//
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// v = An [X,Y,Z] vector to translate by.
|
// v = An [X,Y,Z] vector to translate by. For function form with `p` is a point list or VNF, can be "centroid", "mean" or "box".
|
||||||
// p = Either a point, or a list of points to be translated when used as a function.
|
// p = Either a point, or a list of points to be translated when used as a function.
|
||||||
// ---
|
// ---
|
||||||
// x = X axis translation.
|
// x = X axis translation.
|
||||||
|
@ -139,12 +141,24 @@ _NO_ARG = [true,[123232345],false];
|
||||||
// mat2d = move([2,3]); // Returns: [[1,0,2],[0,1,3],[0,0,1]]
|
// mat2d = move([2,3]); // Returns: [[1,0,2],[0,1,3],[0,0,1]]
|
||||||
// mat3d = move([2,3,4]); // Returns: [[1,0,0,2],[0,1,0,3],[0,0,1,4],[0,0,0,1]]
|
// mat3d = move([2,3,4]); // Returns: [[1,0,0,2],[0,1,0,3],[0,0,1,4],[0,0,0,1]]
|
||||||
module move(v=[0,0,0], p, x=0, y=0, z=0) {
|
module move(v=[0,0,0], p, x=0, y=0, z=0) {
|
||||||
|
assert(!is_string(v),"Module form of `move()` does not accept string `v` arguments");
|
||||||
assert(is_undef(p), "Module form `move()` does not accept p= argument.");
|
assert(is_undef(p), "Module form `move()` does not accept p= argument.");
|
||||||
assert(is_vector(v) && (len(v)==3 || len(v)==2), "Invalid value for `v`")
|
assert(is_vector(v) && (len(v)==3 || len(v)==2), "Invalid value for `v`")
|
||||||
translate(point3d(v)+[x,y,z]) children();
|
translate(point3d(v)+[x,y,z]) children();
|
||||||
}
|
}
|
||||||
|
|
||||||
function move(v=[0,0,0], p=_NO_ARG, x=0, y=0, z=0) =
|
function move(v=[0,0,0], p=_NO_ARG, x=0, y=0, z=0) =
|
||||||
|
is_string(v) ? (
|
||||||
|
assert(is_vnf(p) || is_path(p),"String movements only work with point lists and VNFs")
|
||||||
|
let(
|
||||||
|
center = v=="centroid" ? centroid(p)
|
||||||
|
: v=="mean" ? mean(p)
|
||||||
|
: v=="box" ? mean(pointlist_bounds(p))
|
||||||
|
: assert(false,str("Unknown string movement ",v))
|
||||||
|
)
|
||||||
|
move(-center,p=p, x=x,y=y,z=z)
|
||||||
|
)
|
||||||
|
:
|
||||||
assert(is_vector(v) && (len(v)==3 || len(v)==2), "Invalid value for `v`")
|
assert(is_vector(v) && (len(v)==3 || len(v)==2), "Invalid value for `v`")
|
||||||
let(
|
let(
|
||||||
m = affine3d_translate(point3d(v)+[x,y,z])
|
m = affine3d_translate(point3d(v)+[x,y,z])
|
||||||
|
|
|
@ -584,8 +584,8 @@ module no_module() {
|
||||||
function _valstr(x) =
|
function _valstr(x) =
|
||||||
is_string(x)? str("\"",str_replace_char(x, "\"", "\\\""),"\"") :
|
is_string(x)? str("\"",str_replace_char(x, "\"", "\\\""),"\"") :
|
||||||
is_list(x)? str("[",str_join([for (xx=x) _valstr(xx)],","),"]") :
|
is_list(x)? str("[",str_join([for (xx=x) _valstr(xx)],","),"]") :
|
||||||
is_num(x) && x==floor(x)? fmt_int(x) :
|
is_num(x) && x==floor(x)? format_int(x) :
|
||||||
is_finite(x)? fmt_float(x,12) : x;
|
is_finite(x)? format_float(x,12) : x;
|
||||||
|
|
||||||
|
|
||||||
// Module: assert_approx()
|
// Module: assert_approx()
|
||||||
|
|
Loading…
Reference in a new issue