Skip to content

Commit edc78da

Browse files
committed
Merge remote-tracking branch 'upstream/master'
2 parents a12bf3a + 3fe1199 commit edc78da

4 files changed

Lines changed: 175 additions & 99 deletions

File tree

masks.scad

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1322,7 +1322,7 @@ module edge_profile(edges=EDGES_ALL, except=[], excess=0.01, convexity=10) {
13221322
// excess = Excess length to extrude the profile to make edge masks. Default: 0.01
13231323
// convexity = Max number of times a line could intersect the perimeter of the mask shape. Default: 10
13241324
// flip = If true, reverses the orientation of any external profile parts at each edge. Default false
1325-
// corner_type = Specifies how exterior corners should be formed. Must be one of `"none"`, `"chamfer"`, `"round"`, or `"sharp"`. Default: `"none"`
1325+
// corner_type = Specifies how to form exterior corners, and if `size` is set, interior corners. Must be one of `"none"`, `"chamfer"`, `"round"`, or `"sharp"`. Default: `"none"`
13261326
// size = If given the width and height of the 2D profile, enable rounding and chamfering of internal corners when given a negative profile.
13271327
// Side Effects:
13281328
// Tags the children with "remove" (and hence sets `$tag`) if no tag is already set.
@@ -1420,7 +1420,7 @@ module edge_profile_asym(
14201420
edges=EDGES_ALL, except=[],
14211421
excess=0.01, convexity=10,
14221422
flip=false, corner_type="none",
1423-
size=[0,0]
1423+
size=undef
14241424
) {
14251425
function _corner_orientation(pos,pvec) =
14261426
let(
@@ -1561,7 +1561,11 @@ module edge_profile_asym(
15611561
check1 = assert($parent_geom != undef, "\nNo object to attach to!")
15621562
assert(is_cuboid, "Parent must be a cuboid")
15631563
assert(in_list(corner_type, ["none", "round", "chamfer", "sharp"]))
1564-
assert(is_bool(flip));
1564+
assert(is_bool(flip))
1565+
assert(is_undef(size) || (is_num(size) && size>0) || (is_vector(size,2) && all_positive(size)),
1566+
"size must be a positive number of 2-vector");
1567+
size = is_undef(size) ? [0,0] : force_list(size,2);
1568+
15651569
edges = _edges(edges, except=except);
15661570
vecs = [
15671571
for (i = [0:3], axis=[0:2])
@@ -1596,11 +1600,11 @@ module edge_profile_asym(
15961600
$profile_type = "corner";
15971601
position(pos) {
15981602
multmatrix(mirT) {
1599-
if (vp1.x == vp2.x && size.y > 0) {
1603+
if (vp1.x == vp2.x && size.x>0) {
16001604
zflip() {
16011605
if (corner_type=="chamfer") {
16021606
fn = $fn;
1603-
move([size.y,size.y]) {
1607+
move(size) {
16041608
rotate_extrude(angle=90, $fn=4)
16051609
left_half(planar=true, $fn=fn)
16061610
zrot(-90) fwd(size.y) children();
@@ -1613,7 +1617,7 @@ module edge_profile_asym(
16131617
square([size.x+0.01, size.y+0.01]);
16141618
}
16151619
} else if (corner_type=="round") {
1616-
move([size.y,size.y]) {
1620+
move(size) {
16171621
rotate_extrude(angle=90)
16181622
left_half(planar=true)
16191623
zrot(-90) fwd(size.y) children();

skin.scad

Lines changed: 112 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -587,7 +587,7 @@ function skin(profiles, slices, refine=1, method="direct", sampling, caps, close
587587
// Named Anchors:
588588
// "origin" = Centers the extruded shape vertically only, but keeps the original path positions in the X and Y. Oriented UP.
589589
// "original_base" = Keeps the original path positions in the X and Y, but at the bottom of the extrusion. Oriented DOWN.
590-
// "original_top" = Keeps the original path positions in the X and Y, but at the top of the extrusion. Oriented UP.
590+
// "original_top" = Keeps the original path positions in the X and Y, but at the top height of the extrusion. Oriented UP.
591591
// "edge0", "edge1", etc. = Center of each side edge, spin pointing up along the edge. Can access with EDGE(i)
592592
// "face0", "face1", etc. = Center of each side face, spin pointing up. Can access with FACE(i)
593593
// "top_edge0", "top_edge1", etc = Center of each top edge, spin pointing clockwise (from top). Can access with EDGE(TOP,i)
@@ -785,61 +785,102 @@ module linear_sweep(
785785
}
786786

787787

788-
function _make_all_prism_anchors(bot, top, startind=0) =
789-
let(
790-
facenormal= [
791-
for(i=idx(bot))
792-
let(
793-
edge0 = [top[i],bot[i]], // vertical edge at i
794-
edge1 = [select(top,i+1),select(bot,i+1)], // vertical edge at i+1
795-
facenormal = unit(unit(cross(edge1[1]-edge0[0], edge0[1]-edge0[0]))+
796-
unit(cross(edge0[0]-edge1[1], edge1[0]-edge1[1])))
797-
)
798-
facenormal
799-
],
800-
anchors = [for(i=idx(bot))
801-
let(
802788

803-
edge1 = [top[i],bot[i]], // vertical edge at i
804-
edge2 = [select(top,i+1),select(bot,i+1)], // vertical edge at i+1
805-
806-
facecenter = mean(concat(edge1,edge2)),
807-
facespin = _compute_spin(facenormal[i], UP),
808-
809-
side_edge_center = mean(edge1),
810-
side_edge_dir = top[i]-bot[i],
811-
side_edge_normal = unit(vector_bisect(facenormal[i],select(facenormal,i-1))),
812-
side_edge_spin = _compute_spin(side_edge_normal, side_edge_dir),
813-
side_edge_angle = 180-vector_angle(facenormal[i], select(facenormal,i-1)),
814-
side_edge_len = norm(side_edge_dir),
815-
816-
top_edge_center = (edge2[0]+edge1[0])/2,
817-
top_edge_dir = edge2[0]-edge1[0],
818-
bot_edge_center = (edge1[1]+edge2[1])/2,
819-
bot_edge_dir = edge1[1]-edge2[1],
820-
topnormal = unit(facenormal[i]+UP),
821-
botnormal = unit(facenormal[i]+DOWN),
822-
topedgespin = _compute_spin(topnormal, top_edge_dir),
823-
botedgespin = _compute_spin(botnormal, bot_edge_dir),
824-
topedgeangle = 180-vector_angle(UP,facenormal[i])
825-
)
826-
each [
827-
named_anchor(str("face",i+startind), facecenter, facenormal[i], facespin),
828-
named_anchor(str("edge",i+startind), side_edge_center, side_edge_normal, side_edge_spin,
829-
info=[["edge_angle",side_edge_angle], ["edge_length",side_edge_len]]),
830-
named_anchor(str("top_edge",i+startind), top_edge_center, topnormal, topedgespin,
831-
info=[["edge_angle",topedgeangle],["edge_length",norm(top_edge_dir)]]),
832-
named_anchor(str("bot_edge",i+startind), bot_edge_center, botnormal, botedgespin,
833-
info=[["edge_angle",180-topedgeangle],["edge_length",norm(bot_edge_dir)]]),
834-
named_anchor(str("top_corner",i+startind), top[i], unit(side_edge_normal+UP),
835-
_compute_spin(unit(side_edge_normal+UP),side_edge_dir)),
836-
named_anchor(str("bot_corner",i+startind), bot[i], unit(side_edge_normal+DOWN),
837-
_compute_spin(unit(side_edge_normal+DOWN),side_edge_dir))
838-
]
839-
]
840-
)
841-
anchors;
789+
function _lsw_sweep_tangent(p, u, h, shift=[0,0], scale=[1,1], twist=0) =
790+
let(
791+
sc = lerp([1,1], scale, u),
792+
dsc = scale - [1,1],
793+
q = zrot(-twist*u, p),
794+
k = -twist*PI/180
795+
)
796+
[
797+
dsc.x*q.x - sc.x*k*q.y + shift.x,
798+
dsc.y*q.y + sc.y*k*q.x + shift.y,
799+
h
800+
];
801+
802+
function _lsw_face_normal(path, layer, i, u, h, shift=[0,0], scale=[1,1], twist=0, p=undef) =
803+
let(
804+
p0 = select(path, i),
805+
p1 = select(path, i+1),
806+
ps = is_undef(p)? (p0+p1)/2 : p,
807+
eh = select(layer, i+1) - select(layer, i),
808+
vs = _lsw_sweep_tangent(ps, u, h, shift=shift, scale=scale, twist=twist),
809+
raw = cross(vs, eh),
810+
fb = cross(UP, eh)
811+
)
812+
unit(raw, error=unit(fb, error=RIGHT));
842813

814+
function _lsw_seam_normal(path, layer, i, u, h, shift=[0,0], scale=[1,1], twist=0) =
815+
let(
816+
p = select(path, i),
817+
n0 = _lsw_face_normal(path, layer, i-1, u, h, shift=shift, scale=scale, twist=twist, p=p),
818+
n1 = _lsw_face_normal(path, layer, i, u, h, shift=shift, scale=scale, twist=twist, p=p)
819+
)
820+
unit(vector_bisect(n1, n0), error=unit(n1+n0, error=n1));
821+
822+
823+
function _make_all_linear_sweep_anchors(path, midpath, toppath, h, shift=[0,0], scale=[1,1], twist=0, startind=0) =
824+
let(
825+
bot = path3d(path, -h/2),
826+
mid = path3d(midpath, 0),
827+
top = path3d(toppath, h/2)
828+
)
829+
[
830+
for (i=idx(path))
831+
let(
832+
p0 = path[i],
833+
834+
mid_face_normal = _lsw_face_normal(path, mid, i, 1/2, h, shift=shift, scale=scale, twist=twist),
835+
top_face_normal = _lsw_face_normal(path, top, i, 1, h, shift=shift, scale=scale, twist=twist),
836+
bot_face_normal = _lsw_face_normal(path, bot, i, 0, h, shift=shift, scale=scale, twist=twist),
837+
838+
facecenter = (mid[i] + select(mid, i+1)) / 2,
839+
faceref = unit(point3d(shift,h)),
840+
facespin = _compute_spin(mid_face_normal, faceref),
841+
842+
side_edge_center = mid[i],
843+
side_edge_dir = _lsw_sweep_tangent(p0, 1/2, h, shift=shift, scale=scale, twist=twist),
844+
side_edge_normal = _lsw_seam_normal(path, mid, i, 1/2, h, shift=shift, scale=scale, twist=twist),
845+
side_edge_spin = _compute_spin(side_edge_normal, side_edge_dir),
846+
side_edge_angle = 180 - vector_angle(
847+
_lsw_face_normal(path, mid, i, 1/2, h, shift=shift, scale=scale, twist=twist, p=p0),
848+
_lsw_face_normal(path, mid, i-1, 1/2, h, shift=shift, scale=scale, twist=twist, p=p0)
849+
),
850+
side_edge_len = norm(top[i]-bot[i]),
851+
852+
top_edge_center = (top[i] + select(top, i+1)) / 2,
853+
top_edge_dir = select(top, i+1) - top[i],
854+
topnormal = unit(top_face_normal + UP, error=UP),
855+
topedgespin = _compute_spin(topnormal, top_edge_dir),
856+
topedgeangle = 180 - vector_angle(UP, top_face_normal),
857+
858+
bot_edge_center = (bot[i] + select(bot, i+1)) / 2,
859+
bot_edge_dir = bot[i] - select(bot, i+1),
860+
botnormal = unit(bot_face_normal + DOWN, error=DOWN),
861+
botedgespin = _compute_spin(botnormal, bot_edge_dir),
862+
botedgeangle = 180 - vector_angle(DOWN, bot_face_normal),
863+
864+
top_corner_pos = top[i],
865+
top_corner_norm = unit(_lsw_seam_normal(path, top, i, 1, h, shift=shift, scale=scale, twist=twist) + UP, error=UP),
866+
867+
bot_corner_pos = select(bot, i),
868+
bot_corner_norm = unit(_lsw_seam_normal(path, bot, i, 0, h, shift=shift, scale=scale, twist=twist) + DOWN, error=DOWN)
869+
)
870+
each [
871+
named_anchor(str("face", i+startind), facecenter, mid_face_normal, facespin),
872+
named_anchor(str("edge", i+startind), side_edge_center, side_edge_normal, side_edge_spin,
873+
info=[["edge_angle", side_edge_angle], ["edge_length", side_edge_len]]),
874+
named_anchor(str("top_edge", i+startind), top_edge_center, topnormal, topedgespin,
875+
info=[["edge_angle", topedgeangle], ["edge_length", norm(top_edge_dir)]]),
876+
named_anchor(str("bot_edge", i+startind), bot_edge_center, botnormal, botedgespin,
877+
info=[["edge_angle", botedgeangle], ["edge_length", norm(bot_edge_dir)]]),
878+
named_anchor(str("top_corner", i+startind), top_corner_pos, top_corner_norm,
879+
_compute_spin(top_corner_norm, side_edge_dir)),
880+
named_anchor(str("bot_corner", i+startind), bot_corner_pos, bot_corner_norm,
881+
_compute_spin(bot_corner_norm, side_edge_dir))
882+
]
883+
];
843884

844885

845886
function linear_sweep(
@@ -866,8 +907,11 @@ function linear_sweep(
866907
assert(is_vector(shift, 2), str(shift))
867908
assert(is_bool(caps) || is_bool_list(caps,2), "\ncaps must be boolean or a list of two booleans.")
868909
let(
910+
scale = is_num(scale) ? [scale, scale] : point2d(scale),
869911
h = one_defined([h, height,l,length],"h,height,l,length",dflt=1),
870912
regions = region_parts(region),
913+
topmat = move(shift) * scale(scale) * rot(-twist), // needed for anchoring even in texture case
914+
midmat = move(shift/2) * scale(lerp([1,1],scale,1/2)) * rot(-twist/2), // needed for anchoring even in texture case
871915
vnf = !is_undef(texture)?
872916
_textured_linear_sweep(
873917
region, h=h, caps=caps,
@@ -882,8 +926,6 @@ function linear_sweep(
882926
center == false? "original_base" :
883927
default(anchor, "original_base"),
884928
slices = default(slices, max(1,ceil(abs(twist)/5))),
885-
scale = is_num(scale)? [scale,scale] : point2d(scale),
886-
topmat = move(shift) * scale(scale) * rot(-twist),
887929
trgns = [
888930
for (rgn = regions) [
889931
for (path = rgn) let(
@@ -922,14 +964,19 @@ function linear_sweep(
922964
vnf,
923965
regparts = flatten(regions),
924966
sizes = [0,each cumsum([for(entry=regparts) len(entry)])],
925-
ganchors = [
926-
for(i=idx(regparts))
927-
let(
928-
bot = path3d(regparts[i],-h/2),
929-
top = path3d(move(shift,scale(scale, zrot(-twist, regparts[i]))),h/2)
930-
)
931-
each _make_all_prism_anchors(bot,top, startind=sizes[i])
932-
],
967+
ganchors = [
968+
for (i=idx(regparts))
969+
each _make_all_linear_sweep_anchors(
970+
regparts[i],
971+
apply(midmat,regparts[i]),
972+
apply(topmat,regparts[i]),
973+
h=h,
974+
shift=shift,
975+
scale=scale,
976+
twist=twist,
977+
startind=sizes[i]
978+
)
979+
],
933980
anchors = [
934981
named_anchor("original_base", [0,0,-h/2], DOWN),
935982
named_anchor("original_top", [0,0,h/2], UP),
@@ -4545,8 +4592,7 @@ function _textured_linear_sweep(
45454592
inset = is_num(inset)? inset : inset? 1 : 0,
45464593
twist = default(twist, 0),
45474594
shift = default(shift, [0,0]),
4548-
scale = scale==undef? [1,1,1] :
4549-
is_num(scale)? [scale,scale,1] : scale,
4595+
scale = scale==undef? [1,1,1] : point3d(scale,1),
45504596
samples = !is_vnf(texture)? len(texture[0]) :
45514597
is_num(samples)? samples : 8,
45524598
vnf_tile =

version.scad

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ _BOSL2_VERSION = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOS
1414

1515

1616

17-
BOSL_VERSION = [2,0,744];
17+
18+
BOSL_VERSION = [2,0,746];
19+
1820

1921

2022

0 commit comments

Comments
 (0)