mirror of
https://github.com/BelfrySCAD/BOSL2.git
synced 2025-01-01 09:49:45 +00:00
Enable passing a region to stroke().
This commit is contained in:
parent
724e49385b
commit
83f61f5a6a
1 changed files with 188 additions and 182 deletions
370
drawing.scad
370
drawing.scad
|
@ -132,7 +132,7 @@
|
||||||
// path = [for (i=[0:15:360]) [(i-180)/3,20*cos(2*i)]];
|
// path = [for (i=[0:15:360]) [(i-180)/3,20*cos(2*i)]];
|
||||||
// stroke(path, width=2, dots=true, color="lightgreen", dots_color="red", $fn=18);
|
// stroke(path, width=2, dots=true, color="lightgreen", dots_color="red", $fn=18);
|
||||||
function stroke(
|
function stroke(
|
||||||
path, width=1, closed=false,
|
path, width=1, closed,
|
||||||
endcaps, endcap1, endcap2, joints, dots,
|
endcaps, endcap1, endcap2, joints, dots,
|
||||||
endcap_width, endcap_width1, endcap_width2, joint_width, dots_width,
|
endcap_width, endcap_width1, endcap_width2, joint_width, dots_width,
|
||||||
endcap_length, endcap_length1, endcap_length2, joint_length, dots_length,
|
endcap_length, endcap_length1, endcap_length2, joint_length, dots_length,
|
||||||
|
@ -143,7 +143,7 @@ function stroke(
|
||||||
convexity=10, hull=true
|
convexity=10, hull=true
|
||||||
) = no_function("stroke");
|
) = no_function("stroke");
|
||||||
module stroke(
|
module stroke(
|
||||||
path, width=1, closed=false,
|
path, width=1, closed,
|
||||||
endcaps, endcap1, endcap2, joints, dots,
|
endcaps, endcap1, endcap2, joints, dots,
|
||||||
endcap_width, endcap_width1, endcap_width2, joint_width, dots_width,
|
endcap_width, endcap_width1, endcap_width2, joint_width, dots_width,
|
||||||
endcap_length, endcap_length1, endcap_length2, joint_length, dots_length,
|
endcap_length, endcap_length1, endcap_length2, joint_length, dots_length,
|
||||||
|
@ -200,16 +200,8 @@ module stroke(
|
||||||
assert(false, str("Invalid endcap: ",cap))
|
assert(false, str("Invalid endcap: ",cap))
|
||||||
) * linewidth;
|
) * linewidth;
|
||||||
|
|
||||||
|
closed = default(closed, is_region(path));
|
||||||
assert(is_bool(closed));
|
assert(is_bool(closed));
|
||||||
assert(is_list(path));
|
|
||||||
if (len(path) > 1) {
|
|
||||||
assert(is_path(path,[2,3]), "The path argument must be a list of 2D or 3D points.");
|
|
||||||
}
|
|
||||||
path = deduplicate( closed? close_path(path) : path );
|
|
||||||
|
|
||||||
assert(is_num(width) || (is_vector(width) && len(width)==len(path)));
|
|
||||||
width = is_num(width)? [for (x=path) width] : width;
|
|
||||||
assert(all([for (w=width) w>0]));
|
|
||||||
|
|
||||||
dots = dots==true? "dot" : dots;
|
dots = dots==true? "dot" : dots;
|
||||||
|
|
||||||
|
@ -247,175 +239,196 @@ module stroke(
|
||||||
|
|
||||||
endcap_angle1 = first_defined([endcap_angle1, endcap_angle, dots_angle]);
|
endcap_angle1 = first_defined([endcap_angle1, endcap_angle, dots_angle]);
|
||||||
endcap_angle2 = first_defined([endcap_angle2, endcap_angle, dots_angle]);
|
endcap_angle2 = first_defined([endcap_angle2, endcap_angle, dots_angle]);
|
||||||
|
joint_angle = first_defined([joint_angle, dots_angle]);
|
||||||
assert(is_undef(endcap_angle1)||is_num(endcap_angle1));
|
assert(is_undef(endcap_angle1)||is_num(endcap_angle1));
|
||||||
assert(is_undef(endcap_angle2)||is_num(endcap_angle2));
|
assert(is_undef(endcap_angle2)||is_num(endcap_angle2));
|
||||||
assert(is_undef(joint_angle)||is_num(joint_angle));
|
assert(is_undef(joint_angle)||is_num(joint_angle));
|
||||||
|
|
||||||
endcap_shape1 = _shape_path(endcap1, width[0], endcap_width1, endcap_length1, endcap_extent1);
|
|
||||||
endcap_shape2 = _shape_path(endcap2, last(width), endcap_width2, endcap_length2, endcap_extent2);
|
|
||||||
|
|
||||||
endcap_color1 = first_defined([endcap_color1, endcap_color, dots_color, color]);
|
endcap_color1 = first_defined([endcap_color1, endcap_color, dots_color, color]);
|
||||||
endcap_color2 = first_defined([endcap_color2, endcap_color, dots_color, color]);
|
endcap_color2 = first_defined([endcap_color2, endcap_color, dots_color, color]);
|
||||||
joint_color = first_defined([joint_color, dots_color, color]);
|
joint_color = first_defined([joint_color, dots_color, color]);
|
||||||
|
|
||||||
trim1 = width[0] * first_defined([
|
paths = is_region(path)? path : [path];
|
||||||
trim1, trim,
|
for (path = paths) {
|
||||||
(endcap1=="arrow")? endcap_length1-0.01 :
|
assert(is_list(path));
|
||||||
(endcap1=="arrow2")? endcap_length1*3/4 :
|
if (len(path) > 1) {
|
||||||
0
|
assert(is_path(path,[2,3]), "The path argument must be a list of 2D or 3D points, or a region.");
|
||||||
]);
|
|
||||||
assert(is_num(trim1));
|
|
||||||
|
|
||||||
trim2 = last(width) * first_defined([
|
|
||||||
trim2, trim,
|
|
||||||
(endcap2=="arrow")? endcap_length2-0.01 :
|
|
||||||
(endcap2=="arrow2")? endcap_length2*3/4 :
|
|
||||||
0
|
|
||||||
]);
|
|
||||||
assert(is_num(trim2));
|
|
||||||
|
|
||||||
|
|
||||||
if (len(path) == 1) {
|
|
||||||
if (len(path[0]) == 2) {
|
|
||||||
translate(path[0]) circle(d=width[0]);
|
|
||||||
} else {
|
|
||||||
translate(path[0]) sphere(d=width[0]);
|
|
||||||
}
|
}
|
||||||
} else {
|
path = deduplicate( closed? close_path(path) : path );
|
||||||
pathcut = _path_cut_points(path, [trim1, path_length(path)-trim2], closed=false);
|
|
||||||
pathcut_su = _cut_to_seg_u_form(pathcut,path);
|
|
||||||
path2 = _path_cut_getpaths(path, pathcut, closed=false)[1];
|
|
||||||
widths = _path_select(width, pathcut_su[0][0], pathcut_su[0][1], pathcut_su[1][0], pathcut_su[1][1]);
|
|
||||||
start_vec = path[0] - path[1];
|
|
||||||
end_vec = last(path) - select(path,-2);
|
|
||||||
|
|
||||||
if (len(path[0]) == 2) {
|
assert(is_num(width) || (is_vector(width) && len(width)==len(path)));
|
||||||
// Straight segments
|
width = is_num(width)? [for (x=path) width] : width;
|
||||||
setcolor(color) {
|
assert(all([for (w=width) w>0]));
|
||||||
for (i = idx(path2,e=-2)) {
|
|
||||||
seg = select(path2,i,i+1);
|
endcap_shape1 = _shape_path(endcap1, width[0], endcap_width1, endcap_length1, endcap_extent1);
|
||||||
delt = seg[1] - seg[0];
|
endcap_shape2 = _shape_path(endcap2, last(width), endcap_width2, endcap_length2, endcap_extent2);
|
||||||
translate(seg[0]) {
|
|
||||||
rot(from=BACK,to=delt) {
|
trim1 = width[0] * first_defined([
|
||||||
trapezoid(w1=widths[i], w2=widths[i+1], h=norm(delt), anchor=FRONT);
|
trim1, trim,
|
||||||
|
(endcap1=="arrow")? endcap_length1-0.01 :
|
||||||
|
(endcap1=="arrow2")? endcap_length1*3/4 :
|
||||||
|
0
|
||||||
|
]);
|
||||||
|
assert(is_num(trim1));
|
||||||
|
|
||||||
|
trim2 = last(width) * first_defined([
|
||||||
|
trim2, trim,
|
||||||
|
(endcap2=="arrow")? endcap_length2-0.01 :
|
||||||
|
(endcap2=="arrow2")? endcap_length2*3/4 :
|
||||||
|
0
|
||||||
|
]);
|
||||||
|
assert(is_num(trim2));
|
||||||
|
|
||||||
|
|
||||||
|
if (len(path) == 1) {
|
||||||
|
if (len(path[0]) == 2) {
|
||||||
|
translate(path[0]) circle(d=width[0]);
|
||||||
|
} else {
|
||||||
|
translate(path[0]) sphere(d=width[0]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pathcut = _path_cut_points(path, [trim1, path_length(path)-trim2], closed=false);
|
||||||
|
pathcut_su = _cut_to_seg_u_form(pathcut,path);
|
||||||
|
path2 = _path_cut_getpaths(path, pathcut, closed=false)[1];
|
||||||
|
widths = _path_select(width, pathcut_su[0][0], pathcut_su[0][1], pathcut_su[1][0], pathcut_su[1][1]);
|
||||||
|
start_vec = path[0] - path[1];
|
||||||
|
end_vec = last(path) - select(path,-2);
|
||||||
|
|
||||||
|
if (len(path[0]) == 2) {
|
||||||
|
// Straight segments
|
||||||
|
setcolor(color) {
|
||||||
|
for (i = idx(path2,e=-2)) {
|
||||||
|
seg = select(path2,i,i+1);
|
||||||
|
delt = seg[1] - seg[0];
|
||||||
|
translate(seg[0]) {
|
||||||
|
rot(from=BACK,to=delt) {
|
||||||
|
trapezoid(w1=widths[i], w2=widths[i+1], h=norm(delt), anchor=FRONT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Joints
|
// Joints
|
||||||
setcolor(joint_color) {
|
setcolor(joint_color) {
|
||||||
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);
|
||||||
translate(path2[i]) {
|
translate(path2[i]) {
|
||||||
if (joints != undef) {
|
if (joints != undef) {
|
||||||
joint_shape = _shape_path(
|
joint_shape = _shape_path(
|
||||||
joints, width[i],
|
joints, width[i],
|
||||||
joint_width,
|
joint_width,
|
||||||
joint_length,
|
joint_length,
|
||||||
joint_extent
|
joint_extent
|
||||||
);
|
);
|
||||||
v1 = unit(path2[i] - path2[i-1]);
|
v1 = unit(path2[i] - path2[i-1]);
|
||||||
v2 = unit(path2[i+1] - path2[i]);
|
v2 = unit(path2[i+1] - path2[i]);
|
||||||
vec = unit((v1+v2)/2);
|
vec = unit((v1+v2)/2);
|
||||||
mat = is_undef(joint_angle)
|
mat = is_undef(joint_angle)
|
||||||
? rot(from=BACK,to=v1)
|
? rot(from=BACK,to=v1)
|
||||||
: zrot(joint_angle);
|
: zrot(joint_angle);
|
||||||
multmatrix(mat) polygon(joint_shape);
|
multmatrix(mat) polygon(joint_shape);
|
||||||
} else if (hull) {
|
} else if (hull) {
|
||||||
hull() {
|
hull() {
|
||||||
|
rot(from=BACK, to=path2[i]-path2[i-1])
|
||||||
|
circle(d=widths[i]);
|
||||||
|
rot(from=BACK, to=path2[i+1]-path2[i])
|
||||||
|
circle(d=widths[i]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
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]);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
rot(from=BACK, to=path2[i]-path2[i-1])
|
|
||||||
circle(d=widths[i]);
|
|
||||||
rot(from=BACK, to=path2[i+1]-path2[i])
|
|
||||||
circle(d=widths[i]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Endcap1
|
// Endcap1
|
||||||
setcolor(endcap_color1) {
|
setcolor(endcap_color1) {
|
||||||
translate(path[0]) {
|
translate(path[0]) {
|
||||||
mat = is_undef(endcap_angle1)? rot(from=BACK,to=start_vec) :
|
mat = is_undef(endcap_angle1)? rot(from=BACK,to=start_vec) :
|
||||||
zrot(endcap_angle1);
|
zrot(endcap_angle1);
|
||||||
multmatrix(mat) polygon(endcap_shape1);
|
multmatrix(mat) polygon(endcap_shape1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Endcap2
|
// Endcap2
|
||||||
setcolor(endcap_color2) {
|
setcolor(endcap_color2) {
|
||||||
translate(last(path)) {
|
translate(last(path)) {
|
||||||
mat = is_undef(endcap_angle2)? rot(from=BACK,to=end_vec) :
|
mat = is_undef(endcap_angle2)? rot(from=BACK,to=end_vec) :
|
||||||
zrot(endcap_angle2);
|
zrot(endcap_angle2);
|
||||||
multmatrix(mat) polygon(endcap_shape2);
|
multmatrix(mat) polygon(endcap_shape2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
} else {
|
quatsums = q_cumulative([
|
||||||
quatsums = q_cumulative([
|
for (i = idx(path2,e=-2)) let(
|
||||||
for (i = idx(path2,e=-2)) let(
|
vec1 = i==0? UP : unit(path2[i]-path2[i-1], UP),
|
||||||
vec1 = i==0? UP : unit(path2[i]-path2[i-1], UP),
|
vec2 = unit(path2[i+1]-path2[i], UP),
|
||||||
vec2 = unit(path2[i+1]-path2[i], UP),
|
axis = vector_axis(vec1,vec2),
|
||||||
axis = vector_axis(vec1,vec2),
|
ang = vector_angle(vec1,vec2)
|
||||||
ang = vector_angle(vec1,vec2)
|
) quat(axis,ang)
|
||||||
) quat(axis,ang)
|
]);
|
||||||
]);
|
rotmats = [for (q=quatsums) q_matrix4(q)];
|
||||||
rotmats = [for (q=quatsums) q_matrix4(q)];
|
sides = [
|
||||||
sides = [
|
for (i = idx(path2,e=-2))
|
||||||
for (i = idx(path2,e=-2))
|
quantup(segs(max(widths[i],widths[i+1])/2),4)
|
||||||
quantup(segs(max(widths[i],widths[i+1])/2),4)
|
];
|
||||||
];
|
|
||||||
|
|
||||||
// Straight segments
|
// Straight segments
|
||||||
setcolor(color) {
|
setcolor(color) {
|
||||||
for (i = idx(path2,e=-2)) {
|
for (i = idx(path2,e=-2)) {
|
||||||
dist = norm(path2[i+1] - path2[i]);
|
dist = norm(path2[i+1] - path2[i]);
|
||||||
w1 = widths[i]/2;
|
w1 = widths[i]/2;
|
||||||
w2 = widths[i+1]/2;
|
w2 = widths[i+1]/2;
|
||||||
$fn = sides[i];
|
$fn = sides[i];
|
||||||
translate(path2[i]) {
|
translate(path2[i]) {
|
||||||
multmatrix(rotmats[i]) {
|
multmatrix(rotmats[i]) {
|
||||||
cylinder(r1=w1, r2=w2, h=dist, center=false);
|
cylinder(r1=w1, r2=w2, h=dist, center=false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Joints
|
// Joints
|
||||||
setcolor(joint_color) {
|
setcolor(joint_color) {
|
||||||
for (i = [1:1:len(path2)-2]) {
|
for (i = [1:1:len(path2)-2]) {
|
||||||
$fn = sides[i];
|
$fn = sides[i];
|
||||||
translate(path2[i]) {
|
translate(path2[i]) {
|
||||||
if (joints != undef) {
|
if (joints != undef) {
|
||||||
joint_shape = _shape_path(
|
joint_shape = _shape_path(
|
||||||
joints, width[i],
|
joints, width[i],
|
||||||
joint_width,
|
joint_width,
|
||||||
joint_length,
|
joint_length,
|
||||||
joint_extent
|
joint_extent
|
||||||
);
|
);
|
||||||
multmatrix(rotmats[i] * xrot(180)) {
|
multmatrix(rotmats[i] * xrot(180)) {
|
||||||
$fn = sides[i];
|
$fn = sides[i];
|
||||||
if (is_undef(joint_angle)) {
|
if (is_undef(joint_angle)) {
|
||||||
rotate_extrude(convexity=convexity) {
|
rotate_extrude(convexity=convexity) {
|
||||||
right_half(planar=true) {
|
right_half(planar=true) {
|
||||||
polygon(joint_shape);
|
polygon(joint_shape);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
} else {
|
rotate([90,0,joint_angle]) {
|
||||||
rotate([90,0,joint_angle]) {
|
linear_extrude(height=max(widths[i],0.001), center=true, convexity=convexity) {
|
||||||
linear_extrude(height=max(widths[i],0.001), center=true, convexity=convexity) {
|
polygon(joint_shape);
|
||||||
polygon(joint_shape);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else if (hull) {
|
||||||
} else if (hull) {
|
hull(){
|
||||||
hull(){
|
multmatrix(rotmats[i]) {
|
||||||
|
sphere(d=widths[i],style="aligned");
|
||||||
|
}
|
||||||
|
multmatrix(rotmats[i-1]) {
|
||||||
|
sphere(d=widths[i],style="aligned");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
multmatrix(rotmats[i]) {
|
multmatrix(rotmats[i]) {
|
||||||
sphere(d=widths[i],style="aligned");
|
sphere(d=widths[i],style="aligned");
|
||||||
}
|
}
|
||||||
|
@ -423,55 +436,48 @@ module stroke(
|
||||||
sphere(d=widths[i],style="aligned");
|
sphere(d=widths[i],style="aligned");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
multmatrix(rotmats[i]) {
|
|
||||||
sphere(d=widths[i],style="aligned");
|
|
||||||
}
|
|
||||||
multmatrix(rotmats[i-1]) {
|
|
||||||
sphere(d=widths[i],style="aligned");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Endcap1
|
// Endcap1
|
||||||
setcolor(endcap_color1) {
|
setcolor(endcap_color1) {
|
||||||
translate(path[0]) {
|
translate(path[0]) {
|
||||||
multmatrix(rotmats[0] * xrot(180)) {
|
multmatrix(rotmats[0] * xrot(180)) {
|
||||||
$fn = sides[0];
|
$fn = sides[0];
|
||||||
if (is_undef(endcap_angle1)) {
|
if (is_undef(endcap_angle1)) {
|
||||||
rotate_extrude(convexity=convexity) {
|
rotate_extrude(convexity=convexity) {
|
||||||
right_half(planar=true) {
|
right_half(planar=true) {
|
||||||
polygon(endcap_shape1);
|
polygon(endcap_shape1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
} else {
|
rotate([90,0,endcap_angle1]) {
|
||||||
rotate([90,0,endcap_angle1]) {
|
linear_extrude(height=max(widths[0],0.001), center=true, convexity=convexity) {
|
||||||
linear_extrude(height=max(widths[0],0.001), center=true, convexity=convexity) {
|
polygon(endcap_shape1);
|
||||||
polygon(endcap_shape1);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Endcap2
|
// Endcap2
|
||||||
setcolor(endcap_color2) {
|
setcolor(endcap_color2) {
|
||||||
translate(last(path)) {
|
translate(last(path)) {
|
||||||
multmatrix(last(rotmats)) {
|
multmatrix(last(rotmats)) {
|
||||||
$fn = last(sides);
|
$fn = last(sides);
|
||||||
if (is_undef(endcap_angle2)) {
|
if (is_undef(endcap_angle2)) {
|
||||||
rotate_extrude(convexity=convexity) {
|
rotate_extrude(convexity=convexity) {
|
||||||
right_half(planar=true) {
|
right_half(planar=true) {
|
||||||
polygon(endcap_shape2);
|
polygon(endcap_shape2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
} else {
|
rotate([90,0,endcap_angle2]) {
|
||||||
rotate([90,0,endcap_angle2]) {
|
linear_extrude(height=max(last(widths),0.001), center=true, convexity=convexity) {
|
||||||
linear_extrude(height=max(last(widths),0.001), center=true, convexity=convexity) {
|
polygon(endcap_shape2);
|
||||||
polygon(endcap_shape2);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue