Merge pull request #749 from adrianVmariano/master

doc tweaks, path_chamfer_rounding fix
This commit is contained in:
Revar Desmera 2022-01-07 19:28:37 -08:00 committed by GitHub
commit 00df38a83b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 952 additions and 890 deletions

View file

@ -1274,25 +1274,6 @@ module attachable(
}
// Function: named_anchor()
// Usage:
// a = named_anchor(name, pos, [orient], [spin]);
// Topics: Attachments
// See Also: reorient(), attachable()
// Description:
// Creates an anchor data structure. For a more step-by-step explanation of attachments,
// see the [[Attachments Tutorial|Tutorial-Attachments]].
// Arguments:
// name = The string name of the anchor. Lowercase. Words separated by single dashes. No spaces.
// pos = The [X,Y,Z] position of the anchor.
// orient = A vector pointing in the direction parts should project from the anchor position.
// spin = If needed, the angle to rotate the part around the direction vector.
function named_anchor(name, pos=[0,0,0], orient=UP, spin=0) = [name, pos, orient, spin];
// Function: reorient()
//
// Usage: Square/Trapezoid Geometry
@ -1418,6 +1399,24 @@ function reorient(
) _attach_transform(anchor,spin,orient,geom,p);
// Function: named_anchor()
// Usage:
// a = named_anchor(name, pos, [orient], [spin]);
// Topics: Attachments
// See Also: reorient(), attachable()
// Description:
// Creates an anchor data structure. For a more step-by-step explanation of attachments,
// see the [[Attachments Tutorial|Tutorial-Attachments]].
// Arguments:
// name = The string name of the anchor. Lowercase. Words separated by single dashes. No spaces.
// pos = The [X,Y,Z] position of the anchor.
// orient = A vector pointing in the direction parts should project from the anchor position.
// spin = If needed, the angle to rotate the part around the direction vector.
function named_anchor(name, pos=[0,0,0], orient=UP, spin=0) = [name, pos, orient, spin];
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//

File diff suppressed because it is too large Load diff

View file

@ -172,6 +172,10 @@ CENTER = [ 0, 0, 0]; // Centered zero vector.
CTR = CENTER;
// Section: Line specifiers
// Used by functions in geometry.scad for specifying whether two points
// are treated as an unbounded line, a ray with one endpoint, or a segment
// with two endpoints.
// Constant: SEGMENT
// Topics: Constants, Lines

View file

@ -4,7 +4,7 @@
// Includes:
// include <BOSL2/std.scad>
// FileGroup: Basic Modeling
// FileSummary: Shortcuts for translation, rotation, etc. Can act on geometry, paths, or can return a matrix.
// FileSummary: Copy or distribute objects onto a line or grid. Mirror shortcuts.
// FileFootnotes: STD=Included in std.scad
//////////////////////////////////////////////////////////////////////

View file

@ -9,7 +9,7 @@
// Includes:
// include <BOSL2/std.scad>
// FileGroup: Basic Modeling
// FileSummary: Attachable cubes, cylinders, spheres, ruler, and text. Many can produce a VNF.
// FileSummary: Create and draw 2D and 3D paths: arc, helix, turtle graphics
// FileFootnotes: STD=Included in std.scad
//////////////////////////////////////////////////////////////////////
@ -650,7 +650,7 @@ module dashed_stroke(path, dashpat=[3,3], width=1, closed=false) {
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(N+1,r,angle,d,cp,points,width,thickness,start,wedge,long,cw,ccw,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")
// First try for 2D arc specified by width and thickness
is_def(width) && is_def(thickness)? (

View file

@ -7,7 +7,7 @@
// Includes:
// include <BOSL2/std.scad>
// FileGroup: Math
// FileSummary: Line and plane intersections, circles from 3 points, etc.
// FileSummary: Geometrical calculations including intersections of lines, circles and planes, circle from 3 points
// FileFootnotes: STD=Included in std.scad
//////////////////////////////////////////////////////////////////////
@ -1076,6 +1076,72 @@ function circle_line_intersection(c,r,d,line,bounded=false,eps=EPSILON) =
&& (!bounded[1] || (p-line[1])*(line[0]-line[1])>=0)) p];
// Function: circle_circle_intersection()
// Usage:
// pts = circle_circle_tangents(c1, r1|d1, c2, r2|d2, [eps]);
// Topics: Geometry, Circles
// Description:
// Compute the intersection points of two circles. Returns a list of the intersection points, which
// will contain two points in the general case, one point for tangent circles, or will be empty
// if the circles do not intersect.
// Arguments:
// c1 = Center of the first circle.
// r1 = Radius of the first circle.
// c2 = Center of the second circle.
// r2 = Radius of the second circle.
// eps = Tolerance for detecting tangent circles. Default: EPSILON
// ---
// d1 = Diameter of the first circle.
// d2 = Diameter of the second circle.
// Example(2D,NoAxes): Circles intersect in two points.
// $fn=32;
// c1 = [4,4]; r1 = 3;
// c2 = [7,7]; r2 = 2;
// pts = circle_circle_intersection(c1,r1,c2,r2);
// move(c1) stroke(circle(r=r1), width=0.2, closed=true);
// move(c2) stroke(circle(r=r2), width=0.2, closed=true);
// color("red")move_copies(pts) circle(r=.3);
// Example(2D,NoAxes): Circles are tangent, so one intersection point:
// $fn=32;
// c1 = [4,4]; r1 = 4;
// c2 = [4,10]; r2 = 2;
// pts = circle_circle_intersection(c1,r1,c2,r2);
// move(c1) stroke(circle(r=r1), width=0.2, closed=true);
// move(c2) stroke(circle(r=r2), width=0.2, closed=true);
// color("red")move_copies(pts) circle(r=.3);
// Example(2D,NoAxes): Another tangent example:
// $fn=32;
// c1 = [4,4]; r1 = 4;
// c2 = [5,5]; r2 = 4-sqrt(2);
// pts = circle_circle_intersection(c1,r1,c2,r2);
// move(c1) stroke(circle(r=r1), width=0.2, closed=true);
// move(c2) stroke(circle(r=r2), width=0.2, closed=true);
// color("red")move_copies(pts) circle(r=.3);
// Example(2D,NoAxes): Circles do not intersect. Returns empty list.
// $fn=32;
// c1 = [3,4]; r1 = 2;
// c2 = [7,10]; r2 = 3;
// pts = circle_circle_intersection(c1,r1,c2,r2);
// move(c1) stroke(circle(r=r1), width=0.2, closed=true);
// move(c2) stroke(circle(r=r2), width=0.2, closed=true);
// color("red")move_copies(pts) circle(r=.2); // pts is []
function circle_circle_intersection(c1,r1,c2,r2,eps=EPSILON,d1,d2) =
assert( is_path([c1,c2],dim=2), "Invalid center point(s)." )
let(
r1 = get_radius(r1=r1,d1=d1),
r2 = get_radius(r1=r2,d1=d2),
d = norm(c2-c1),
a = (c2-c1)/d,
b = [-a.y,a.x],
L = (r1^2-r2^2+d^2)/2/d,
hsqr = r1^2-L^2
)
approx(hsqr,0,eps) ? [L*a+c1]
: hsqr<0 ? []
: let(h=sqrt(hsqr))
[L*a+h*b+c1, L*a-h*b+c1];
// Function&Module: circle_2tangents()
// Usage: As Function
// circ = circle_2tangents(pt1, pt2, pt3, r|d, [tangents]);
@ -1323,6 +1389,7 @@ function circle_point_tangents(r, d, cp, pt) =
// r1 = Radius of the first circle.
// c2 = Center of the second circle.
// r2 = Radius of the second circle.
// ---
// d1 = Diameter of the first circle.
// d2 = Diameter of the second circle.
// Example(2D,NoAxes): Four tangents, first in green, second in black, third in blue, last in red.

View file

@ -996,8 +996,8 @@ module rabbit_clip(type, length, width, snap, thickness, depth, compression=0.1
? concat(pin_smooth, reverse(pin_smooth))
: let(side_smooth=select(pin_smooth, 0, 2))
concat(side_smooth, [socket_smooth], reverse(side_smooth));
bez = path_to_bezier(path,relsize=smoothing,tangents=tangent);
rounded = bezier_path(bez,splinesteps=splinesteps);
bez = path_to_bezpath(path,relsize=smoothing,tangents=tangent);
rounded = bezpath_curve(bez,splinesteps=splinesteps);
bounds = pointlist_bounds(rounded);
extrapt = is_pin ? [] : [rounded[0] - [0,extra]];
finalpath = is_pin ? rounded

View file

@ -1,10 +1,11 @@
//////////////////////////////////////////////////////////////////////
// LibFile: lists.scad
// Functions for constructing and manipulating generic lists.
// Functions for operating on generic lists. Provides functiosn for indexing lists, changing list
// structure, and constructing lists by rearranging or modifying another list.
// Includes:
// include <BOSL2/std.scad>
// FileGroup: Data Management
// FileSummary: Various list manipulation functions
// FileSummary: List indexing, change list structure, rearrange/modify lists
// FileFootnotes: STD=Included in std.scad
//////////////////////////////////////////////////////////////////////
@ -387,6 +388,7 @@ function repeat(val, n, i=0) =
// s = The starting value of the list of numbers.
// step = The amount to increment successive numbers in the list.
// reverse = Reverse the list. Default: false.
// See Also: idx()
// Example:
// nl1 = count(5); // Returns: [0,1,2,3,4]
// nl2 = count(5,3); // Returns: [3,4,5,6,7]
@ -851,9 +853,10 @@ function idx(list, s=0, e=-1, step=1) =
// Topics: List Handling, Iteration
// See Also: idx(), triplet(), combinations(), permutations()
// Description:
// Takes a list, and returns a list of adjacent pairs from it, optionally wrapping back to the front.
// Returns a list of all of the pairs of adjacent items from a list, optionally wrapping back to the front. The pairs overlap, and
// are returned in order starting with the first two entries in the list. If the list has less than two elements, the empty list is returned.
// Arguments:
// list = The list to iterate.
// list = The list to use for making pairs
// wrap = If true, wrap back to the start from the end. ie: return the last and first items as the last pair. Default: false
// Example(2D): Does NOT wrap from end to start,
// for (p = pair(circle(d=40, $fn=12)))
@ -883,7 +886,7 @@ function pair(list, wrap=false) =
// Topics: List Handling, Iteration
// See Also: idx(), pair(), combinations(), permutations()
// Description:
// Takes a list, and returns a list of adjacent triplets from it, optionally wrapping back to the front.
// Returns a list of all adjacent triplets from a list, optionally wrapping back to the front.
// If you set `wrap` to true then the first triplet is the one centered on the first list element, so it includes
// the last element and the first two elements. If the list has fewer than three elements then the empty list is returned.
// Arguments:

View file

@ -176,7 +176,7 @@ module chain_hull()
// trapezoid(w1=10, w2=5, h=10, anchor=BACK);
// Example:
// include <BOSL2/beziers.scad>
// path = bezier_path([
// path = bezpath_curve([
// [-50,0], [-25,50], [0,0], [50,0]
// ]);
// path_extrude2d(path, caps=false)

View file

@ -10,7 +10,7 @@
// Includes:
// include <BOSL2/std.scad>
// FileGroup: Advanced Modeling
// FileSummary: Work with arbitrary 2D or 3D paths.
// FileSummary: Operations on paths: length, resampling, tangents, splitting into subpaths
// FileFootnotes: STD=Included in std.scad
//////////////////////////////////////////////////////////////////////
@ -727,7 +727,11 @@ function path_torsion(path, closed=false) =
// stroke(path2, closed=true);
function path_chamfer_and_rounding(path, closed=true, chamfer, rounding) =
let (
path = deduplicate(path,closed=true),
p = force_path(path)
)
assert(is_path(p),"Input 'path' is not a path")
let(
path = deduplicate(p,closed=true),
lp = len(path),
chamfer = is_undef(chamfer)? repeat(0,lp) :
is_vector(chamfer)? list_pad(chamfer,lp,0) :
@ -737,6 +741,7 @@ function path_chamfer_and_rounding(path, closed=true, chamfer, rounding) =
is_vector(rounding)? list_pad(rounding,lp,0) :
is_num(rounding)? repeat(rounding,lp) :
assert(false, "Bad rounding value."),
corner_paths = [
for (i=(closed? [0:1:lp-1] : [1:1:lp-2])) let(
p1 = select(path,i-1),

View file

@ -293,13 +293,14 @@ function round_corners(path, method="circle", radius, cut, joint, k, closed=true
dummy = verbose ? echo("Roundover scale factors:",scalefactors) : 0
)
assert(min(scalefactors)>=1,str("Roundovers are too big for the path. If you multitply them by this vector they should fit: ",scalefactors))
[
// duplicates are introduced when roundings fully consume a segment, so remove them
deduplicate([
for(i=[0:1:len(path)-1]) each
(dk[i][0] == 0)? [path[i]] :
(method=="smooth")? _bezcorner(select(path,i-1,i+1), dk[i]) :
(method=="chamfer") ? _chamfcorner(select(path,i-1,i+1), dk[i]) :
_circlecorner(select(path,i-1,i+1), dk[i])
];
]);
// Computes the continuous curvature control points for a corner when given as
// input three points in a list defining the corner. The points must be
@ -344,7 +345,7 @@ function _bezcorner(points, parm) =
points[1]+k*d*next,
points[1]+d*next
] : _smooth_bez_fill(points,parm),
N = max(3,$fn>0 ?$fn : ceil(bezier_segment_length(P)/$fs))
N = max(3,$fn>0 ?$fn : ceil(bezier_length(P)/$fs))
)
bezier_curve(P,N+1,endpoint=true);
@ -449,7 +450,7 @@ function _rounding_offsets(edgespec,z_dir=1) =
// in which case the size parameter specifies the sum of the deviations of the two peaks of the curve. In 3-space
// the bezier curve may have three extrema: two maxima and one minimum. In this case the size specifies
// the sum of the maxima minus the minimum. At a given segment there is a maximum size: if your size
// value is too large it will be rounded down. See also path_to_bezier().
// value is too large it will be rounded down. See also path_to_bezpath().
// Arguments:
// path = path to smooth
// tangents = tangents constraining curve direction at each point. Default: computed automatically
@ -499,11 +500,12 @@ function _rounding_offsets(edgespec,z_dir=1) =
// stroke(smooth_path(pts, uniform=false, relsize=0.1),width=.1);
// color("red")move_copies(pts)circle(r=.15,$fn=12);
module smooth_path(path, tangents, size, relsize, splinesteps=10, uniform=false, closed=false) {no_module();}
function smooth_path(path, tangents, size, relsize, splinesteps=10, uniform=false, closed=false) =
function smooth_path(path, tangents, size, relsize, splinesteps=10, uniform=false, closed) =
is_1region(path) ? smooth_path(path[0], tangents, size, relsize, splinesteps, uniform, default(closed,true)) :
let (
bez = path_to_bezier(path, tangents=tangents, size=size, relsize=relsize, uniform=uniform, closed=closed)
bez = path_to_bezpath(path, tangents=tangents, size=size, relsize=relsize, uniform=uniform, closed=default(closed,false))
)
bezier_path(bez,splinesteps=splinesteps);
bezpath_curve(bez,splinesteps=splinesteps);
@ -663,7 +665,7 @@ function _path_join(paths,joint,k=0.5,i=0,result=[],relocate=true,closed=false)
loop?"closing the path":str("adding path ",i+1)))
let(
bezpts = _smooth_bez_fill([firstcut[0], corner, nextcut[0]],k[i]),
N = max(3,$fn>0 ?$fn : ceil(bezier_segment_length(bezpts)/$fs)),
N = max(3,$fn>0 ?$fn : ceil(bezier_length(bezpts)/$fs)),
bezpath = approx(firstcut[0],corner) && approx(corner,nextcut[0])
? []
: bezier_curve(bezpts,N),

View file

@ -221,7 +221,7 @@ module circle(r, d, anchor=CENTER, spin=0) {
// Usage: As a Function
// path = ellipse(r|d=, [realign=], [circum=], ...);
// Topics: Shapes (2D), Paths (2D), Path Generators, Attachable
// See Also: circle()
// See Also: circle(), circle_2tangents(), circle_3points()
// Description:
// When called as a module, creates a 2D polygon that approximates a circle or ellipse of the given size.
// When called as a function, returns a 2D list of points (path) for a polygon that approximates a circle or ellipse of the given size.
@ -1126,6 +1126,85 @@ function teardrop2d(r, ang=45, cap_h, d, anchor=CENTER, spin=0) =
// Function&Module: egg()
// Usage: As Module
// egg(length, r1, r2, R);
// Usage: As Function
// path = egg(length, r1|d2, r2|d2, R|D);
// Topics: Shapes (2D), Paths (2D), Path Generators, Attachable
// See Also: circle(), ellipse(), glued_circles()
// Description:
// Constructs an egg-shaped object by connecting two circles with convex arcs that are tangent to the circles.
// You specify the length of the egg, the radii of the two circles, and the desired arc radius.
// Note that because the side radius, R, is often much larger than the end radii, you may get better
// results using `$fs` and `$fa` to control the number of semgments rather than using `$fn`.
// This shape may be useful for creating a cam.
// Arguments:
// length = length of the egg
// r1 = radius of the left-hand circle
// r2 = radius of the right-hand circle
// R = radius of the joining arcs
// ---
// d1 = diameter of the left-hand circle
// d2 = diameter of the right-hand circle
// D = diameter of the joining arcs
// Extra Anchors:
// "left" = center of the left circle
// "right" = center of the right circle
// Example(2D,NoAxes): This first example shows how the egg is constructed from two circles and two joining arcs.
// $fn=100;
// color("red")stroke(egg(78,25,12, 60),closed=true);
// stroke([left(14,circle(25)),
// right(27,circle(12))]);
// Examples(2D,NoAxes):
// egg(78,25,12,50,$fn=64);
// egg(78,25,12,60,$fn=64);
// egg(78,25,12,85,$fs=0.1,$fa=1);
// egg(78,25,12,150,$fs=0.1,$fa=1);
// egg(78,25,4, 140, $fs=0.1, $fa=1);
// stroke(egg(50,15,20, 40, $fs=0.1, $fa=1,anchor=BACK));
function egg(length, r1, r2, R, d1, d2, D, anchor=CENTER, spin=0) =
let(
r1 = get_radius(r1=r1,d1=d1),
r2 = get_radius(r1=r2,d1=d2),
D = get_radius(r1=R, d1=D)
)
assert(length>0)
assert(R>length/2, "Side radius R must be larger than length/2")
assert(length>r1+r2, "Length must be longer than 2*(r1+r2)")
assert(length>2*r2, "Length must be longer than 2*r2")
assert(length>2*r1, "Length must be longer than 2*r1")
let(
c1 = [-length/2+r1,0],
c2 = [length/2-r2,0],
Rmin = (r1+r2+norm(c1-c2))/2,
Mlist = circle_circle_intersection(c1,R-r1,c2,R-r2),
arcparms = reverse([for(M=Mlist) [M, c1+r1*unit(c1-M), c2+r2*unit(c2-M)]]),
path = concat(
arc(r=r2, cp=c2, points=[[length/2,0],arcparms[0][2]],endpoint=false),
arc(r=R, cp=arcparms[0][0], points=select(arcparms[0],[2,1]),endpoint=false),
arc(r=r1, points=[arcparms[0][1], [-length/2,0], arcparms[1][1]],endpoint=false),
arc(r=R, cp=arcparms[1][0], points=select(arcparms[1],[1,2]),endpoint=false),
arc(r=r2, cp=c2, points=[arcparms[1][2], [length/2,0]],endpoint=false)
),
anchors = [named_anchor("left", c1, BACK, 0),
named_anchor("right", c2, BACK, 0)]
)
reorient(anchor, spin, two_d=true, path=path, extent=true, p=path, anchors=anchors);
module egg(length,r1,r2,R,d1,d2,D,anchor=CENTER, spin=0)
{
path = egg(length,r1,r2,R,d1,d2,D);
anchors = [named_anchor("left", [-length/2+r1,0], BACK, 0),
named_anchor("right", [length/2-r2,0], BACK, 0)];
attachable(anchor, spin, two_d=true, path=path, extent=true, anchors=anchors){
polygon(path);
children();
}
}
// Function&Module: glued_circles()
// Usage: As Module
// glued_circles(r/d=, [spread=], [tangent=], ...);
@ -1134,7 +1213,7 @@ function teardrop2d(r, ang=45, cap_h, d, anchor=CENTER, spin=0) =
// Usage: As Function
// path = glued_circles(r/d=, [spread=], [tangent=], ...);
// Topics: Shapes (2D), Paths (2D), Path Generators, Attachable
// See Also: circle(), ellipse()
// See Also: circle(), ellipse(), egg()
// Description:
// When called as a function, returns a 2D path forming a shape of two circles joined by curved waist.
// When called as a module, creates a 2D shape of two circles joined by curved waist. Uses "hull" style anchoring.

View file

@ -10,7 +10,7 @@
// Includes:
// include <BOSL2/std.scad>
// FileGroup: Advanced Modeling
// FileSummary: Construct 3D shapes from a 2D cross sections of the desired shape.
// FileSummary: Construct 3D shapes from 2D cross sections of the desired shape.
// FileFootnotes: STD=Included in std.scad
//////////////////////////////////////////////////////////////////////

View file

@ -1281,8 +1281,7 @@ function skew(p=_NO_ARG, sxy=0, sxz=0, syx=0, syz=0, szx=0, szy=0) =
p==_NO_ARG? m : apply(m, p);
// Section: Applying transformation matrices to
// Section: Applying transformation matrices to data
/// Internal Function: is_2d_transform()
/// Usage:

View file

@ -8,9 +8,7 @@
// FileSummary: Routed bundles of wires.
//////////////////////////////////////////////////////////////////////
include <beziers.scad>
include <rounding.scad>
// Section: Functions
@ -77,10 +75,10 @@ function hex_offsets(n, d, lev=0, arr=[]) =
// wirediam = The diameter of each wire in the bundle.
// rounding = The radius that the path corners will be rounded to.
// wirenum = The first wire's offset into the color table.
// bezsteps = The corner roundings in the path will be converted into this number of segments.
// corner_steps = The corner roundings in the path will be converted into this number of segments.
// Example:
// wiring([[50,0,-50], [50,50,-50], [0,50,-50], [0,0,-50], [0,0,0]], rounding=10, wires=13);
module wiring(path, wires, wirediam=2, rounding=10, wirenum=0, bezsteps=12) {
module wiring(path, wires, wirediam=2, rounding=10, wirenum=0, corner_steps=12) {
colors = [
[0.2, 0.2, 0.2], [1.0, 0.2, 0.2], [0.0, 0.8, 0.0], [1.0, 1.0, 0.2],
[0.3, 0.3, 1.0], [1.0, 1.0, 1.0], [0.7, 0.5, 0.0], [0.5, 0.5, 0.5],
@ -89,14 +87,13 @@ module wiring(path, wires, wirediam=2, rounding=10, wirenum=0, bezsteps=12) {
[0.6, 0.6, 1.0],
];
offsets = hex_offsets(wires, wirediam);
bezpath = fillet_path(path, rounding);
poly = path_merge_collinear(path3d(bezier_path(bezpath, bezsteps)));
rounded_path = round_corners(path, radius=rounding,$fn=(corner_steps+1)*4,closed=false);
n = max(segs(wirediam), 8);
r = wirediam/2;
for (i = [0:1:wires-1]) {
extpath = [for (j = [0:1:n-1]) let(a=j*360/n) [r*cos(a)+offsets[i][0], r*sin(a)+offsets[i][1]]];
color(colors[(i+wirenum)%len(colors)]) {
path_sweep(extpath, poly);
path_sweep(extpath, rounded_path);
}
}
}