mirror of
https://github.com/BelfrySCAD/BOSL2.git
synced 2024-12-29 16:29:40 +00:00
Merge pull request #1394 from adrianVmariano/master
path sweep end anchors
This commit is contained in:
commit
af59a6c4a6
4 changed files with 147 additions and 50 deletions
|
@ -2764,17 +2764,47 @@ function reorient(
|
|||
// See Also: reorient(), attachable()
|
||||
// Usage:
|
||||
// a = named_anchor(name, pos, [orient], [spin]);
|
||||
// a = named_anchor(name, [pos], rot=, [flip=]);
|
||||
// Description:
|
||||
// Creates an anchor data structure. For a step-by-step explanation of attachments,
|
||||
// Creates an anchor data structure. You can specify the position, orient direction and spin directly.
|
||||
// Alternatively for the 3D case you can give a 4x4 rotation matrix which can specify the orient and spin, and optionally
|
||||
// the position, using a translation component of the matrix. If you specify `pos` along with `rot` then the position you
|
||||
// give overrides any translation included in `rot`. For a 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. Default: UP
|
||||
// spin = If needed, the angle to rotate the part around the direction vector. Default: 0
|
||||
function named_anchor(name, pos, orient=UP, spin=0) = [name, pos, orient, spin];
|
||||
// ---
|
||||
// rot = A 4x4 rotations matrix, which may include a translation
|
||||
// flip = If true, flip the anchor the opposite direction. Default: false
|
||||
function named_anchor(name, pos, orient, spin, rot, flip) =
|
||||
assert(num_defined([orient,spin])==0 || num_defined([rot,flip])==0, "Cannot mix orient or spin with rot or flip")
|
||||
assert(num_defined([pos,rot])>0, "Must give pos or rot")
|
||||
is_undef(rot) ? [name, pos, default(orient,UP), default(spin,0)]
|
||||
:
|
||||
let(
|
||||
flip = default(flip,false),
|
||||
pos = default(pos,apply(rot,CTR)),
|
||||
rotpart = _force_rot(rot),
|
||||
dummy = assert(approx(det4(rotpart),1), "Input rotation is not a rotation matrix"),
|
||||
dir = flip ? apply(rotpart,DOWN)
|
||||
: apply(rotpart,UP),
|
||||
rot = flip? affine3d_rot_by_axis(apply(rotpart,BACK),180)*rot
|
||||
: rot,
|
||||
decode=rot_decode(rot(to=UP,from=dir)*_force_rot(rot)),
|
||||
spin = decode[0]*sign(decode[1].z)
|
||||
)
|
||||
[name, pos, dir, spin];
|
||||
|
||||
|
||||
function _force_rot(T) =
|
||||
[for(i=[0:3])
|
||||
[for(j=[0:3]) j<3 ? T[i][j] :
|
||||
i==3 ? 1
|
||||
: 0]];
|
||||
|
||||
// Function: attach_geom()
|
||||
// Synopsis: Returns the internal geometry description of an attachable object.
|
||||
// Topics: Attachments
|
||||
|
@ -3202,7 +3232,6 @@ function _attach_transform(anchor, spin, orient, geom, p) =
|
|||
assert(is_undef(orient) || is_vector(orient,3), str("Got: ",orient))
|
||||
let(
|
||||
anchor = default(anchor, CENTER),
|
||||
|
||||
spin = default(spin, 0),
|
||||
orient = default(orient, UP),
|
||||
two_d = _attach_geom_2d(geom),
|
||||
|
@ -3210,12 +3239,13 @@ function _attach_transform(anchor, spin, orient, geom, p) =
|
|||
let(
|
||||
anch = _find_anchor($attach_to, geom),
|
||||
pos = anch[1]
|
||||
) two_d? (
|
||||
assert(two_d && is_num(spin))
|
||||
affine3d_zrot(spin) *
|
||||
rot(to=FWD, from=point3d(anch[2])) *
|
||||
affine3d_translate(point3d(-pos))
|
||||
) : (
|
||||
)
|
||||
two_d?
|
||||
assert(is_num(spin))
|
||||
affine3d_zrot(spin)
|
||||
* rot(to=FWD, from=point3d(anch[2]))
|
||||
* affine3d_translate(point3d(-pos))
|
||||
:
|
||||
assert(is_num(spin) || is_vector(spin,3))
|
||||
let(
|
||||
ang = vector_angle(anch[2], DOWN),
|
||||
|
@ -3223,40 +3253,33 @@ function _attach_transform(anchor, spin, orient, geom, p) =
|
|||
ang2 = (anch[2]==UP || anch[2]==DOWN)? 0 : 180-anch[3],
|
||||
axis2 = rot(p=axis,[0,0,ang2])
|
||||
)
|
||||
affine3d_rot_by_axis(axis2,ang) * (
|
||||
is_num(spin)? affine3d_zrot(ang2+spin) : (
|
||||
affine3d_zrot(spin.z) *
|
||||
affine3d_yrot(spin.y) *
|
||||
affine3d_xrot(spin.x) *
|
||||
affine3d_zrot(ang2)
|
||||
)
|
||||
) * affine3d_translate(point3d(-pos))
|
||||
)
|
||||
affine3d_rot_by_axis(axis2,ang)
|
||||
* (is_num(spin)? affine3d_zrot(ang2+spin)
|
||||
: affine3d_zrot(spin.z) * affine3d_yrot(spin.y) * affine3d_xrot(spin.x)
|
||||
* affine3d_zrot(ang2))
|
||||
* affine3d_translate(point3d(-pos))
|
||||
) : (
|
||||
let(
|
||||
pos = _find_anchor(anchor, geom)[1]
|
||||
) two_d? (
|
||||
assert(two_d && is_num(spin))
|
||||
affine3d_zrot(spin) *
|
||||
affine3d_translate(point3d(-pos))
|
||||
) : (
|
||||
)
|
||||
two_d?
|
||||
assert(is_num(spin))
|
||||
affine3d_zrot(spin) * affine3d_translate(point3d(-pos))
|
||||
:
|
||||
assert(is_num(spin) || is_vector(spin,3))
|
||||
let(
|
||||
axis = vector_axis(UP,orient),
|
||||
ang = vector_angle(UP,orient)
|
||||
)
|
||||
affine3d_rot_by_axis(axis,ang) * (
|
||||
is_num(spin)? affine3d_zrot(spin) : (
|
||||
affine3d_zrot(spin.z) *
|
||||
affine3d_yrot(spin.y) *
|
||||
affine3d_xrot(spin.x)
|
||||
)
|
||||
) * affine3d_translate(point3d(-pos))
|
||||
affine3d_rot_by_axis(axis,ang)
|
||||
* ( is_num(spin)? affine3d_zrot(spin)
|
||||
: affine3d_zrot(spin.z) * affine3d_yrot(spin.y) * affine3d_xrot(spin.x))
|
||||
* affine3d_translate(point3d(-pos))
|
||||
)
|
||||
)
|
||||
) is_undef(p)? m :
|
||||
is_vnf(p)? [(p==EMPTY_VNF? p : apply(m, p[0])), p[1]] :
|
||||
apply(m, p);
|
||||
is_undef(p)? m
|
||||
: is_vnf(p) && p==EMPTY_VNF? p
|
||||
: apply(m, p);
|
||||
|
||||
|
||||
function _get_cp(geom) =
|
||||
|
|
|
@ -956,12 +956,12 @@ function _path_join(paths,joint,k=0.5,i=0,result=[],relocate=true,closed=false)
|
|||
// path = [[0,0],[6,2],[9,7],[8,10]];
|
||||
// xdistribute(spacing=10){
|
||||
// offset_stroke(path, width = 2);
|
||||
// offset_stroke(path, start="round", end="round", width = 2);
|
||||
// offset_stroke(path, start="round", end="round", width = 2, $fn=32);
|
||||
// offset_stroke(path, start="pointed", end="pointed", width = 2);
|
||||
// }
|
||||
// fwd(10) xdistribute(spacing=10){
|
||||
// offset_stroke(arc, width = 2);
|
||||
// offset_stroke(arc, start="round", end="round", width = 2);
|
||||
// offset_stroke(arc, start="round", end="round", width = 2, $fn=32);
|
||||
// offset_stroke(arc, start="pointed", end="pointed", width = 2);
|
||||
// }
|
||||
// Example(2D): The effect of the `rounded` and `chamfer` options is most evident at sharp corners. This only affects the middle of the path, not the ends.
|
||||
|
|
71
skin.scad
71
skin.scad
|
@ -1482,9 +1482,17 @@ module spiral_sweep(poly, h, r, turns=1, taper, r1, r2, d, d1, d2, internal=fals
|
|||
// orient = Vector to rotate top towards after spin
|
||||
// atype = Select "hull" or "intersect" anchor types. Default: "hull"
|
||||
// cp = Centerpoint for determining "intersect" anchors or centering the shape. Determintes the base of the anchor vector. Can be "centroid", "mean", "box" or a 3D point. Default: "centroid"
|
||||
// Side Effects:
|
||||
// `$transforms` is set to the array of transformation matrices that define the swept object.
|
||||
// `$scales` is set to the array of scales that were applied at each point to create the swept object.
|
||||
// Anchor Types:
|
||||
// "hull" = Anchors to the virtual convex hull of the shape.
|
||||
// "intersect" = Anchors to the surface of the shape.
|
||||
// Extra Anchors:
|
||||
// start = When `closed==false`, the origin point of the shape, on the starting face of the object
|
||||
// end = When `closed==false`, the origin point of the shape, on the ending face of the object
|
||||
// start-centroid = When `closed==false`, the centroid of the shape, on the starting face of the object
|
||||
// end-centroid = When `closed==false`, the centroid of the shape, on the ending face of the object
|
||||
// Example(NoScales): A simple sweep of a square along a sine wave:
|
||||
// path = [for(theta=[-180:5:180]) [theta/10, 10*sin(theta)]];
|
||||
// sq = square(6,center=true);
|
||||
|
@ -1759,39 +1767,74 @@ module spiral_sweep(poly, h, r, turns=1, taper, r1, r2, d, d1, d2, internal=fals
|
|||
// path_sweep(left(.05,square([1.1,1])), curve, closed=true,
|
||||
// method="manual", normal=UP);
|
||||
// }
|
||||
// Example(Med,NoScales,VPR=[78.1,0,43.2],VPT=[2.18042,-0.485127,1.90371],VPD=74.4017): The "start" and "end" anchors are located at the origin point of the swept shape.
|
||||
// shape = back_half(right_half(star(n=5,id=5,od=10)),y=-1);
|
||||
// path = arc(angle=[0,180],d=30);
|
||||
// path_sweep(shape,path,method="natural"){
|
||||
// attach(["start","end"]) anchor_arrow(s=5);
|
||||
// }
|
||||
// Example(Med,NoScales,VPR=[78.1,0,43.2],VPT=[2.18042,-0.485127,1.90371],VPD=74.4017): The "start" and "end" anchors are located at the origin point of the swept shape.
|
||||
// shape = back_half(right_half(star(n=5,id=5,od=10)),y=-1);
|
||||
// path = arc(angle=[0,180],d=30);
|
||||
// path_sweep(shape,path,method="natural"){
|
||||
// attach(["start-centroid","end-centroid"]) anchor_arrow(s=5);
|
||||
// }
|
||||
// Example(Med,NoScales,VPR=[78.1,0,43.2],VPT=[2.18042,-0.485127,1.90371],VPD=74.4017): Note that the "start" anchors are backwards compared to the direction of the sweep, so you have to attach the TOP to align the shape with its ends.
|
||||
// shape = back_half(right_half(star(n=5,id=5,od=10)),y=-1)[0];
|
||||
// path = arc(angle=[0,180],d=30);
|
||||
// path_sweep(shape,path,method="natural",scale=[1,1.5])
|
||||
// recolor("red"){
|
||||
// attach("start",TOP) stroke([path3d(shape)],width=.5);
|
||||
// attach("end") stroke([path3d(yscale(1.5,shape))],width=.5);
|
||||
// }
|
||||
|
||||
module path_sweep(shape, path, method="incremental", normal, closed, twist=0, twist_by_length=true, scale=1, scale_by_length=true,
|
||||
symmetry=1, last_normal, tangent, uniform=true, relaxed=false, caps, style="min_edge", convexity=10,
|
||||
anchor="origin",cp="centroid",spin=0, orient=UP, atype="hull",profiles=false,width=1)
|
||||
{
|
||||
dummy = assert(is_region(shape) || is_path(shape,2), "shape must be a 2D path or region");
|
||||
vnf = path_sweep(shape, path, method, normal, closed, twist, twist_by_length, scale, scale_by_length,
|
||||
symmetry, last_normal, tangent, uniform, relaxed, caps, style);
|
||||
|
||||
if (profiles){
|
||||
dummy = assert(is_region(shape) || is_path(shape,2), "shape must be a 2D path or region")
|
||||
assert(in_list(atype, _ANCHOR_TYPES), "Anchor type must be \"hull\" or \"intersect\"");
|
||||
tran = path_sweep(shape, path, method, normal, closed, twist, twist_by_length, scale, scale_by_length,
|
||||
symmetry, last_normal, tangent, uniform, relaxed,transforms=true);
|
||||
trans_scale = path_sweep(shape, path, method, normal, closed, twist, twist_by_length, scale, scale_by_length,
|
||||
symmetry, last_normal, tangent, uniform, relaxed, caps, style, transforms=true,_return_scales=true);
|
||||
transforms = trans_scale[0];
|
||||
scales = trans_scale[1];
|
||||
firstscale = is_num(scales[0]) ? 1/scales[0] : [1/scales[0].x, 1/scales[0].y];
|
||||
lastscale = is_num(last(scales)) ? 1/last(scales) : [1/last(scales).x, 1/last(scales).y];
|
||||
vnf = sweep(is_path(shape)?clockwise_polygon(shape):shape, transforms, closed=false, caps=caps,style=style);
|
||||
shapecent = point3d(centroid(shape));
|
||||
$transforms = transforms;
|
||||
$scales = scales;
|
||||
anchors = closed ? []
|
||||
:
|
||||
[
|
||||
named_anchor("start", rot=transforms[0]*scale(firstscale), flip=true),
|
||||
named_anchor("end", rot=last(transforms)*scale(lastscale)),
|
||||
named_anchor("start-centroid", rot=transforms[0]*move(shapecent)*scale(firstscale), flip=true),
|
||||
named_anchor("end-centroid", rot=last(transforms)*move(shapecent)*scale(lastscale))
|
||||
];
|
||||
if (profiles){
|
||||
rshape = is_path(shape) ? [path3d(shape)]
|
||||
: [for(s=shape) path3d(s)];
|
||||
attachable(anchor,spin,orient, vnf=vnf, extent=atype=="hull", cp=cp) {
|
||||
for(T=tran) stroke([for(part=rshape)apply(T,part)],width=width);
|
||||
attachable(anchor,spin,orient, vnf=vnf, extent=atype=="hull", cp=cp, anchors=anchors) {
|
||||
for(T=transforms) stroke([for(part=rshape)apply(T,part)],width=width);
|
||||
children();
|
||||
}
|
||||
}
|
||||
else
|
||||
vnf_polyhedron(vnf,convexity=convexity,anchor=anchor, spin=spin, orient=orient, atype=atype, cp=cp)
|
||||
attachable(anchor,spin,orient,vnf=vnf,extent=atype=="hull", cp=cp,anchors=anchors){
|
||||
vnf_polyhedron(vnf,convexity=convexity);
|
||||
children();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function path_sweep(shape, path, method="incremental", normal, closed, twist=0, twist_by_length=true, scale=1, scale_by_length=true,
|
||||
symmetry=1, last_normal, tangent, uniform=true, relaxed=false, caps, style="min_edge", transforms=false,
|
||||
anchor="origin",cp="centroid",spin=0, orient=UP, atype="hull") =
|
||||
anchor="origin",cp="centroid",spin=0, orient=UP, atype="hull",_return_scales=false) =
|
||||
is_1region(path) ? path_sweep(shape=shape,path=path[0], method=method, normal=normal, closed=default(closed,true),
|
||||
twist=twist, scale=scale, scale_by_length=scale_by_length, twist_by_length=twist_by_length, symmetry=symmetry, last_normal=last_normal,
|
||||
tangent=tangent, uniform=uniform, relaxed=relaxed, caps=caps, style=style, transforms=transforms,
|
||||
anchor=anchor, cp=cp, spin=spin, orient=orient, atype=atype) :
|
||||
anchor=anchor, cp=cp, spin=spin, orient=orient, atype=atype, _return_scales=_return_scales) :
|
||||
let(closed=default(closed,false))
|
||||
assert(in_list(atype, _ANCHOR_TYPES), "Anchor type must be \"hull\" or \"intersect\"")
|
||||
assert(!closed || twist % (360/symmetry)==0, str("For a closed sweep, twist must be a multiple of 360/symmetry = ",360/symmetry))
|
||||
|
@ -1943,7 +1986,9 @@ function path_sweep(shape, path, method="incremental", normal, closed, twist=0,
|
|||
apply(transform_list[L], rshape)),
|
||||
dummy = ends_match ? 0 : echo("WARNING: ***** The points do not match when closing the model in path_sweep() *****")
|
||||
)
|
||||
transforms ? transform_list
|
||||
transforms && _return_scales
|
||||
? [transform_list,scale]
|
||||
: transforms ? transform_list
|
||||
: sweep(is_path(shape)?clockwise_polygon(shape):shape, transform_list, closed=false, caps=fullcaps,style=style,
|
||||
anchor=anchor,cp=cp,spin=spin,orient=orient,atype=atype);
|
||||
|
||||
|
|
|
@ -1242,7 +1242,36 @@ create using `linear_extrude()` or `rotate_extrude()`.
|
|||
To make a shape attachable, you just need to wrap it with an `attachable()` module with a
|
||||
basic description of the shape's geometry. By default, the shape is expected to be centered
|
||||
at the origin. The `attachable()` module expects exactly two children. The first will be
|
||||
the shape to make attachable, and the second will be `children()`, literally.
|
||||
the shape to make attachable, and the second will be `children()`,
|
||||
literally.
|
||||
|
||||
### Pass-through Attachables
|
||||
The simplest way to make your own attachable module is to simply pass
|
||||
through to a pre-existing attachable submodule. This could be
|
||||
appropriate if you want to rename a module, or if the anchors of an
|
||||
existing module are suited to (or good enough for) your object. In
|
||||
order for your attachable module to work properly you need to accept
|
||||
the `anchor`, `spin` and `orient` parameters, give them suitable
|
||||
defaults, and pass them to the attachable submodule. Don't forget to
|
||||
pass the children to the attachable submodule as well, or your new
|
||||
module will ignore its children.
|
||||
|
||||
```openscad-3D
|
||||
include <BOSL2/std.scad>
|
||||
module cutcube(anchor=CENTER,spin=0,orient=UP)
|
||||
{
|
||||
tag_scope(){
|
||||
diff()
|
||||
cuboid(15, rounding=2, anchor=anchor,spin=spin,orient=orient){
|
||||
tag("remove")attach(TOP)cuboid(5);
|
||||
children();
|
||||
}
|
||||
}
|
||||
}
|
||||
diff()
|
||||
cutcube()
|
||||
tag("remove")attach(RIGHT) cyl(d=2,h=8);
|
||||
```
|
||||
|
||||
### Prismoidal/Cuboidal Attachables
|
||||
To make a cuboidal or prismoidal shape attachable, you use the `size`, `size2`, and `offset`
|
||||
|
|
Loading…
Reference in a new issue