mirror of
https://github.com/BelfrySCAD/BOSL2.git
synced 2025-01-19 19:09:36 +00:00
Enabled use of stroke() for 3D paths.
This commit is contained in:
parent
126f2acd15
commit
d5aac19ef8
2 changed files with 113 additions and 35 deletions
146
shapes2d.scad
146
shapes2d.scad
|
@ -15,7 +15,7 @@
|
||||||
// stroke(path, [width], [closed], [endcaps], [endcap_width], [endcap_length], [endcap_extent], [trim]);
|
// stroke(path, [width], [closed], [endcaps], [endcap_width], [endcap_length], [endcap_extent], [trim]);
|
||||||
// stroke(path, [width], [closed], [endcap1], [endcap2], [endcap_width1], [endcap_width2], [endcap_length1], [endcap_length2], [endcap_extent1], [endcap_extent2], [trim1], [trim2]);
|
// stroke(path, [width], [closed], [endcap1], [endcap2], [endcap_width1], [endcap_width2], [endcap_length1], [endcap_length2], [endcap_extent1], [endcap_extent2], [trim1], [trim2]);
|
||||||
// Description:
|
// Description:
|
||||||
// Draws a 2D line path with a given line thickness. Endcaps can be specified for each end individually.
|
// Draws a 2D or 3D path with a given line width. Endcaps can be specified for each end individually.
|
||||||
// Figure(2D,Big): Endcap Types
|
// Figure(2D,Big): Endcap Types
|
||||||
// endcaps = [
|
// endcaps = [
|
||||||
// ["butt", "square", "round", "chisel", "tail", "tail2"],
|
// ["butt", "square", "round", "chisel", "tail", "tail2"],
|
||||||
|
@ -45,9 +45,13 @@
|
||||||
// endcap_extent = Extents length of endcaps, in multiples of the line width. Default: `endcap_width*0.5`
|
// endcap_extent = Extents length of endcaps, in multiples of the line width. Default: `endcap_width*0.5`
|
||||||
// endcap_extent1 = Extents length of starting endcap, in multiples of the line width. Default: `endcap_width1*0.5`
|
// endcap_extent1 = Extents length of starting endcap, in multiples of the line width. Default: `endcap_width1*0.5`
|
||||||
// endcap_extent2 = Extents length of ending endcap, in multiples of the line width. Default: `endcap_width2*0.5`
|
// endcap_extent2 = Extents length of ending endcap, in multiples of the line width. Default: `endcap_width2*0.5`
|
||||||
|
// endcap_angle = Extra axial rotation given to flat endcaps for 3D paths, in degrees. If not given, the endcaps are fully spun. Default: `undef` (Fully spun cap)
|
||||||
|
// endcap_angle1 = Extra axial rotation given to a flat starting endcap for 3D paths, in degrees. If not given, the endcap is fully spun. Default: `undef` (Fully spun cap)
|
||||||
|
// endcap_angle2 = Extra axial rotation given to a flat ending endcap for 3D paths, in degrees. If not given, the endcap is fully spun. Default: `undef` (Fully spun cap)
|
||||||
// trim = Trim the the start and end line segments by this much, to keep them from interfering with custom endcaps.
|
// trim = Trim the the start and end line segments by this much, to keep them from interfering with custom endcaps.
|
||||||
// trim1 = Trim the the starting line segment by this much, to keep it from interfering with a custom endcap.
|
// trim1 = Trim the the starting line segment by this much, to keep it from interfering with a custom endcap.
|
||||||
// trim2 = Trim the the ending line segment by this much, to keep it from interfering with a custom endcap.
|
// trim2 = Trim the the ending line segment by this much, to keep it from interfering with a custom endcap.
|
||||||
|
// convexity = Max number of times a line could intersect a wall of an endcap.
|
||||||
// Example(2D): Drawing a Path
|
// Example(2D): Drawing a Path
|
||||||
// path = [[0,100], [100,100], [200,0], [100,-100], [100,0]];
|
// path = [[0,100], [100,100], [200,0], [100,-100], [100,0]];
|
||||||
// stroke(path, width=20);
|
// stroke(path, width=20);
|
||||||
|
@ -71,13 +75,24 @@
|
||||||
// path = circle(d=50,$fn=18);
|
// path = circle(d=50,$fn=18);
|
||||||
// widths = [for (i=idx(path)) 10*i/len(path)+2];
|
// widths = [for (i=idx(path)) 10*i/len(path)+2];
|
||||||
// stroke(path,width=widths,$fa=1,$fs=1);
|
// stroke(path,width=widths,$fa=1,$fs=1);
|
||||||
|
// Example: 3D Path with Endcaps
|
||||||
|
// path = rot([15,30,0], p=path3d(pentagon(d=50)));
|
||||||
|
// stroke(path, width=2, endcaps="arrow2", $fn=18);
|
||||||
|
// Example: 3D Path with Flat Endcaps
|
||||||
|
// path = rot([15,30,0], p=path3d(pentagon(d=50)));
|
||||||
|
// stroke(path, width=2, endcaps="arrow2", endcap_angle=0, $fn=18);
|
||||||
|
// Example: 3D Path with Mixed Endcaps
|
||||||
|
// path = rot([15,30,0], p=path3d(pentagon(d=50)));
|
||||||
|
// stroke(path, width=2, endcap1="arrow2", endcap2="tail", endcap_angle2=0, $fn=18);
|
||||||
module stroke(
|
module stroke(
|
||||||
path, width=1, closed=false,
|
path, width=1, closed=false,
|
||||||
endcaps, endcap1, endcap2,
|
endcaps, endcap1, endcap2,
|
||||||
trim, trim1, trim2,
|
trim, trim1, trim2,
|
||||||
endcap_width, endcap_width1, endcap_width2,
|
endcap_width, endcap_width1, endcap_width2,
|
||||||
endcap_length, endcap_length1, endcap_length2,
|
endcap_length, endcap_length1, endcap_length2,
|
||||||
endcap_extent, endcap_extent1, endcap_extent2
|
endcap_extent, endcap_extent1, endcap_extent2,
|
||||||
|
endcap_angle, endcap_angle1, endcap_angle2,
|
||||||
|
convexity=10
|
||||||
) {
|
) {
|
||||||
function _endcap_shape(cap,linewidth,w,l,l2) = (
|
function _endcap_shape(cap,linewidth,w,l,l2) = (
|
||||||
let(sq2=sqrt(2), l3=l-l2)
|
let(sq2=sqrt(2), l3=l-l2)
|
||||||
|
@ -92,15 +107,14 @@ module stroke(
|
||||||
cap=="arrow"? [[0,0], [w/2,-l2], [w/2,-l2-l], [0,-l], [-w/2,-l2-l], [-w/2,-l2]] :
|
cap=="arrow"? [[0,0], [w/2,-l2], [w/2,-l2-l], [0,-l], [-w/2,-l2-l], [-w/2,-l2]] :
|
||||||
cap=="arrow2"? [[0,0], [w/2,-l2-l], [0,-l], [-w/2,-l2-l]] :
|
cap=="arrow2"? [[0,0], [w/2,-l2-l], [0,-l], [-w/2,-l2-l]] :
|
||||||
cap=="tail"? [[0,0], [w/2,l2], [w/2,l2-l], [0,-l], [-w/2,l2-l], [-w/2,l2]] :
|
cap=="tail"? [[0,0], [w/2,l2], [w/2,l2-l], [0,-l], [-w/2,l2-l], [-w/2,l2]] :
|
||||||
cap=="tail2"? [[w/2,0], [w/2,-l], [1/2,-l-l2], [-1/2,-l-l2], [-w/2,-l], [-w/2,0]] :
|
cap=="tail2"? [[w/2,0], [w/2,-l], [0,-l-l2], [-w/2,-l], [-w/2,0]] :
|
||||||
is_path(cap)? cap :
|
is_path(cap)? cap :
|
||||||
[]
|
[]
|
||||||
) * linewidth;
|
) * linewidth;
|
||||||
|
|
||||||
assert(is_bool(closed));
|
assert(is_bool(closed));
|
||||||
assert(is_path(path));
|
assert(is_path(path,[2,3]), "The path argument must be a list of 2D or 3D points.");
|
||||||
path = closed? concat(path,[path[0]]) : path;
|
path = closed? concat(path,[path[0]]) : path;
|
||||||
assert(is_list(path) && is_vector(path[0]) && len(path[0])==2, "path must be a 2D list of points.");
|
|
||||||
|
|
||||||
assert(is_num(width) || (is_vector(width) && len(width)==len(path)));
|
assert(is_num(width) || (is_vector(width) && len(width)==len(path)));
|
||||||
width = is_num(width)? [for (x=path) width] : width;
|
width = is_num(width)? [for (x=path) width] : width;
|
||||||
|
@ -125,6 +139,11 @@ module stroke(
|
||||||
assert(is_num(endcap_extent1));
|
assert(is_num(endcap_extent1));
|
||||||
assert(is_num(endcap_extent2));
|
assert(is_num(endcap_extent2));
|
||||||
|
|
||||||
|
endcap_angle1 = first_defined([endcap_angle1, endcap_angle]);
|
||||||
|
endcap_angle2 = first_defined([endcap_angle2, endcap_angle]);
|
||||||
|
assert(is_undef(endcap_angle1)||is_num(endcap_angle1));
|
||||||
|
assert(is_undef(endcap_angle2)||is_num(endcap_angle2));
|
||||||
|
|
||||||
endcap_shape1 = _endcap_shape(endcap1, select(width,0), endcap_width1, endcap_length1, endcap_extent1);
|
endcap_shape1 = _endcap_shape(endcap1, select(width,0), endcap_width1, endcap_length1, endcap_extent1);
|
||||||
endcap_shape2 = _endcap_shape(endcap2, select(width,-1), endcap_width2, endcap_length2, endcap_extent2);
|
endcap_shape2 = _endcap_shape(endcap2, select(width,-1), endcap_width2, endcap_length2, endcap_extent2);
|
||||||
|
|
||||||
|
@ -155,41 +174,100 @@ module stroke(
|
||||||
[lerp(width[epos[0]], width[(epos[0]+1)%len(width)], epos[1])]
|
[lerp(width[epos[0]], width[(epos[0]+1)%len(width)], epos[1])]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Line segments
|
if (is_path(path,2)) {
|
||||||
for (i = idx(path2,end=-2)) {
|
// Straight segments
|
||||||
seg = select(path2,i,i+1);
|
for (i = idx(path2,end=-2)) {
|
||||||
delt = seg[1] - seg[0];
|
seg = select(path2,i,i+1);
|
||||||
translate(seg[0])
|
delt = seg[1] - seg[0];
|
||||||
rot(from=BACK,to=delt)
|
translate(seg[0])
|
||||||
trapezoid(w1=widths[i], w2=widths[i+1], h=norm(delt), anchor=FRONT);
|
rot(from=BACK,to=delt)
|
||||||
}
|
trapezoid(w1=widths[i], w2=widths[i+1], h=norm(delt), anchor=FRONT);
|
||||||
|
}
|
||||||
|
|
||||||
// Joints
|
// Joints
|
||||||
for (i = [1:1:len(path2)-2]) {
|
for (i = [1:1:len(path2)-2]) {
|
||||||
$fn = quantup(segs(widths[i]/2),4);
|
$fn = quantup(segs(widths[i]/2),4);
|
||||||
hull() {
|
hull() {
|
||||||
translate(path2[i]) {
|
translate(path2[i]) {
|
||||||
rot(from=BACK, to=path2[i]-path2[i-1])
|
rot(from=BACK, to=path2[i]-path2[i-1])
|
||||||
circle(d=widths[i]);
|
circle(d=widths[i]);
|
||||||
rot(from=BACK, to=path2[i+1]-path2[i])
|
rot(from=BACK, to=path2[i+1]-path2[i])
|
||||||
circle(d=widths[i]);
|
circle(d=widths[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Endcap1
|
// Endcap1
|
||||||
translate(path[0]) {
|
translate(path[0]) {
|
||||||
start_vec = select(path,0) - select(path,1);
|
start_vec = select(path,0) - select(path,1);
|
||||||
rot(from=BACK, to=start_vec) {
|
rot(from=BACK, to=start_vec) {
|
||||||
polygon(endcap_shape1);
|
polygon(endcap_shape1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Endcap2
|
// Endcap2
|
||||||
translate(select(path,-1)) {
|
translate(select(path,-1)) {
|
||||||
end_vec = select(path,-1) - select(path,-2);
|
end_vec = select(path,-1) - select(path,-2);
|
||||||
rot(from=BACK, to=end_vec) {
|
rot(from=BACK, to=end_vec) {
|
||||||
polygon(endcap_shape2);
|
polygon(endcap_shape2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Straight segments
|
||||||
|
for (i = idx(path2,end=-2)) {
|
||||||
|
seg = select(path2,i,i+1);
|
||||||
|
delt = seg[1] - seg[0];
|
||||||
|
translate(seg[0])
|
||||||
|
rot(from=UP,to=delt)
|
||||||
|
cylinder(r1=widths[i]/2, r2=widths[i+1]/2, h=norm(delt), center=false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Joints
|
||||||
|
for (i = [1:1:len(path2)-2]) {
|
||||||
|
$fn = quantup(segs(widths[i]/2),4);
|
||||||
|
translate(path2[i])
|
||||||
|
rot(from=UP, to=path2[i]-path2[i-1])
|
||||||
|
sphere(d=widths[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Endcap1
|
||||||
|
translate(path[0]) {
|
||||||
|
start_vec = select(path,0) - select(path,1);
|
||||||
|
rot(from=UP, to=start_vec) {
|
||||||
|
if (is_undef(endcap_angle1)) {
|
||||||
|
rotate_extrude(convexity=convexity) {
|
||||||
|
right_half(planar=true) {
|
||||||
|
polygon(endcap_shape1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rotate([90,0,endcap_angle1]) {
|
||||||
|
linear_extrude(height=widths[0], center=true, convexity=convexity) {
|
||||||
|
polygon(endcap_shape1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Endcap2
|
||||||
|
translate(select(path,-1)) {
|
||||||
|
end_vec = select(path,-1) - select(path,-2);
|
||||||
|
rot(from=UP, to=end_vec) {
|
||||||
|
if (is_undef(endcap_angle2)) {
|
||||||
|
rotate_extrude(convexity=convexity) {
|
||||||
|
right_half(planar=true) {
|
||||||
|
polygon(endcap_shape2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rotate([90,0,endcap_angle2]) {
|
||||||
|
linear_extrude(height=select(widths,-1), center=true, convexity=convexity) {
|
||||||
|
polygon(endcap_shape2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
BOSL_VERSION = [2,0,168];
|
BOSL_VERSION = [2,0,169];
|
||||||
|
|
||||||
|
|
||||||
// Section: BOSL Library Version Functions
|
// Section: BOSL Library Version Functions
|
||||||
|
|
Loading…
Reference in a new issue