Force N parameters to n in most places

This commit is contained in:
Adrian Mariano 2022-03-13 21:40:55 -04:00
parent 8861464dbb
commit 7d6a2b593f
9 changed files with 132 additions and 130 deletions

View file

@ -595,23 +595,23 @@ module dashed_stroke(path, dashpat=[3,3], width=1, closed=false) {
// Function&Module: arc()
// Usage: 2D arc from 0º to `angle` degrees.
// arc(N, r|d=, angle);
// arc(n, r|d=, angle);
// Usage: 2D arc from START to END degrees.
// arc(N, r|d=, angle=[START,END])
// arc(n, r|d=, angle=[START,END])
// Usage: 2D arc from `start` to `start+angle` degrees.
// arc(N, r|d=, start=, angle=)
// arc(n, r|d=, start=, angle=)
// Usage: 2D circle segment by `width` and `thickness`, starting and ending on the X axis.
// arc(N, width=, thickness=)
// arc(n, width=, thickness=)
// Usage: Shortest 2D or 3D arc around centerpoint `cp`, starting at P0 and ending on the vector pointing from `cp` to `P1`.
// arc(N, cp=, points=[P0,P1], [long=], [cw=], [ccw=])
// arc(n, cp=, points=[P0,P1], [long=], [cw=], [ccw=])
// Usage: 2D or 3D arc, starting at `P0`, passing through `P1` and ending at `P2`.
// arc(N, points=[P0,P1,P2])
// arc(n, points=[P0,P1,P2])
// Topics: Paths (2D), Paths (3D), Shapes (2D), Path Generators
// Description:
// If called as a function, returns a 2D or 3D path forming an arc.
// If called as a module, creates a 2D arc polygon or pie slice shape.
// Arguments:
// N = Number of vertices to form the arc curve from.
// n = Number of vertices to form the arc curve from.
// r = Radius of the arc.
// angle = If a scalar, specifies the end angle in degrees (relative to start parameter). If a vector of two scalars, specifies start and end angles.
// ---
@ -629,7 +629,7 @@ module dashed_stroke(path, dashpat=[3,3], width=1, closed=false) {
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). (Module only) Default: `CENTER`
// spin = Rotate this many degrees around the Z axis after anchor. See [spin](attachments.scad#subsection-spin). (Module only) Default: `0`
// Examples(2D):
// arc(N=4, r=30, angle=30, wedge=true);
// arc(n=4, r=30, angle=30, wedge=true);
// arc(r=30, angle=30, wedge=true);
// arc(d=60, angle=30, wedge=true);
// arc(d=60, angle=120);
@ -646,17 +646,17 @@ module dashed_stroke(path, dashpat=[3,3], width=1, closed=false) {
// Example(FlatSpin,VPD=175):
// path = arc(points=[[0,30,0],[0,0,30],[30,0,0]]);
// stroke(path, dots=true, dots_color="blue");
function arc(N, r, angle, d, cp, points, width, thickness, start, wedge=false, long=false, cw=false, ccw=false, endpoint=true) =
function arc(n, r, angle, d, cp, points, width, thickness, start, wedge=false, long=false, cw=false, ccw=false, endpoint=true) =
assert(is_bool(endpoint))
!endpoint ? assert(!wedge, "endpoint cannot be false if wedge is true")
list_head(arc(u_add(N,1),r,angle,d,cp,points,width,thickness,start,wedge,long,cw,ccw,true)) :
assert(is_undef(N) || (is_integer(N) && N>=2), "Number of points must be an integer 2 or larger")
list_head(arc(u_add(n,1),r,angle,d,cp,points,width,thickness,start,wedge,long,cw,ccw,true)) :
assert(is_undef(n) || (is_integer(n) && n>=2), "Number of points must be an integer 2 or larger")
// First try for 2D arc specified by width and thickness
is_def(width) && is_def(thickness)? (
assert(!any_defined([r,cp,points]) && !any([cw,ccw,long]),"Conflicting or invalid parameters to arc")
assert(width>0, "Width must be postive")
assert(thickness>0, "Thickness must be positive")
arc(N,points=[[width/2,0], [0,thickness], [-width/2,0]],wedge=wedge)
arc(n,points=[[width/2,0], [0,thickness], [-width/2,0]],wedge=wedge)
) : is_def(angle)? (
let(
parmok = !any_defined([points,width,thickness]) &&
@ -673,8 +673,8 @@ function arc(N, r, angle, d, cp, points, width, thickness, start, wedge=false, l
assert(angle!=0, "Arc has zero length")
assert(is_def(r) && r>0, "Arc radius invalid")
let(
N = is_def(N) ? N : max(3, ceil(segs(r)*abs(angle)/360)),
arcpoints = [for(i=[0:N-1]) let(theta = start + i*angle/(N-1)) r*[cos(theta),sin(theta)]+cp],
n = is_def(n) ? n : max(3, ceil(segs(r)*abs(angle)/360)),
arcpoints = [for(i=[0:n-1]) let(theta = start + i*angle/(n-1)) r*[cos(theta),sin(theta)]+cp],
extra = wedge? [cp] : []
)
concat(extra,arcpoints)
@ -689,7 +689,7 @@ function arc(N, r, angle, d, cp, points, width, thickness, start, wedge=false, l
center2d = is_def(cp) ? project_plane(plane,cp) : undef,
points2d = project_plane(plane, points)
)
lift_plane(plane,arc(N,cp=center2d,points=points2d,wedge=wedge,long=long))
lift_plane(plane,arc(n,cp=center2d,points=points2d,wedge=wedge,long=long))
) : is_def(cp)? (
// Arc defined by center plus two points, will have radius defined by center and points[0]
// and extent defined by direction of point[1] from the center
@ -710,7 +710,7 @@ function arc(N, r, angle, d, cp, points, width, thickness, start, wedge=false, l
r=norm(v1),
final_angle = long || (ccw && dir<0) || (cw && dir>0) ? -dir*(360-angle) : dir*angle
)
arc(N,cp=cp,r=r,start=atan2(v1.y,v1.x),angle=final_angle,wedge=wedge)
arc(n,cp=cp,r=r,start=atan2(v1.y,v1.x),angle=final_angle,wedge=wedge)
) : (
// Final case is arc passing through three points, starting at point[0] and ending at point[3]
let(col = is_collinear(points[0],points[1],points[2]))
@ -724,15 +724,15 @@ function arc(N, r, angle, d, cp, points, width, thickness, start, wedge=false, l
theta_start = atan2(points[0].y-cp.y, points[0].x-cp.x),
theta_end = atan2(points[1].y-cp.y, points[1].x-cp.x),
angle = posmod(theta_end-theta_start, 360),
arcpts = arc(N,cp=cp,r=r,start=theta_start,angle=angle,wedge=wedge)
arcpts = arc(n,cp=cp,r=r,start=theta_start,angle=angle,wedge=wedge)
)
dir ? arcpts : reverse(arcpts)
);
module arc(N, r, angle, d, cp, points, width, thickness, start, wedge=false, anchor=CENTER, spin=0)
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);
path = arc(n=n, r=r, angle=angle, d=d, cp=cp, points=points, width=width, thickness=thickness, start=start, wedge=wedge);
attachable(anchor,spin, two_d=true, path=path, extent=false) {
polygon(path);
children();

View file

@ -492,7 +492,7 @@ function modang(x) =
// Function: rand_int()
// Usage:
// rand_int(minval, maxval, N, [seed]);
// rand_int(minval, maxval, n, [seed]);
// Description:
// Return a list of random integers in the range of minval to maxval, inclusive.
// Arguments:
@ -503,51 +503,51 @@ function modang(x) =
// Example:
// ints = rand_int(0,100,3);
// int = rand_int(-10,10,1)[0];
function rand_int(minval, maxval, N, seed=undef) =
assert( is_finite(minval+maxval+N) && (is_undef(seed) || is_finite(seed) ), "Input must be finite numbers.")
function rand_int(minval, maxval, n, seed=undef) =
assert( is_finite(minval+maxval+n) && (is_undef(seed) || is_finite(seed) ), "Input must be finite numbers.")
assert(maxval >= minval, "Max value cannot be smaller than minval")
let (rvect = is_def(seed) ? rands(minval,maxval+1,N,seed) : rands(minval,maxval+1,N))
let (rvect = is_def(seed) ? rands(minval,maxval+1,n,seed) : rands(minval,maxval+1,n))
[for(entry = rvect) floor(entry)];
// Function: random_points()
// Usage:
// points = random_points([N], [dim], [scale], [seed]);
// points = random_points([n], [dim], [scale], [seed]);
// See Also: random_polygon(), spherical_random_points()
// Topics: Random, Points
// Description:
// Generate `N` uniform random points of dimension `dim` with data ranging from -scale to +scale.
// Generate `n` uniform random points of dimension `dim` with data ranging from -scale to +scale.
// The `scale` may be a number, in which case the random data lies in a cube,
// or a vector with dimension `dim`, in which case each dimension has its own scale.
// Arguments:
// N = number of points to generate. Default: 1
// n = number of points to generate. Default: 1
// dim = dimension of the points. Default: 2
// scale = the scale of the point coordinates. Default: 1
// seed = an optional seed for the random generation.
function random_points(N, dim=2, scale=1, seed) =
assert( is_int(N) && N>=0, "The number of points should be a non-negative integer.")
function random_points(n, dim=2, scale=1, seed) =
assert( is_int(n) && n>=0, "The number of points should be a non-negative integer.")
assert( is_int(dim) && dim>=1, "The point dimensions should be an integer greater than 1.")
assert( is_finite(scale) || is_vector(scale,dim), "The scale should be a number or a vector with length equal to d.")
let(
rnds = is_undef(seed)
? rands(-1,1,N*dim)
: rands(-1,1,N*dim, seed) )
? rands(-1,1,n*dim)
: rands(-1,1,n*dim, seed) )
is_num(scale)
? scale*[for(i=[0:1:N-1]) [for(j=[0:dim-1]) rnds[i*dim+j] ] ]
: [for(i=[0:1:N-1]) [for(j=[0:dim-1]) scale[j]*rnds[i*dim+j] ] ];
? scale*[for(i=[0:1:n-1]) [for(j=[0:dim-1]) rnds[i*dim+j] ] ]
: [for(i=[0:1:n-1]) [for(j=[0:dim-1]) scale[j]*rnds[i*dim+j] ] ];
// Function: gaussian_rands()
// Usage:
// arr = gaussian_rands([N],[mean], [cov], [seed]);
// arr = gaussian_rands([n],[mean], [cov], [seed]);
// Description:
// Returns a random number or vector with a Gaussian/normal distribution.
// Arguments:
// N = the number of points to return. Default: 1
// n = the number of points to return. Default: 1
// mean = The average of the random value (a number or vector). Default: 0
// cov = covariance matrix of the random numbers, or variance in the 1D case. Default: 1
// seed = If given, sets the random number seed.
function gaussian_rands(N=1, mean=0, cov=1, seed=undef) =
function gaussian_rands(n=1, mean=0, cov=1, seed=undef) =
assert(is_num(mean) || is_vector(mean))
let(
dim = is_num(mean) ? 1 : len(mean)
@ -555,8 +555,8 @@ function gaussian_rands(N=1, mean=0, cov=1, seed=undef) =
assert((dim==1 && is_num(cov)) || is_matrix(cov,dim,dim),"mean and covariance matrix not compatible")
assert(is_undef(seed) || is_finite(seed))
let(
nums = is_undef(seed)? rands(0,1,dim*N*2) : rands(0,1,dim*N*2,seed),
rdata = [for (i = count(dim*N,0,2)) sqrt(-2*ln(nums[i]))*cos(360*nums[i+1])]
nums = is_undef(seed)? rands(0,1,dim*n*2) : rands(0,1,dim*n*2,seed),
rdata = [for (i = count(dim*n,0,2)) sqrt(-2*ln(nums[i]))*cos(360*nums[i+1])]
)
dim==1 ? add_scalar(sqrt(cov)*rdata,mean) :
assert(is_matrix_symmetric(cov),"Supplied covariance matrix is not symmetric")
@ -569,7 +569,7 @@ function gaussian_rands(N=1, mean=0, cov=1, seed=undef) =
// Function: spherical_random_points()
// Usage:
// points = spherical_random_points([N], [radius], [seed]);
// points = spherical_random_points([n], [radius], [seed]);
// See Also: random_polygon(), random_points()
// Topics: Random, Points
// Description:
@ -580,7 +580,7 @@ function gaussian_rands(N=1, mean=0, cov=1, seed=undef) =
// seed = an optional seed for the random generation.
// See https://mathworld.wolfram.com/SpherePointPicking.html
function spherical_random_points(N=1, radius=1, seed) =
function spherical_random_points(n=1, radius=1, seed) =
assert( is_int(n) && n>=1, "The number of points should be an integer greater than zero.")
assert( is_num(radius) && radius>0, "The radius should be a non-negative number.")
let( theta = is_undef(seed)
@ -619,9 +619,6 @@ function random_polygon(n=3,size=1, seed) =
// Section: GCD/GCF, LCM
// Function: gcd()

View file

@ -366,7 +366,7 @@ module path_extrude(path, convexity=10, clipsize=100) {
) rot(from=vec1,to=vec2)
]);
// This adds a rotation midway between each item on the list
interp = rot_resample(rotmats,N=2,method="count");
interp = rot_resample(rotmats,n=2,method="count");
epsilon = 0.0001; // Make segments ever so slightly too long so they overlap.
ptcount = len(path);
for (i = [0:1:ptcount-2]) {

View file

@ -895,7 +895,7 @@ function _path_join(paths,joint,k=0.5,i=0,result=[],relocate=true,closed=false)
// closed = true if the curve is closed, false otherwise. Default: false
//
// Example(2D): Basic examples illustrating flat, round, and pointed ends, on a finely sampled arc and a path made from 3 segments.
// arc = arc(points=[[1,1],[3,4],[6,3]],N=50);
// arc = arc(points=[[1,1],[3,4],[6,3]],n=50);
// path = [[0,0],[6,2],[9,7],[8,10]];
// xdistribute(spacing=10){
// offset_stroke(path, width = 2);
@ -927,12 +927,12 @@ function _path_join(paths,joint,k=0.5,i=0,result=[],relocate=true,closed=false)
// right(5)
// offset_stroke(path, start=os_flat(abs_angle=0), end=os_flat(abs_angle=0));
// Example(2D): With continuous sampling the end treatment can remove segments or extend the last segment linearly, as shown here. Again the left side uses relative angle flat ends and the right hand example uses absolute angle.
// arc = arc(points=[[4,0],[3,4],[6,3]],N=50);
// arc = arc(points=[[4,0],[3,4],[6,3]],n=50);
// offset_stroke(arc, start=os_flat(angle=45), end=os_flat(angle=45));
// right(5)
// offset_stroke(arc, start=os_flat(abs_angle=45), end=os_flat(abs_angle=45));
// Example(2D): The os_pointed() end treatment allows adjustment of the point tip, as shown here. The width is 2 so a location of 1 is at the edge.
// arc = arc(points=[[1,1],[3,4],[6,3]],N=50);
// arc = arc(points=[[1,1],[3,4],[6,3]],n=50);
// offset_stroke(arc, width=2, start=os_pointed(loc=1,dist=3),end=os_pointed(loc=1,dist=3));
// right(10)
// offset_stroke(arc, width=2, start=os_pointed(dist=4),end=os_pointed(dist=-1));
@ -940,7 +940,7 @@ function _path_join(paths,joint,k=0.5,i=0,result=[],relocate=true,closed=false)
// offset_stroke(arc, width=2, start=os_pointed(loc=2,dist=2),end=os_pointed(loc=.5,dist=-1));
// Example(2D): The os_round() end treatment adds roundovers to the end corners by specifying the `cut` parameter. In the first example, the cut parameter is the same at each corner. The bezier smoothness parameter `k` is given to allow a larger cut. In the second example, each corner is given a different roundover, including zero for no rounding at all. The red shows the same strokes without the roundover.
// $fn=36;
// arc = arc(points=[[1,1],[3,4],[6,3]],N=50);
// arc = arc(points=[[1,1],[3,4],[6,3]],n=50);
// path = [[0,0],[6,2],[9,7],[8,10]];
// offset_stroke(path, width=2, rounded=false,start=os_round(angle=-20, cut=0.4,k=.9), end=os_round(angle=-35, cut=0.4,k=.9));
// color("red")down(.1)offset_stroke(path, width=2, rounded=false,start=os_flat(-20), end=os_flat(-35));
@ -949,7 +949,7 @@ function _path_join(paths,joint,k=0.5,i=0,result=[],relocate=true,closed=false)
// color("red")down(.1)offset_stroke(arc, width=2, rounded=false, start=os_flat(-45), end=os_flat(20));
// }
// Example(2D): Negative cut values produce a flaring end. Note how the absolute angle aligns the ends of the first example withi the axes. In the second example positive and negative cut values are combined. Note also that very different cuts are needed at the start end to produce a similar looking flare.
// arc = arc(points=[[1,1],[3,4],[6,3]],N=50);
// arc = arc(points=[[1,1],[3,4],[6,3]],n=50);
// path = [[0,0],[6,2],[9,7],[8,10]];
// offset_stroke(path, width=2, rounded=false,start=os_round(cut=-1, abs_angle=90), end=os_round(cut=-0.5, abs_angle=0),$fn=36);
// right(10)
@ -1091,7 +1091,7 @@ function _stroke_end(width,left, right, spec) =
normal_dir = unit(normal_seg[1]-normal_seg[0]),
width_dir = sign(width[0]-width[1])
)
type == "round"? [arc(points=[right[0],normal_pt,left[0]],N=ceil(segs(width/2)/2)),1,1] :
type == "round"? [arc(points=[right[0],normal_pt,left[0]],n=ceil(segs(width/2)/2)),1,1] :
type == "pointed"? [[normal_pt],0,0] :
type == "shifted_point"? (
let(shiftedcenter = center + width_dir * parallel_dir * struct_val(spec, "loc"))
@ -1911,6 +1911,11 @@ function _rp_compute_patches(top, bot, rtop, rsides, ktop, ksides, concave) =
// This can help troubleshoot problems with your parameters. With the function form setting debug to true causes it to return [patches,vnf] where
// patches is a list of the bezier control points for the corner patches.
// .
// Note that rounded_prism() is not well suited to rounding shapes that have already been rounded, or that have many points.
// It works best when the top and bottom are polygons with well-defined corners. When the polygons have been rounded already,
// further rounding generates tiny bezier patches patches that can more easily
// interfere, giving rise to an invalid polyhedron. It's also slow because you get bezier patches for every corner in the model.
// .
// Arguments:
// bottom = 2d or 3d path describing bottom polygon
// top = 2d or 3d path describing top polygon (must be the same dimension as bottom)

View file

@ -482,7 +482,7 @@ function regular_ngon(n=6, r, d, or, od, ir, id, side, rounding=0, realign=false
a = 360 - i*360/n,
p = polar_to_xy(r-inset, a)
)
each arc(N=steps, cp=p, r=rounding, start=a+180/n, angle=-360/n)
each arc(n=steps, cp=p, r=rounding, start=a+180/n, angle=-360/n)
],
maxx_idx = max_index(column(path2,0)),
path3 = list_rotate(path2,maxx_idx)
@ -868,30 +868,30 @@ function trapezoid(h, w1, w2, angle, shift=0, chamfer=0, rounding=0, flip=false,
each (
let(i = 0)
rads[i] == 0? [base[i]] :
srads[i] > 0? arc(N=rounds[i]?undef:2, cp=base[i]+offs[i], angle=[angs[i], 90], r=rads[i]) :
flip? arc(N=rounds[i]?undef:2, cp=base[i]+offs[i], angle=[angs[i],-90], r=rads[i]) :
arc(N=rounds[i]?undef:2, cp=base[i]+offs[i], angle=[180+angs[i],90], r=rads[i])
srads[i] > 0? arc(n=rounds[i]?undef:2, cp=base[i]+offs[i], angle=[angs[i], 90], r=rads[i]) :
flip? arc(n=rounds[i]?undef:2, cp=base[i]+offs[i], angle=[angs[i],-90], r=rads[i]) :
arc(n=rounds[i]?undef:2, cp=base[i]+offs[i], angle=[180+angs[i],90], r=rads[i])
),
each (
let(i = 1)
rads[i] == 0? [base[i]] :
srads[i] > 0? arc(N=rounds[i]?undef:2, cp=base[i]+offs[i], angle=[90,180+angs[i]], r=rads[i]) :
flip? arc(N=rounds[i]?undef:2, cp=base[i]+offs[i], angle=[270,180+angs[i]], r=rads[i]) :
arc(N=rounds[i]?undef:2, cp=base[i]+offs[i], angle=[90,angs[i]], r=rads[i])
srads[i] > 0? arc(n=rounds[i]?undef:2, cp=base[i]+offs[i], angle=[90,180+angs[i]], r=rads[i]) :
flip? arc(n=rounds[i]?undef:2, cp=base[i]+offs[i], angle=[270,180+angs[i]], r=rads[i]) :
arc(n=rounds[i]?undef:2, cp=base[i]+offs[i], angle=[90,angs[i]], r=rads[i])
),
each (
let(i = 2)
rads[i] == 0? [base[i]] :
srads[i] > 0? arc(N=rounds[i]?undef:2, cp=base[i]+offs[i], angle=[180+angs[i],270], r=rads[i]) :
flip? arc(N=rounds[i]?undef:2, cp=base[i]+offs[i], angle=[180+angs[i],90], r=rads[i]) :
arc(N=rounds[i]?undef:2, cp=base[i]+offs[i], angle=[angs[i],-90], r=rads[i])
srads[i] > 0? arc(n=rounds[i]?undef:2, cp=base[i]+offs[i], angle=[180+angs[i],270], r=rads[i]) :
flip? arc(n=rounds[i]?undef:2, cp=base[i]+offs[i], angle=[180+angs[i],90], r=rads[i]) :
arc(n=rounds[i]?undef:2, cp=base[i]+offs[i], angle=[angs[i],-90], r=rads[i])
),
each (
let(i = 3)
rads[i] == 0? [base[i]] :
srads[i] > 0? arc(N=rounds[i]?undef:2, cp=base[i]+offs[i], angle=[-90,angs[i]], r=rads[i]) :
flip? arc(N=rounds[i]?undef:2, cp=base[i]+offs[i], angle=[90,angs[i]], r=rads[i]) :
arc(N=rounds[i]?undef:2, cp=base[i]+offs[i], angle=[270,180+angs[i]], r=rads[i])
srads[i] > 0? arc(n=rounds[i]?undef:2, cp=base[i]+offs[i], angle=[-90,angs[i]], r=rads[i]) :
flip? arc(n=rounds[i]?undef:2, cp=base[i]+offs[i], angle=[90,angs[i]], r=rads[i]) :
arc(n=rounds[i]?undef:2, cp=base[i]+offs[i], angle=[270,180+angs[i]], r=rads[i])
),
],
path = reverse(cpath)
@ -1309,12 +1309,12 @@ function glued_circles(r, spread=10, tangent=30, d, anchor=CENTER, spin=0) =
// outer curves. In the other case the inner curves are present and endpoint=false
// prevents point duplication.
path = tangent==0 ?
concat(arc(N=lobesegs+1, r=r, cp=-cp1, angle=[sa1,ea1]),
arc(N=lobesegs+1, r=r, cp=cp1, angle=[sa1+180,ea1+180]))
concat(arc(n=lobesegs+1, r=r, cp=-cp1, angle=[sa1,ea1]),
arc(n=lobesegs+1, r=r, cp=cp1, angle=[sa1+180,ea1+180]))
:
concat(arc(N=lobesegs, r=r, cp=-cp1, angle=[sa1,ea1], endpoint=false),
concat(arc(n=lobesegs, r=r, cp=-cp1, angle=[sa1,ea1], endpoint=false),
[for(theta=lerpn(ea2+180,ea2-subarc+180,arcsegs,endpoint=false)) r2*[cos(theta),sin(theta)] - cp2],
arc(N=lobesegs, r=r, cp=cp1, angle=[sa1+180,ea1+180], endpoint=false),
arc(n=lobesegs, r=r, cp=cp1, angle=[sa1+180,ea1+180], endpoint=false),
[for(theta=lerpn(ea2,ea2-subarc,arcsegs,endpoint=false)) r2*[cos(theta),sin(theta)] + cp2]),
maxx_idx = max_index(column(path,0)),
path2 = reverse_polygon(list_rotate(path,maxx_idx))
@ -1417,15 +1417,15 @@ module supershape(step=0.5,m1=4,m2=undef,n1,n2=undef,n3=undef,a=1,b=undef, r=und
// Function&Module: reuleaux_polygon()
// Usage: As Module
// reuleaux_polygon(N, r|d, ...);
// reuleaux_polygon(n, r|d, ...);
// Usage: As Function
// path = reuleaux_polygon(N, r|d, ...);
// path = reuleaux_polygon(n, r|d, ...);
// Topics: Shapes (2D), Paths (2D), Path Generators, Attachable
// See Also: regular_ngon(), pentagon(), hexagon(), octagon()
// Description:
// Creates a 2D Reuleaux Polygon; a constant width shape that is not circular. Uses "intersect" type anchoring.
// Arguments:
// N = Number of "sides" to the Reuleaux Polygon. Must be an odd positive number. Default: 3
// n = Number of "sides" to the Reuleaux Polygon. Must be an odd positive number. Default: 3
// r = Radius of the shape. Scale shape to fit in a circle of radius r.
// ---
// d = Diameter of the shape. Scale shape to fit in a circle of diameter d.
@ -1434,19 +1434,19 @@ module supershape(step=0.5,m1=4,m2=undef,n1,n2=undef,n3=undef,a=1,b=undef, r=und
// Extra Anchors:
// "tip0", "tip1", etc. = Each tip has an anchor, pointing outwards.
// Examples(2D):
// reuleaux_polygon(N=3, r=50);
// reuleaux_polygon(N=5, d=100);
// reuleaux_polygon(n=3, r=50);
// reuleaux_polygon(n=5, d=100);
// Examples(2D): Standard vector anchors are based on extents
// reuleaux_polygon(N=3, d=50) show_anchors(custom=false);
// reuleaux_polygon(n=3, d=50) show_anchors(custom=false);
// Examples(2D): Named anchors exist for the tips
// reuleaux_polygon(N=3, d=50) show_anchors(std=false);
module reuleaux_polygon(N=3, r, d, anchor=CENTER, spin=0) {
assert(N>=3 && (N%2)==1);
// reuleaux_polygon(n=3, d=50) show_anchors(std=false);
module reuleaux_polygon(n=3, r, d, anchor=CENTER, spin=0) {
assert(n>=3 && (n%2)==1);
r = get_radius(r=r, d=d, dflt=1);
path = reuleaux_polygon(N=N, r=r);
path = reuleaux_polygon(n=n, r=r);
anchors = [
for (i = [0:1:N-1]) let(
ca = 360 - i * 360/N,
for (i = [0:1:n-1]) let(
ca = 360 - i * 360/n,
cp = polar_to_xy(r, ca)
) named_anchor(str("tip",i), cp, unit(cp,BACK), 0),
];
@ -1457,23 +1457,23 @@ module reuleaux_polygon(N=3, r, d, anchor=CENTER, spin=0) {
}
function reuleaux_polygon(N=3, r, d, anchor=CENTER, spin=0) =
assert(N>=3 && (N%2)==1)
function reuleaux_polygon(n=3, r, d, anchor=CENTER, spin=0) =
assert(n>=3 && (n%2)==1)
let(
r = get_radius(r=r, d=d, dflt=1),
ssegs = max(3,ceil(segs(r)/N)),
slen = norm(polar_to_xy(r,0)-polar_to_xy(r,180-180/N)),
ssegs = max(3,ceil(segs(r)/n)),
slen = norm(polar_to_xy(r,0)-polar_to_xy(r,180-180/n)),
path = [
for (i = [0:1:N-1]) let(
ca = 180 - (i+0.5) * 360/N,
sa = ca + 180 + (90/N),
ea = ca + 180 - (90/N),
for (i = [0:1:n-1]) let(
ca = 180 - (i+0.5) * 360/n,
sa = ca + 180 + (90/n),
ea = ca + 180 - (90/n),
cp = polar_to_xy(r, ca)
) each arc(N=ssegs-1, r=slen, cp=cp, angle=[sa,ea], endpoint=false)
) each arc(n=ssegs-1, r=slen, cp=cp, angle=[sa,ea], endpoint=false)
],
anchors = [
for (i = [0:1:N-1]) let(
ca = 360 - i * 360/N,
for (i = [0:1:n-1]) let(
ca = 360 - i * 360/n,
cp = polar_to_xy(r, ca)
) named_anchor(str("tip",i), cp, unit(cp,BACK), 0),
]

View file

@ -746,11 +746,11 @@ module spiral_sweep(poly, h, r, turns=1, higbee, center, r1, r2, d, d1, d2, higb
// .
// Figure(3D,Big,VPR=[70,0,345],VPD=20,VPT=[5.5,10.8,-2.7],NoScales): This example shows how the shape, in this case the quadrilateral defined by `[[0, 0], [0, 1], [0.25, 1], [1, 0]]`, appears as the cross section of the swept polyhedron. The blue line shows the path. The normal vector to the shape is shown in black; it is based at the origin and points upwards in the Z direction. The sweep aligns this normal vector with the blue path tangent, which in this case, flips the shape around. Note that for a 2D path like this one, the Y direction in the shape is mapped to the Z direction in the sweep.
// tri= [[0, 0], [0, 1], [.25,1], [1, 0]];
// path = arc(r=5,N=81,angle=[-20,65]);
// path = arc(r=5,n=81,angle=[-20,65]);
// % path_sweep(tri,path);
// T = path_sweep(tri,path,transforms=true);
// color("red")for(i=[0:20:80]) stroke(apply(T[i],path3d(tri)),width=.1,closed=true);
// color("blue")stroke(path3d(arc(r=5,N=101,angle=[-20,80])),width=.1,endcap2="arrow2");
// color("blue")stroke(path3d(arc(r=5,n=101,angle=[-20,80])),width=.1,endcap2="arrow2");
// color("red")stroke([path3d(tri)],width=.1);
// stroke([CENTER,UP], width=.07,endcap2="arrow2",color="black");
// .
@ -763,11 +763,11 @@ module spiral_sweep(poly, h, r, turns=1, higbee, center, r1, r2, d, d1, d2, higb
// reverse the order of points in the path we get a different result:
// Figure(3D,Big,VPR=[70,0,20],VPD=20,VPT=[1.25,9.25,-2.65],NoScales): The same sweep operation with the path traveling in the opposite direction. Note that in order to line up the normal correctly, the shape is reversed compared to Figure 1, so the resulting sweep looks quite different.
// tri= [[0, 0], [0, 1], [.25,1], [1, 0]];
// path = reverse(arc(r=5,N=81,angle=[-20,65]));
// path = reverse(arc(r=5,n=81,angle=[-20,65]));
// % path_sweep(tri,path);
// T = path_sweep(tri,path,transforms=true);
// color("red")for(i=[0:20:80]) stroke(apply(T[i],path3d(tri)),width=.1,closed=true);
// color("blue")stroke(reverse(path3d(arc(r=5,N=101,angle=[-20-15,65]))),width=.1,endcap2="arrow2");
// color("blue")stroke(reverse(path3d(arc(r=5,n=101,angle=[-20-15,65]))),width=.1,endcap2="arrow2");
// color("red")stroke([path3d(tri)],width=.1);
// stroke([CENTER,UP], width=.07,endcap2="arrow2",color="black");
// Continues:
@ -778,11 +778,11 @@ module spiral_sweep(poly, h, r, turns=1, higbee, center, r1, r2, d, d1, d2, higb
// the cross sections in your polyhedron. If any of them intersect, the polyhedron will be invalid.
// Figure(3D,Big,VPR=[47,0,325],VPD=23,VPT=[6.8,4,-3.8],NoScales): We have scaled the path to an ellipse and show a large triangle as the shape. The triangle is sometimes bigger than the local radius of the path, leading to an invalid polyhedron, which you can identify because the red lines cross in the middle.
// tri= scale([4.5,2.5],[[0, 0], [0, 1], [1, 0]]);
// path = xscale(1.5,arc(r=5,N=81,angle=[-70,70]));
// path = xscale(1.5,arc(r=5,n=81,angle=[-70,70]));
// % path_sweep(tri,path);
// T = path_sweep(tri,path,transforms=true);
// color("red")for(i=[0:20:80]) stroke(apply(T[i],path3d(tri)),width=.1,closed=true);
// color("blue")stroke(path3d(xscale(1.5,arc(r=5,N=81,angle=[-70,80]))),width=.1,endcap2="arrow2");
// color("blue")stroke(path3d(xscale(1.5,arc(r=5,n=81,angle=[-70,80]))),width=.1,endcap2="arrow2");
// Continues:
// During the sweep operation the shape's normal vector aligns with the tangent vector of the path. Note that
// this leaves an ambiguity about how the shape is rotated as it sweeps along the path.
@ -791,11 +791,11 @@ module spiral_sweep(poly, h, r, turns=1, higbee, center, r1, r2, d, d1, d2, higb
// number of degrees to twist along the whole swept polyhedron. This produces a result like the one shown below.
// Figure(3D,Big,VPR=[66,0,14],VPD=20,VPT=[3.4,4.5,-0.8]): The shape twists as we sweep. Note that it still aligns the origin in the shape with the path, and still aligns the normal vector with the path tangent vector.
// tri= [[0, 0], [0, 1], [.25,1],[1, 0]];
// path = arc(r=5,N=81,angle=[-20,65]);
// path = arc(r=5,n=81,angle=[-20,65]);
// % path_sweep(tri,path,twist=-60);
// T = path_sweep(tri,path,transforms=true,twist=-60);
// color("red")for(i=[0:20:80]) stroke(apply(T[i],path3d(tri)),width=.1,closed=true);
// color("blue")stroke(path3d(arc(r=5,N=101,angle=[-20,80])),width=.1,endcap2="arrow2");
// color("blue")stroke(path3d(arc(r=5,n=101,angle=[-20,80])),width=.1,endcap2="arrow2");
// Continues:
// The `twist` argument adds the specified number of degrees of twist into the model, and it may be positive or
// negative. When `closed=true` the starting shape and ending shape must match to avoid a sudden extreme twist at the
@ -926,7 +926,7 @@ module spiral_sweep(poly, h, r, turns=1, higbee, center, r1, r2, d, d1, d2, higb
// cube(0.5); // Adding a small cube is not a problem with this valid model
// Example(Med,VPR=[16,0,100],VPT=[0.05,0.6,0.6],VPD=25,NoScales): Using the `profiles=true` option can help debug bad polyhedra such as this one. If any of the profiles intersect or cross each other, the polyhedron will be invalid. In this case, you can see these intersections in the middle of the shape, which may give insight into how to fix your shape. The profiles may also help you identify cases with a valid polyhedron where you have more profiles than needed to adequately define the shape.
// tri= scale([4.5,2.5],[[0, 0], [0, 1], [1, 0]]);
// path = left(4,xscale(1.5,arc(r=5,N=25,angle=[-70,70])));
// path = left(4,xscale(1.5,arc(r=5,n=25,angle=[-70,70])));
// path_sweep(tri,path,profiles=true,width=.1);
// Example(NoScales): This 3d arc produces a result that twists to an undefined angle. By default the incremental method sets the starting normal to UP, but the ending normal is unconstrained.
// ushape = [[-10, 0],[-10, 10],[ -7, 10],[ -7, 2],[ 7, 2],[ 7, 7],[ 10, 7],[ 10, 0]];
@ -1574,7 +1574,7 @@ function _smooth(data,len,closed=false,angle=false) =
// Function: rot_resample()
// Usage:
// rlist = rot_resample(rotlist, N, [method], [twist], [scale], [smoothlen], [long], [turns], [closed])
// rlist = rot_resample(rotlist, n, [method], [twist], [scale], [smoothlen], [long], [turns], [closed])
// Description:
// Takes as input a list of rotation matrices in 3d. Produces as output a resampled
// list of rotation operators (4x4 matrixes) suitable for use with sweep(). You can optionally apply twist to
@ -1593,11 +1593,11 @@ function _smooth(data,len,closed=false,angle=false) =
// .
// The default is to resample based on the length of the arc defined by each rotation operator. This produces
// uniform sampling over all of the transformations. It requires that each rotation has nonzero length.
// In this case N specifies the total number of samples. If you set method to "count" then N you get
// N samples for each transform. You can set N to a vector to vary the samples at each step.
// In this case n specifies the total number of samples. If you set method to "count" then you get
// n samples for each transform. You can set n to a vector to vary the samples at each step.
// Arguments:
// rotlist = list of rotation operators in 3d to resample
// N = Number of rotations to produce as output when method is "length" or number for each transformation if method is "count". Can be a vector when method is "count"
// n = Number of rotations to produce as output when method is "length" or number for each transformation if method is "count". Can be a vector when method is "count"
// --
// method = sampling method, either "length" or "count"
// twist = scalar or vector giving twist to add overall or at each rotation. Default: none
@ -1607,33 +1607,33 @@ function _smooth(data,len,closed=false,angle=false) =
// turns = add extra turns. If a scalar adds the turns to every rotation, or give a vector. Default: 0
// closed = if true then the rotation list is treated as closed. Default: false
// Example(3D): Resampling the arc from a compound rotation with translations thrown in.
// tran = rot_resample([ident(4), back(5)*up(4)*xrot(-10)*zrot(-20)*yrot(117,cp=[10,0,0])], N=25);
// tran = rot_resample([ident(4), back(5)*up(4)*xrot(-10)*zrot(-20)*yrot(117,cp=[10,0,0])], n=25);
// sweep(circle(r=1,$fn=3), tran);
// Example(3D): Applying a scale factor
// tran = rot_resample([ident(4), back(5)*up(4)*xrot(-10)*zrot(-20)*yrot(117,cp=[10,0,0])], N=25, scale=2);
// tran = rot_resample([ident(4), back(5)*up(4)*xrot(-10)*zrot(-20)*yrot(117,cp=[10,0,0])], n=25, scale=2);
// sweep(circle(r=1,$fn=3), tran);
// Example(3D): Applying twist
// tran = rot_resample([ident(4), back(5)*up(4)*xrot(-10)*zrot(-20)*yrot(117,cp=[10,0,0])], N=25, twist=60);
// tran = rot_resample([ident(4), back(5)*up(4)*xrot(-10)*zrot(-20)*yrot(117,cp=[10,0,0])], n=25, twist=60);
// sweep(circle(r=1,$fn=3), tran);
// Example(3D): Going the long way
// tran = rot_resample([ident(4), back(5)*up(4)*xrot(-10)*zrot(-20)*yrot(117,cp=[10,0,0])], N=25, long=true);
// tran = rot_resample([ident(4), back(5)*up(4)*xrot(-10)*zrot(-20)*yrot(117,cp=[10,0,0])], n=25, long=true);
// sweep(circle(r=1,$fn=3), tran);
// Example(3D): Getting transformations from turtle3d
// include<BOSL2/turtle3d.scad>
// tran=turtle3d(["arcsteps",1,"up", 10, "arczrot", 10,170],transforms=true);
// sweep(circle(r=1,$fn=3),rot_resample(tran, N=40));
// sweep(circle(r=1,$fn=3),rot_resample(tran, n=40));
// Example(3D): If you specify a larger angle in turtle you need to use the long argument
// include<BOSL2/turtle3d.scad>
// tran=turtle3d(["arcsteps",1,"up", 10, "arczrot", 10,270],transforms=true);
// sweep(circle(r=1,$fn=3),rot_resample(tran, N=40,long=true));
// sweep(circle(r=1,$fn=3),rot_resample(tran, n=40,long=true));
// Example(3D): And if the angle is over 360 you need to add turns to get the right result. Note long is false when the remaining angle after subtracting full turns is below 180:
// include<BOSL2/turtle3d.scad>
// tran=turtle3d(["arcsteps",1,"up", 10, "arczrot", 10,90+360],transforms=true);
// sweep(circle(r=1,$fn=3),rot_resample(tran, N=40,long=false,turns=1));
// sweep(circle(r=1,$fn=3),rot_resample(tran, n=40,long=false,turns=1));
// Example(3D): Here the remaining angle is 270, so long must be set to true
// include<BOSL2/turtle3d.scad>
// tran=turtle3d(["arcsteps",1,"up", 10, "arczrot", 10,270+360],transforms=true);
// sweep(circle(r=1,$fn=3),rot_resample(tran, N=40,long=true,turns=1));
// sweep(circle(r=1,$fn=3),rot_resample(tran, n=40,long=true,turns=1));
// Example(3D): Note the visible line at the scale transition
// include<BOSL2/turtle3d.scad>
// tran = turtle3d(["arcsteps",1,"arcup", 10, 90, "arcdown", 10, 90], transforms=true);
@ -1688,15 +1688,15 @@ function _smooth(data,len,closed=false,angle=false) =
// beltprofile)
// ];
// skin(belt,slices=0,closed=true);
function rot_resample(rotlist,N,twist,scale,smoothlen=1,long=false,turns=0,closed=false,method="length") =
function rot_resample(rotlist,n,twist,scale,smoothlen=1,long=false,turns=0,closed=false,method="length") =
assert(is_int(smoothlen) && smoothlen>0 && smoothlen%2==1, "smoothlen must be a positive odd integer")
assert(method=="length" || method=="count")
let(tcount = len(rotlist) + (closed?0:-1))
assert(method=="count" || is_int(N), "N must be an integer when method is \"length\"")
assert(is_int(N) || is_vector(N,tcount), str("N must be scalar or vector with length ",tcount))
assert(method=="count" || is_int(n), "n must be an integer when method is \"length\"")
assert(is_int(n) || is_vector(n,tcount), str("n must be scalar or vector with length ",tcount))
let(
count = method=="length" ? (closed ? N+1 : N)
: (is_vector(N) ? sum(N) : tcount*N)+1 //(closed?0:1)
count = method=="length" ? (closed ? n+1 : n)
: (is_vector(n) ? sum(n) : tcount*n)+1 //(closed?0:1)
)
assert(is_bool(long) || len(long)==tcount,str("Input long must be a scalar or have length ",tcount))
let(
@ -1717,8 +1717,8 @@ function rot_resample(rotlist,N,twist,scale,smoothlen=1,long=false,turns=0,close
totlen = last(cumlen),
stepsize = totlen/(count-1),
samples = method=="count"
? let( N = force_list(N,tcount))
[for(n=N) lerpn(0,1,n,endpoint=false)]
? let( n = force_list(n,tcount))
[for(N=n) lerpn(0,1,N,endpoint=false)]
:[for(i=idx(parms))
let(
remainder = cumlen[i] % stepsize,

View file

@ -38,14 +38,14 @@ test_turtle();
module test_arc() {
assert_approx(arc(N=8, d=100, angle=135, cp=[10,10]), [[60,10],[57.1941665154,26.5139530978],[49.0915741234,41.1744900929],[36.6016038258,52.3362099614],[21.1260466978,58.7463956091],[4.40177619483,59.6856104947],[-11.6941869559,55.0484433951],[-25.3553390593,45.3553390593]]);
assert_approx(arc(N=8, d=100, angle=135, cp=[10,10],endpoint=false), [[60,10],[57.8470167866,24.5142338627],[51.5734806151,37.778511651],[41.7196642082,48.6505226681],[29.1341716183,56.1939766256],[14.9008570165,59.7592363336],[0.245483899194,59.0392640202],[-13.5698368413,54.0960632174]]);
assert_approx(arc(N=8, d=100, angle=[45,225], cp=[10,10]), [[45.3553390593,45.3553390593],[26.5139530978,57.1941665154],[4.40177619483,59.6856104947],[-16.6016038258,52.3362099614],[-32.3362099614,36.6016038258],[-39.6856104947,15.5982238052],[-37.1941665154,-6.51395309776],[-25.3553390593,-25.3553390593]]);
assert_approx(arc(N=8, d=100, start=45, angle=135, cp=[10,10]), [[45.3553390593,45.3553390593],[31.6941869559,55.0484433951],[15.5982238052,59.6856104947],[-1.12604669782,58.7463956091],[-16.6016038258,52.3362099614],[-29.0915741234,41.1744900929],[-37.1941665154,26.5139530978],[-40,10]]);
assert_approx(arc(N=8, d=100, start=45, angle=-90, cp=[10,10]), [[45.3553390593,45.3553390593],[52.3362099614,36.6016038258],[57.1941665154,26.5139530978],[59.6856104947,15.5982238052],[59.6856104947,4.40177619483],[57.1941665154,-6.51395309776],[52.3362099614,-16.6016038258],[45.3553390593,-25.3553390593]]);
assert_approx(arc(N=8, width=100, thickness=30), [[50,-3.5527136788e-15],[39.5300788555,13.9348601124],[25.3202618476,24.0284558904],[8.71492362453,29.3258437015],[-8.71492362453,29.3258437015],[-25.3202618476,24.0284558904],[-39.5300788555,13.9348601124],[-50,-1.42108547152e-14]]);
assert_approx(arc(N=8, cp=[10,10], points=[[45,45],[-25,45]]), [[45,45],[36.3342442379,51.9107096148],[26.3479795075,56.7198412457],[15.5419588213,59.1862449514],[4.45804117867,59.1862449514],[-6.34797950747,56.7198412457],[-16.3342442379,51.9107096148],[-25,45]]);
assert_approx(arc(N=24, cp=[10,10], points=[[45,45],[-25,45]], long=true), [[45,45],[51.3889035257,37.146982612],[56.0464336973,28.1583574081],[58.7777575294,18.4101349813],[59.4686187624,8.31010126292],[58.0901174104,-1.71924090789],[54.6999187001,-11.2583458482],[49.4398408296,-19.9081753929],[42.5299224539,-27.3068913894],[34.2592180667,-33.1449920477],[24.9737063235,-37.1782589647],[15.0618171232,-39.2379732261],[4.93818287676,-39.2379732261],[-4.97370632349,-37.1782589647],[-14.2592180667,-33.1449920477],[-22.5299224539,-27.3068913894],[-29.4398408296,-19.9081753929],[-34.6999187001,-11.2583458482],[-38.0901174104,-1.71924090789],[-39.4686187624,8.31010126292],[-38.7777575294,18.4101349813],[-36.0464336973,28.1583574081],[-31.3889035257,37.146982612],[-25,45]]);
assert_approx(arc(n=8, d=100, angle=135, cp=[10,10]), [[60,10],[57.1941665154,26.5139530978],[49.0915741234,41.1744900929],[36.6016038258,52.3362099614],[21.1260466978,58.7463956091],[4.40177619483,59.6856104947],[-11.6941869559,55.0484433951],[-25.3553390593,45.3553390593]]);
assert_approx(arc(n=8, d=100, angle=135, cp=[10,10],endpoint=false), [[60,10],[57.8470167866,24.5142338627],[51.5734806151,37.778511651],[41.7196642082,48.6505226681],[29.1341716183,56.1939766256],[14.9008570165,59.7592363336],[0.245483899194,59.0392640202],[-13.5698368413,54.0960632174]]);
assert_approx(arc(n=8, d=100, angle=[45,225], cp=[10,10]), [[45.3553390593,45.3553390593],[26.5139530978,57.1941665154],[4.40177619483,59.6856104947],[-16.6016038258,52.3362099614],[-32.3362099614,36.6016038258],[-39.6856104947,15.5982238052],[-37.1941665154,-6.51395309776],[-25.3553390593,-25.3553390593]]);
assert_approx(arc(n=8, d=100, start=45, angle=135, cp=[10,10]), [[45.3553390593,45.3553390593],[31.6941869559,55.0484433951],[15.5982238052,59.6856104947],[-1.12604669782,58.7463956091],[-16.6016038258,52.3362099614],[-29.0915741234,41.1744900929],[-37.1941665154,26.5139530978],[-40,10]]);
assert_approx(arc(n=8, d=100, start=45, angle=-90, cp=[10,10]), [[45.3553390593,45.3553390593],[52.3362099614,36.6016038258],[57.1941665154,26.5139530978],[59.6856104947,15.5982238052],[59.6856104947,4.40177619483],[57.1941665154,-6.51395309776],[52.3362099614,-16.6016038258],[45.3553390593,-25.3553390593]]);
assert_approx(arc(n=8, width=100, thickness=30), [[50,-3.5527136788e-15],[39.5300788555,13.9348601124],[25.3202618476,24.0284558904],[8.71492362453,29.3258437015],[-8.71492362453,29.3258437015],[-25.3202618476,24.0284558904],[-39.5300788555,13.9348601124],[-50,-1.42108547152e-14]]);
assert_approx(arc(n=8, cp=[10,10], points=[[45,45],[-25,45]]), [[45,45],[36.3342442379,51.9107096148],[26.3479795075,56.7198412457],[15.5419588213,59.1862449514],[4.45804117867,59.1862449514],[-6.34797950747,56.7198412457],[-16.3342442379,51.9107096148],[-25,45]]);
assert_approx(arc(n=24, cp=[10,10], points=[[45,45],[-25,45]], long=true), [[45,45],[51.3889035257,37.146982612],[56.0464336973,28.1583574081],[58.7777575294,18.4101349813],[59.4686187624,8.31010126292],[58.0901174104,-1.71924090789],[54.6999187001,-11.2583458482],[49.4398408296,-19.9081753929],[42.5299224539,-27.3068913894],[34.2592180667,-33.1449920477],[24.9737063235,-37.1782589647],[15.0618171232,-39.2379732261],[4.93818287676,-39.2379732261],[-4.97370632349,-37.1782589647],[-14.2592180667,-33.1449920477],[-22.5299224539,-27.3068913894],[-29.4398408296,-19.9081753929],[-34.6999187001,-11.2583458482],[-38.0901174104,-1.71924090789],[-39.4686187624,8.31010126292],[-38.7777575294,18.4101349813],[-36.0464336973,28.1583574081],[-31.3889035257,37.146982612],[-25,45]]);
assert_approx(arc($fn=24, cp=[10,10], points=[[45,45],[-25,45]], long=true), [[45,45],[53.2421021636,34.0856928585],[58.1827254512,21.3324740498],[59.4446596304,7.71403542491],[56.9315576496,-5.72987274525],[50.8352916125,-17.9728253654],[41.6213035891,-28.0800887515],[29.9930697126,-35.2799863457],[16.8383906815,-39.0228152281],[3.16160931847,-39.0228152281],[-9.9930697126,-35.2799863457],[-21.6213035891,-28.0800887515],[-30.8352916125,-17.9728253654],[-36.9315576496,-5.72987274525],[-39.4446596304,7.71403542491],[-38.1827254512,21.3324740498],[-33.2421021636,34.0856928585],[-25,45]]);
}
test_arc();

View file

@ -119,9 +119,9 @@ test_supershape();
module test_reuleaux_polygon() {
$fn=36;
assert_approx(reuleaux_polygon(N=3, r=50),[[50,0],[45.5443467787,-6.93313174371],[40.449833029,-13.4113329645],[34.7625954562,-19.375936069],[28.5341385645,-24.7729246878],[21.8208682239,-29.5534228563],[14.6835808504,-33.6741376427],[7.18691282348,-37.0977512159],[-0.601244870218,-39.7932588011],[-8.61036146861,-41.7362494642],[-16.7679051715,-42.909127181],[-25,-43.3012701892],[-28.7764416072,-35.9759954373],[-31.8394715604,-28.3249164997],[-34.161350586,-20.417322732],[-35.7210513879,-12.324826528],[-36.5044490743,-4.12071478641],[-36.5044490743,4.12071478641],[-35.7210513879,12.324826528],[-34.161350586,20.417322732],[-31.8394715604,28.3249164997],[-28.7764416072,35.9759954373],[-25,43.3012701892],[-16.7679051715,42.909127181],[-8.61036146861,41.7362494642],[-0.601244870218,39.7932588011],[7.18691282348,37.0977512159],[14.6835808504,33.6741376427],[21.8208682239,29.5534228563],[28.5341385645,24.7729246878],[34.7625954562,19.375936069],[40.449833029,13.4113329645],[45.5443467787,6.93313174371]]);
assert_approx(reuleaux_polygon(N=3, d=100),[[50,0],[45.5443467787,-6.93313174371],[40.449833029,-13.4113329645],[34.7625954562,-19.375936069],[28.5341385645,-24.7729246878],[21.8208682239,-29.5534228563],[14.6835808504,-33.6741376427],[7.18691282348,-37.0977512159],[-0.601244870218,-39.7932588011],[-8.61036146861,-41.7362494642],[-16.7679051715,-42.909127181],[-25,-43.3012701892],[-28.7764416072,-35.9759954373],[-31.8394715604,-28.3249164997],[-34.161350586,-20.417322732],[-35.7210513879,-12.324826528],[-36.5044490743,-4.12071478641],[-36.5044490743,4.12071478641],[-35.7210513879,12.324826528],[-34.161350586,20.417322732],[-31.8394715604,28.3249164997],[-28.7764416072,35.9759954373],[-25,43.3012701892],[-16.7679051715,42.909127181],[-8.61036146861,41.7362494642],[-0.601244870218,39.7932588011],[7.18691282348,37.0977512159],[14.6835808504,33.6741376427],[21.8208682239,29.5534228563],[28.5341385645,24.7729246878],[34.7625954562,19.375936069],[40.449833029,13.4113329645],[45.5443467787,6.93313174371]]);
assert_approx(reuleaux_polygon(N=5, d=100),[[50,0],[47.0014382812,-7.98963912753],[43.2987621605,-15.6783253167],[38.921783409,-23.0041537871],[33.9057428858,-29.9081412755],[28.2910268,-36.3347009341],[22.122841544,-42.2320898832],[15.4508497187,-47.5528258148],[6.92564483387,-47.1699584219],[-1.53092011402,-46.0244388665],[-9.85075783633,-44.1254901984],[-17.9668818917,-41.4884016357],[-25.8139460215,-38.134405465],[-33.3287702792,-34.0905060913],[-40.4508497187,-29.3892626146],[-42.7211543799,-21.1629984251],[-44.2449228251,-12.7663422159],[-45.0098865668,-4.26689892573],[-45.0098865668,4.26689892573],[-44.2449228251,12.7663422159],[-42.7211543799,21.1629984251],[-40.4508497187,29.3892626146],[-33.3287702792,34.0905060913],[-25.8139460215,38.134405465],[-17.9668818917,41.4884016357],[-9.85075783633,44.1254901984],[-1.53092011402,46.0244388665],[6.92564483387,47.1699584219],[15.4508497187,47.5528258148],[22.122841544,42.2320898832],[28.2910268,36.3347009341],[33.9057428858,29.9081412755],[38.921783409,23.0041537871],[43.2987621605,15.6783253167],[47.0014382812,7.98963912753]]);
assert_approx(reuleaux_polygon(n=3, r=50),[[50,0],[45.5443467787,-6.93313174371],[40.449833029,-13.4113329645],[34.7625954562,-19.375936069],[28.5341385645,-24.7729246878],[21.8208682239,-29.5534228563],[14.6835808504,-33.6741376427],[7.18691282348,-37.0977512159],[-0.601244870218,-39.7932588011],[-8.61036146861,-41.7362494642],[-16.7679051715,-42.909127181],[-25,-43.3012701892],[-28.7764416072,-35.9759954373],[-31.8394715604,-28.3249164997],[-34.161350586,-20.417322732],[-35.7210513879,-12.324826528],[-36.5044490743,-4.12071478641],[-36.5044490743,4.12071478641],[-35.7210513879,12.324826528],[-34.161350586,20.417322732],[-31.8394715604,28.3249164997],[-28.7764416072,35.9759954373],[-25,43.3012701892],[-16.7679051715,42.909127181],[-8.61036146861,41.7362494642],[-0.601244870218,39.7932588011],[7.18691282348,37.0977512159],[14.6835808504,33.6741376427],[21.8208682239,29.5534228563],[28.5341385645,24.7729246878],[34.7625954562,19.375936069],[40.449833029,13.4113329645],[45.5443467787,6.93313174371]]);
assert_approx(reuleaux_polygon(n=3, d=100),[[50,0],[45.5443467787,-6.93313174371],[40.449833029,-13.4113329645],[34.7625954562,-19.375936069],[28.5341385645,-24.7729246878],[21.8208682239,-29.5534228563],[14.6835808504,-33.6741376427],[7.18691282348,-37.0977512159],[-0.601244870218,-39.7932588011],[-8.61036146861,-41.7362494642],[-16.7679051715,-42.909127181],[-25,-43.3012701892],[-28.7764416072,-35.9759954373],[-31.8394715604,-28.3249164997],[-34.161350586,-20.417322732],[-35.7210513879,-12.324826528],[-36.5044490743,-4.12071478641],[-36.5044490743,4.12071478641],[-35.7210513879,12.324826528],[-34.161350586,20.417322732],[-31.8394715604,28.3249164997],[-28.7764416072,35.9759954373],[-25,43.3012701892],[-16.7679051715,42.909127181],[-8.61036146861,41.7362494642],[-0.601244870218,39.7932588011],[7.18691282348,37.0977512159],[14.6835808504,33.6741376427],[21.8208682239,29.5534228563],[28.5341385645,24.7729246878],[34.7625954562,19.375936069],[40.449833029,13.4113329645],[45.5443467787,6.93313174371]]);
assert_approx(reuleaux_polygon(n=5, d=100),[[50,0],[47.0014382812,-7.98963912753],[43.2987621605,-15.6783253167],[38.921783409,-23.0041537871],[33.9057428858,-29.9081412755],[28.2910268,-36.3347009341],[22.122841544,-42.2320898832],[15.4508497187,-47.5528258148],[6.92564483387,-47.1699584219],[-1.53092011402,-46.0244388665],[-9.85075783633,-44.1254901984],[-17.9668818917,-41.4884016357],[-25.8139460215,-38.134405465],[-33.3287702792,-34.0905060913],[-40.4508497187,-29.3892626146],[-42.7211543799,-21.1629984251],[-44.2449228251,-12.7663422159],[-45.0098865668,-4.26689892573],[-45.0098865668,4.26689892573],[-44.2449228251,12.7663422159],[-42.7211543799,21.1629984251],[-40.4508497187,29.3892626146],[-33.3287702792,34.0905060913],[-25.8139460215,38.134405465],[-17.9668818917,41.4884016357],[-9.85075783633,44.1254901984],[-1.53092011402,46.0244388665],[6.92564483387,47.1699584219],[15.4508497187,47.5528258148],[22.122841544,42.2320898832],[28.2910268,36.3347009341],[33.9057428858,29.9081412755],[38.921783409,23.0041537871],[43.2987621605,15.6783253167],[47.0014382812,7.98963912753]]);
}
test_reuleaux_polygon();

View file

@ -823,8 +823,8 @@ module ball_screw_rod(
depth = ball_diam * (1-cos(ball_arc/2))/2;
cpy = ball_diam/2/pitch*cos(ball_arc/2);
profile = [
each arc(N=n, d=ball_diam/pitch, cp=[-0.5,cpy], start=270, angle=ball_arc/2),
each arc(N=n, d=ball_diam/pitch, cp=[+0.5,cpy], start=270-ball_arc/2, angle=ball_arc/2)
each arc(n=n, d=ball_diam/pitch, cp=[-0.5,cpy], start=270, angle=ball_arc/2),
each arc(n=n, d=ball_diam/pitch, cp=[+0.5,cpy], start=270-ball_arc/2, angle=ball_arc/2)
];
generic_threaded_rod(
d=d, l=l, pitch=pitch,