mirror of
https://github.com/BelfrySCAD/BOSL2.git
synced 2025-12-09 15:29:09 +00:00
expand glued_circles to different size circles
This commit is contained in:
parent
5408a36ef9
commit
584635b4f3
3 changed files with 279 additions and 4 deletions
|
|
@ -697,8 +697,10 @@ module dashed_stroke(path, dashpat=[3,3], width=1, closed=false, fit=true, round
|
||||||
// arc(...) [ATTACHMENTS];
|
// arc(...) [ATTACHMENTS];
|
||||||
// Description:
|
// Description:
|
||||||
// If called as a function, returns a 2D or 3D path forming an arc. Numerous methods are available to specify the arc as listed in the Arguments section.
|
// If called as a function, returns a 2D or 3D path forming an arc. Numerous methods are available to specify the arc as listed in the Arguments section.
|
||||||
// If `wedge` is true, the centerpoint of the arc appears as the first point in the result.
|
// If called as a module, the arc must be 2D and the module creates the segment of the circle obtained by adding
|
||||||
// If called as a module, the arc must be 2D and the module creates the 2D arc polygon or pie slice shape.
|
// the closing segment to the arc.
|
||||||
|
// If `wedge` is true, the centerpoint of the arc appears as the first point in the result, which is now a sector of a circle.
|
||||||
|
// The module produces the sector of the circle, or pie shape, bounded by the arc.
|
||||||
// .
|
// .
|
||||||
// If `endpoint=false`, which is only accepted by the functional form, then the arc stops one step before the final point.
|
// If `endpoint=false`, which is only accepted by the functional form, then the arc stops one step before the final point.
|
||||||
// The `rounding` parameter, which is permitted only when `wedge=true`, applies specified radius roundings at each of the corners, with `rounding[0]` giving
|
// The `rounding` parameter, which is permitted only when `wedge=true`, applies specified radius roundings at each of the corners, with `rounding[0]` giving
|
||||||
|
|
|
||||||
|
|
@ -1552,7 +1552,10 @@ function c_norm(z) = norm_fro(z);
|
||||||
// coefficients are real numbers. If real is true, then returns only the
|
// coefficients are real numbers. If real is true, then returns only the
|
||||||
// real roots. Otherwise returns a pair of complex values. This method
|
// real roots. Otherwise returns a pair of complex values. This method
|
||||||
// may be more reliable than the general root finder at distinguishing
|
// may be more reliable than the general root finder at distinguishing
|
||||||
// real roots from complex roots.
|
// real roots from complex roots. If the input is a linear equation the
|
||||||
|
// function returns a single root, and it returns the empty list when no
|
||||||
|
// appropriate roots exist (such as when all the roots are complex and real=true).
|
||||||
|
|
||||||
// Algorithm from: https://people.csail.mit.edu/bkph/articles/Quadratics.pdf
|
// Algorithm from: https://people.csail.mit.edu/bkph/articles/Quadratics.pdf
|
||||||
function quadratic_roots(a,b,c,real=false) =
|
function quadratic_roots(a,b,c,real=false) =
|
||||||
real ? [for(root = quadratic_roots(a,b,c,real=false)) if (root.y==0) root.x]
|
real ? [for(root = quadratic_roots(a,b,c,real=false)) if (root.y==0) root.x]
|
||||||
|
|
@ -1561,7 +1564,8 @@ function quadratic_roots(a,b,c,real=false) =
|
||||||
assert(is_num(a) && is_num(b) && is_num(c))
|
assert(is_num(a) && is_num(b) && is_num(c))
|
||||||
assert(a!=0 || b!=0 || c!=0, "\nQuadratic must have a nonzero coefficient.")
|
assert(a!=0 || b!=0 || c!=0, "\nQuadratic must have a nonzero coefficient.")
|
||||||
a==0 && b==0 ? [] : // No solutions
|
a==0 && b==0 ? [] : // No solutions
|
||||||
a==0 ? [[-c/b,0]] :
|
a==0 ? [[-c/b,0]] : // linear case, only one root
|
||||||
|
b==0 && c==0 ? [[0,0],[0,0]] : // a*x^2=0, zero is a double root
|
||||||
let(
|
let(
|
||||||
descrim = b*b-4*a*c,
|
descrim = b*b-4*a*c,
|
||||||
sqrt_des = sqrt(abs(descrim))
|
sqrt_des = sqrt(abs(descrim))
|
||||||
|
|
|
||||||
269
shapes2d.scad
269
shapes2d.scad
|
|
@ -1726,12 +1726,281 @@ function ring(n,ring_width,r,r1,r2,angle,d,d1,d2,cp,points,corner, width,thickne
|
||||||
) new_r>r_actual ? concat(arc2, reverse(arc1)) : concat(arc1,reverse(arc2));
|
) new_r>r_actual ? concat(arc2, reverse(arc1)) : concat(arc1,reverse(arc2));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Function&Module: glued_circles()
|
// Function&Module: glued_circles()
|
||||||
// Synopsis: Creates a shape of two circles joined by a curved waist.
|
// Synopsis: Creates a shape of two circles joined by a curved waist.
|
||||||
// SynTags: Geom, Path
|
// SynTags: Geom, Path
|
||||||
// Topics: Shapes (2D), Paths (2D), Path Generators, Attachable
|
// Topics: Shapes (2D), Paths (2D), Path Generators, Attachable
|
||||||
// See Also: circle(), ellipse(), egg(), keyhole()
|
// See Also: circle(), ellipse(), egg(), keyhole()
|
||||||
// Usage: As Module
|
// Usage: As Module
|
||||||
|
// glued_circles(r/d=, [spread], [r1=/d1=], [r2=/d2=], [tangent=], [bulge=], [width=], [blendR=/blendD=], anchor=, spin=) [ATTACHMENTS];
|
||||||
|
// Usage: As Function
|
||||||
|
// path = glued_circles(r/d=, [spread], [r1=/d1=], [r2=/d2=], [tangent=], [bulge=], [width=], [blendR=/blendD=], anchor=, spin=) [ATTACHMENTS];
|
||||||
|
// Description:
|
||||||
|
// Computes a shape created by joining two circles with arcs. The arcs can join the circles to create a convex, egg shape
|
||||||
|
// or they can join the circles to create a concave shape. The circles being joined are permitted to overlap each other.
|
||||||
|
// When called a function returns the path describing shape with its first point on the X+ axis. This module uses "hull" style anchoring.
|
||||||
|
// When the circles are different sizes, the circle on the left has radius `r1` and the right hand circle has radius `r2`.
|
||||||
|
// .
|
||||||
|
// The joining arcs can be specified in four different ways. You can simply specify the radius of the arc using `blendR=` or `blendD=`.
|
||||||
|
// In this case a positive radius results in a convex shape and a negative radius results in a concave shape. A forbidden radius range exists
|
||||||
|
// where the requested configuration is impossible; the exact bounds of this range depend on the specific geometry.
|
||||||
|
// When `abs(blendR)` is very large the connection will be nearly a straight line.
|
||||||
|
// .
|
||||||
|
// You can specify the angle of the tangent line at the point where the blending arc meets the left hand circle. This angle is
|
||||||
|
// measured between the tangent line and the X- axis, so an angle of zero gives a horizontal tangent, which will produces a straight
|
||||||
|
// joining "arc" if the circles are the same size. A positive angle will rotate the tangent point to the right around the circle
|
||||||
|
// and a negative one will rotate it around the left. When the tangent angle approaches -90 the shape approaches a circle that covers the
|
||||||
|
// two circles being joined. The degenerate case of `tangent=-90` is not permitted. A maximum legal tangent angle exists that depends on
|
||||||
|
// the geometry.
|
||||||
|
// .
|
||||||
|
// You can specify the `bulge=` parameter, which measures how the blending arc deviates from a straight line. A positive value means
|
||||||
|
// it deviates by the specified distance to create a convex, bulging shape. A negative value means it deviates by the specified distance
|
||||||
|
// to create a concave shape. A value of zero produces a flat connection.
|
||||||
|
// .
|
||||||
|
// Finally you can give `width=`. When `width` is smaller than either circle diameter it specifies the width of the waist of the shape (the
|
||||||
|
// narrowest point). In this case the shape is concave. When `width` is larger than either circle diameter it specifies the maximum width of
|
||||||
|
// shape. In this case the shape is convex. The width parameter cannot be in between the diameters of the two circles.
|
||||||
|
// Figure(2D,Med,NoScales): This figure shows width and bulge on a concave shape, when width is smaller than the smallest circle or bulge is negative. The black line shows the flat connection between the two circles, which is the bulge=0 case.
|
||||||
|
// r1=25;
|
||||||
|
// r2=15;
|
||||||
|
// s=35;
|
||||||
|
// h=7;
|
||||||
|
// $fa=5;$fs=1;
|
||||||
|
// path = glued_circles(r1=r1,r2=r2,spread=s, bulge=-h);
|
||||||
|
// pathflat = glued_circles(r1=r1,r2=r2,spread=s, bulge=0);
|
||||||
|
// stroke(pathflat,width=.5,color="black");
|
||||||
|
// stroke(path,width=.5);
|
||||||
|
// rr=_gs_indent_R(r1,r2,s,h);
|
||||||
|
// pts=circle_circle_intersection( abs(r1+rr),[-s/2,0], abs(r2+rr), [s/2,0]);
|
||||||
|
// cp = pts[rr<0?1:0];
|
||||||
|
// tan_pts = circle_circle_tangents(r1,[-s/2,0],r2,[s/2,0])[0];
|
||||||
|
// dir = unit(zrot(-90,tan_pts[1]-tan_pts[0]));
|
||||||
|
// stroke(tan_pts, width=.1, color="black");
|
||||||
|
// isect = line_intersection([cp,cp+dir], tan_pts, LINE, LINE);
|
||||||
|
// stroke([isect, cp+rr*dir], endcaps="arrow2", width=.5, color="blue");
|
||||||
|
// left(2)back(15)color("blue")text("bulge < 0", size=4,anchor=RIGHT);
|
||||||
|
// width=11.6;
|
||||||
|
// color("green"){
|
||||||
|
// stroke([[cp.x,-width],[cp.x,width]], endcaps="arrow2", width=.5);
|
||||||
|
// fwd(4)right(cp.x+2)text("width", size=4, anchor=LEFT);
|
||||||
|
// }
|
||||||
|
// Figure(2D,Med,NoScales): This figure shows width and bulge on a convexe shape, when width is larger than the largest circle or bulge is positive. The black line shows the flat connection between the two circles, which is the bulge=0 case.
|
||||||
|
// r1=25;
|
||||||
|
// r2=15;
|
||||||
|
// s=35;
|
||||||
|
// h=-5.5;
|
||||||
|
// $fa=5;$fs=1;
|
||||||
|
// path = glued_circles(r1=r1,r2=r2,spread=s, bulge=-h);
|
||||||
|
// pathflat = glued_circles(r1=r1,r2=r2,spread=s, bulge=0);
|
||||||
|
// stroke(pathflat,width=.5,color="black");
|
||||||
|
// stroke(path,width=.5);
|
||||||
|
// rr=_gs_indent_R(r1,r2,s,h);
|
||||||
|
// pts=circle_circle_intersection( abs(r1+rr),[-s/2,0], abs(r2+rr), [s/2,0]);
|
||||||
|
// cp = pts[rr<0?1:0];
|
||||||
|
// tan_pts = circle_circle_tangents(r1,[-s/2,0],r2,[s/2,0])[0];
|
||||||
|
// dir = unit(zrot(-90,tan_pts[1]-tan_pts[0]));
|
||||||
|
// stroke(tan_pts, width=.1, color="black");
|
||||||
|
// isect = line_intersection([cp,cp+dir], tan_pts, LINE, LINE);
|
||||||
|
// stroke([isect, cp+rr*dir], endcaps="arrow2", width=.5, color="blue");
|
||||||
|
// left(3.2)back(12)color("blue")text("bulge > 0", size=4,anchor=LEFT);
|
||||||
|
// width=27;
|
||||||
|
// color("green"){
|
||||||
|
// stroke([[cp.x,-width],[cp.x,width]], endcaps="arrow2", width=.5);
|
||||||
|
// fwd(4)right(cp.x-2)text("width", size=4, anchor=RIGHT);
|
||||||
|
// }
|
||||||
|
// Arguments:
|
||||||
|
// r = The radius or diameter of the end circles.
|
||||||
|
// spread = The distance between the centers of the end circles. Default: 10
|
||||||
|
// ---
|
||||||
|
// tangent = The angle in degrees of the tangent point for the joining arcs, measured away from the X- axis, a positive or negative value. Default: 30
|
||||||
|
// bulge = Deviation of the blending arc from a straight line connection, positive for a convex shape or negative for a concave shape.
|
||||||
|
// blendR / blendD = The radius or diameter of the blending arc, a positive for a convex shape, negative for a concave shape.
|
||||||
|
// width = width of the narrowest or widest point of the shape. A positive value.
|
||||||
|
// ---
|
||||||
|
// d = The diameter of the end circles.
|
||||||
|
// r1 / d1 = Radius or diameter of left circle.
|
||||||
|
// r2 / d2 = Radius or diameter of right circle.
|
||||||
|
// 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`
|
||||||
|
// Examples(2D):
|
||||||
|
// glued_circles(r=15, spread=40, tangent=45);
|
||||||
|
// glued_circles(d=30, spread=30, tangent=30);
|
||||||
|
// glued_circles(d=30, spread=30, tangent=15);
|
||||||
|
// glued_circles(d=30, spread=30, tangent=-30);
|
||||||
|
// Example(2D): Called as Function
|
||||||
|
// stroke(closed=true, glued_circles(r=15, spread=40, tangent=45));
|
||||||
|
// Example(2D): Circles with different sizes
|
||||||
|
// glued_circles(r1=15, r2=25, spread=40, tangent=30);
|
||||||
|
// Example(2D): Setting negative bulge value
|
||||||
|
// $fa=1;$fs=1;
|
||||||
|
// glued_circles(r1=15, r2=25, spread=40, bulge=-4);
|
||||||
|
// Example(2D): Setting positive bulge value
|
||||||
|
// $fa=1;$fs=1;
|
||||||
|
// glued_circles(r1=15, r2=25, spread=40, bulge=4);
|
||||||
|
// Example(2D): Zero bulge gives a flat connection
|
||||||
|
// glued_circles(r1=15, r2=25, spread=40, bulge=0);
|
||||||
|
// Example(2D): Specifying negative blending radius
|
||||||
|
// $fa=1;$fs=1;
|
||||||
|
// glued_circles(r1=25, r2=10, spread=40, blendR=-15);
|
||||||
|
// Example(2D): Giving positive blending radius
|
||||||
|
// $fa=1;$fs=1;
|
||||||
|
// glued_circles(r1=25, r2=10, spread=40, blendR=45);
|
||||||
|
// Example(2D): Overlapping circles
|
||||||
|
// $fa=1;$fs=1;
|
||||||
|
// glued_circles(r1=25, r2=20, spread=25, blendR=-4);
|
||||||
|
// Example(2D): Giving a small width
|
||||||
|
// glued_circles(r1=25, r2=10, spread=40, width=8);
|
||||||
|
// Example(2D): Giving a large width
|
||||||
|
// $fs=1;$fa=1;
|
||||||
|
// glued_circles(r1=25, r2=10, spread=40, width=58);
|
||||||
|
// Example(2D): Largest possible concave width is the diameter of the smaller circle
|
||||||
|
// glued_circles(r1=25, r2=10, spread=40, width=20);
|
||||||
|
// Example(2D): Smallest possible convex width is the diameter of the larger circle
|
||||||
|
// glued_circles(r1=25, r2=10, spread=40, width=50);
|
||||||
|
|
||||||
|
function glued_circles(r,spread=10, tangent, r1,r2,d,d1,d2, bulge, blendR,blendD, width, anchor=CENTER, spin=0) =
|
||||||
|
let(
|
||||||
|
r1 = get_radius(r=r,r1=r1,d=d,d1=d1),
|
||||||
|
r2 = get_radius(r=r,r2=r2,d=d,d2=d2),
|
||||||
|
blendR = get_radius(r=blendR, d=blendD)
|
||||||
|
)
|
||||||
|
assert(num_defined([tangent,bulge,blendR,width])<=1, "Can define at most one of tangent, bulge, width, and blendR/blendD")
|
||||||
|
assert(spread>abs(r1-r2), "Spread is too small: one circle is inside the other one")
|
||||||
|
let(
|
||||||
|
tangent = num_defined([tangent,bulge,blendR,width])==0 ? 30 : tangent,
|
||||||
|
cp1 = [-spread/2,0],
|
||||||
|
cp2 = [spread/2,0],
|
||||||
|
blendR = is_def(blendR) ? let(
|
||||||
|
max_indent = spread<=r1+r2 ? 0 : -_gs_waist_R(r1,r2,spread,0),
|
||||||
|
max_bulge = (r1+r2+spread)/2
|
||||||
|
)
|
||||||
|
assert(blendR>max_bulge || blendR<max_indent,
|
||||||
|
str("For this geometry blendR must be smaller than ",max_indent," or larger than ",max_bulge," but was ",blendR))
|
||||||
|
-blendR
|
||||||
|
: is_def(tangent) ? gs_get_tangent_R(r1,r2,spread,tangent)
|
||||||
|
: is_def(width) ? let(
|
||||||
|
pts = circle_circle_intersection(r1,cp1,r2,cp2),
|
||||||
|
minwidth = len(pts)==0 ? 0 : 2*pts[0].y
|
||||||
|
)
|
||||||
|
assert(width>=minwidth, str("For this geometry must have width >= ",minwidth," but width is ",width))
|
||||||
|
assert(width <= 2*min(r1,r2) || width >= 2*max(r1,r2),"The width parameter cannot be between 2*r1 and 2*r2")
|
||||||
|
let( fact=width>=2*max(r1,r2) ? -1 : 1)
|
||||||
|
fact*_gs_waist_R(fact*r1,fact*r2,spread,fact*width)
|
||||||
|
: _gs_indent_R(r1,r2,spread,-bulge),
|
||||||
|
cp_blend = is_finite(blendR) ?
|
||||||
|
let(
|
||||||
|
pts=circle_circle_intersection(abs(r1+blendR), cp1, abs(r2+blendR), cp2)
|
||||||
|
)
|
||||||
|
pts[blendR<0?0:1]
|
||||||
|
: undef,
|
||||||
|
pts = is_finite(blendR) ?
|
||||||
|
let(
|
||||||
|
result = [ cp1 + sign(blendR)*r1*unit(cp_blend-cp1),
|
||||||
|
cp2 + sign(blendR)*r2*unit(cp_blend-cp2)]
|
||||||
|
)
|
||||||
|
result
|
||||||
|
: let(
|
||||||
|
tan_pts = circle_circle_tangents(r1,cp1,r2,cp2)
|
||||||
|
)
|
||||||
|
tan_pts[1],
|
||||||
|
botpath = [
|
||||||
|
each arc(r=r2, cp=cp2, points=[right(r2,cp2),pts[1]],endpoint=false),
|
||||||
|
if (is_finite(blendR))
|
||||||
|
each arc(r=r2, cp=cp_blend, points=reverse(pts),endpoint=false)
|
||||||
|
else
|
||||||
|
pts[1],
|
||||||
|
each arc(r=r1, cp=cp1, points=[pts[0],left(r1,cp1)], endpoint=false)],
|
||||||
|
toppath = yflip(reverse(botpath)),
|
||||||
|
path = [each botpath, left(r1,cp1), each toppath]
|
||||||
|
)
|
||||||
|
reorient(anchor,spin, two_d=true, path=path, extent=true, p=path);
|
||||||
|
|
||||||
|
|
||||||
|
module glued_circles(r,spread=10, tangent, r1,r2,d,d1,d2, bulge, blendR,blendD, width, anchor=CENTER, spin=0)
|
||||||
|
{
|
||||||
|
path = glued_circles(r=r, spread=spread, tangent=tangent, r1=r1, r2=r2, d=d, d1=d1, d2=d2,
|
||||||
|
bulge=bulge, blendR=blendR, blendD=blendD,width=width);
|
||||||
|
attachable(anchor,spin, two_d=true, path=path, extent=true) {
|
||||||
|
polygon(path);
|
||||||
|
children();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function _gs_waist_R(r1,r2,s,waist) =
|
||||||
|
let(
|
||||||
|
A = (r1^2-r2^2)/2/s+s/2,
|
||||||
|
B = (r1-r2)/s,
|
||||||
|
coefs = [B^2,
|
||||||
|
2*A*B-2*r1+waist,
|
||||||
|
A^2+(waist/2)^2 - r1^2],
|
||||||
|
rts = waist<0 && approx(waist, 2*min(r1,r2))
|
||||||
|
? [-coefs[1]/2/coefs[0]]
|
||||||
|
: quadratic_roots(coefs,real=true)
|
||||||
|
)
|
||||||
|
min(rts);
|
||||||
|
|
||||||
|
function gs_get_tangent_R(r1,r2,s,ang) =
|
||||||
|
let(
|
||||||
|
pts = circle_circle_intersection(r1,[-s/2,0],r2,[s/2,0]),
|
||||||
|
minang = len(pts)==0 ? let( minr=_gs_waist_R(r1,r2,s,0),
|
||||||
|
pts=circle_circle_intersection(r1+minr,[-s/2,0], r2+minr, [s/2,0]))
|
||||||
|
atan2(pts[0].y, pts[0].x+s/2)
|
||||||
|
: atan2(pts[0].y, pts[0].x+s/2),
|
||||||
|
dummy = assert(ang>-90 && ang<90-minang,
|
||||||
|
str("Tangent angle must be between -90 and ", 90-minang, " for this geometry but was ",ang)),
|
||||||
|
A = (r1^2-r2^2)/2/s+s/2,
|
||||||
|
B = (r1-r2)/s,
|
||||||
|
flatang = acos(B)
|
||||||
|
)
|
||||||
|
approx(90-ang,flatang,eps=1e-3) ? echo("force")INF
|
||||||
|
:
|
||||||
|
let(
|
||||||
|
alpha = 90-ang > flatang ? 90+ang : 90-ang,
|
||||||
|
rts = quadratic_roots(B^2-cos(alpha)^2,
|
||||||
|
2*A*B-2*cos(alpha)^2*r1,
|
||||||
|
A^2-cos(alpha)^2*r1^2,real=true)
|
||||||
|
)
|
||||||
|
90-ang>flatang ? alpha>=90 ? rts[0] : rts[1]
|
||||||
|
: alpha<=90 ? rts[0] : rts[1];
|
||||||
|
|
||||||
|
|
||||||
|
function _gs_indent_R(r1,r2,s,h) =
|
||||||
|
let(
|
||||||
|
tan_pts = circle_circle_tangents(r1,[-s/2,0],r2,[s/2,0])[0],
|
||||||
|
circ_int = circle_circle_intersection(r1,[-s/2,0],r2,[s/2,0]),
|
||||||
|
minR = h<0 ? -2500 : len(circ_int)==0 ? _gs_waist_R(r1,r2,s,0) : 0,
|
||||||
|
maxR = h>=0 ? 2500 : -(r1+r2+s)/2,
|
||||||
|
dir = unit(zrot(-90,tan_pts[1]-tan_pts[0])),
|
||||||
|
gap = function(rr)
|
||||||
|
let(
|
||||||
|
pts=circle_circle_intersection( abs(r1+rr),[-s/2,0], abs(r2+rr), [s/2,0]),
|
||||||
|
cp = len(pts)==1 ? pts[0] : pts[rr<0?1:0],
|
||||||
|
isect = line_intersection([cp,cp+dir], tan_pts, LINE, LINE)
|
||||||
|
)
|
||||||
|
norm(isect - cp-rr*dir)
|
||||||
|
)
|
||||||
|
h==0 || abs(h) < min(gap(minR),gap(maxR)) ? INF
|
||||||
|
:
|
||||||
|
let(
|
||||||
|
maxh = gap(minR),
|
||||||
|
minh = gap(maxR),
|
||||||
|
dummy = assert(h<0 || h<=maxh, str("For this geometry must have h < ",maxh," but h=",h))
|
||||||
|
assert(h>0 || abs(h)<minh, str("For this geometry must have abs(h) < ",minh," but h=",h)),
|
||||||
|
error = function(r) gap(r)-abs(h),
|
||||||
|
goodR = root_find(error, minR, maxR, tol=1e-7)
|
||||||
|
)
|
||||||
|
goodR;
|
||||||
|
|
||||||
|
|
||||||
|
// Function&Module: old_glued_circles()
|
||||||
|
// Synopsis: Creates a shape of two circles joined by a curved waist.
|
||||||
|
// SynTags: Geom, Path
|
||||||
|
// Topics: Shapes (2D), Paths (2D), Path Generators, Attachable
|
||||||
|
// See Also: circle(), ellipse(), egg(), keyhole()
|
||||||
|
// Usage: As Module
|
||||||
// glued_circles(r/d=, [spread], [tangent], ...) [ATTACHMENTS];
|
// glued_circles(r/d=, [spread], [tangent], ...) [ATTACHMENTS];
|
||||||
// Usage: As Function
|
// Usage: As Function
|
||||||
// path = glued_circles(r/d=, [spread], [tangent], ...);
|
// path = glued_circles(r/d=, [spread], [tangent], ...);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue