@@ -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
845886function 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 ), "\n caps 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 =
0 commit comments