Compare commits

..

1 commit

Author SHA1 Message Date
adrianVmariano
4d1d81b883
Merge 7da26d32cd into d8214cc0e1 2024-09-28 12:44:34 +00:00
2 changed files with 20 additions and 135 deletions

View file

@ -12,7 +12,6 @@
// FileFootnotes: STD=Included in std.scad
//////////////////////////////////////////////////////////////////////
include<structs.scad>
// Default values for attachment code.
$tags=undef; // for backward compatibility
@ -779,12 +778,7 @@ function _make_anchor_legal(anchor,geom) =
// Note that spin is not permitted for
// 2D objects because it would change the child orientation so that the anchors are no longer parallel.
// When you use `align=` you can also adjust the position using `inset=`, which shifts the child
// away from the edge or corner it is aligned to.
// .
// Note that the concept of alignment doesn't always make sense for objects without corners, such as spheres or cylinders.
// In same cases the alignments using such children will be odd because the alignment computation is trying to
// place a non-existent corner somewhere. Because attach() doesn't have in formation about the child when
// it runs it cannot handle curved shapes differently from cubes, so this behavior cannot be changed.
// away from the edge or corner it is aligned to.
// .
// If you give `inside=true` then the anchor arrows are lined up so they are pointing the same direction and
// the child object will be located inside the parent. In this case a default "remove" tag is applied to
@ -837,8 +831,6 @@ function _make_anchor_legal(anchor,geom) =
// `$attach_anchor` for each anchor given, this is set to the `[ANCHOR, POSITION, ORIENT, SPIN]` information for that anchor.
// if inside is true then set default tag to "remove"
// `$attach_to` is set to the value of the `child` argument, if given. Otherwise, `undef`
// `$edge_angle` is set to the angle of the edge if the anchor is on an edge and the parent is a prismoid or vnf with "hull" anchoring
// `$edge_length` is set to the length of the edge if the anchor is on an edge and the parent is a prismoid or vnf with "hull" anchoring
// Example: Cylinder placed on top of cube:
// cuboid(50)
// attach(TOP,BOT) cylinder(d1=30,d2=15,h=25);
@ -889,29 +881,6 @@ function _make_anchor_legal(anchor,geom) =
// attach(RIGHT+FRONT, TOP, inside=true) cuboid([10,3,5]);
// attach(RIGHT+FRONT, TOP, inside=true, align=TOP,shiftout=.01) cuboid([5,1,2]);
// }
// Example: Attaching a 3d edge mask. Simple 2d masks can be done using {{edge_profile()}} but this mask varies along its length.
// module wavy_edge(length,cycles, r, steps, n)
// {
// rmin = is_vector(r) ? r[0] : 0.01;
// rmax = is_vector(r) ? r[1] : r;
// layers = [for(z=[0:steps])
// let(
// r=rmin+(rmax-rmin)/2*(cos(z*360*cycles/steps)+1),ff=echo(r=r)
// )
// path3d( concat([[0,0]],
// arc(corner=path2d([BACK,CTR,RIGHT]), n=n, r=r)),
// z/steps*length-length/2)
// ];
// attachable([rmax,rmax,length]){
// skin(layers,slices=0);
// children();
// }
// }
// diff()
// cuboid(25)
// attach([TOP+RIGHT,TOP+LEFT,TOP+FWD, FWD+RIGHT], FWD+LEFT, inside=true, shiftout=.01)
// wavy_edge(length=25.1,cycles=1.4,r=4,steps=24,n=15);
module attach(parent, child, overlap, align, spin=0, norot, inset=0, shiftout=0, inside=false, from, to)
{
@ -936,11 +905,10 @@ module attach(parent, child, overlap, align, spin=0, norot, inset=0, shiftout=0,
assert(is_undef(align) || !is_string(child), "child is a named anchor. Named anchors are not supported with align=");
two_d = _attach_geom_2d($parent_geom);
basegeom = $parent_geom[0]=="conoid" ? attach_geom(r=2,h=2,axis=$parent_geom[5])
: $parent_geom[0]=="prismoid" ? attach_geom(size=[2,2,2],axis=$parent_geom[4])
basegeom = $parent_geom[0]=="conoid" ? attach_geom(r=2,h=2)
: $parent_geom[0]=="spheroid" ? echo("here")attach_geom(r=2)
: attach_geom(size=[2,2,2]);
childgeom = attach_geom([2,2,2]);
child_abstract_anchor = is_vector(child) && !two_d ? _find_anchor(_make_anchor_legal(child,childgeom), childgeom) : undef;
child_abstract_anchor = is_vector(child) && !two_d ? _find_anchor(child, basegeom) : undef;
overlap = (overlap!=undef)? overlap : $overlap;
parent = first_defined([parent,from]);
anchors = is_vector(parent) || is_string(parent) ? [parent] : parent;
@ -967,49 +935,21 @@ module attach(parent, child, overlap, align, spin=0, norot, inset=0, shiftout=0,
: point3d(anchors[anch_ind]);
$anchor=anchor;
anchor_data = _find_anchor(anchor, $parent_geom);
$edge_angle = len(anchor_data)==5 ? struct_val(anchor_data[4],"edge_angle") : undef;
$edge_length = len(anchor_data)==5 ? struct_val(anchor_data[4],"edge_length") : undef;
anchor_pos = anchor_data[1];
anchor_dir = factor*anchor_data[2];
anchor_spin = two_d || !inside || anchor==TOP || anchor==BOT ? anchor_data[3]
: let(spin_dir = rot(anchor_data[3],from=UP, to=-anchor_dir, p=BACK))
_compute_spin(anchor_dir,spin_dir);
parent_abstract_anchor = is_vector(anchor) && !two_d ? _find_anchor(_make_anchor_legal(anchor,basegeom),basegeom) : undef;
parent_abstract_anchor = is_vector(anchor) && !two_d ? _find_anchor(anchor,basegeom) : undef;
for(align_ind = idx(align_list)){
align = is_undef(align_list[align_ind]) ? undef
: assert(is_vector(align_list[align_ind],2) || is_vector(align_list[align_ind],3), "align direction must be a 2-vector or 3-vector")
two_d ? _force_anchor_2d(align_list[align_ind])
: point3d(align_list[align_ind]);
spin = is_num(spin) ? spin
: align==CENTER ? 0
: sum(v_abs(anchor))==1 ? // parent anchor is a face
let(
spindir = in_list(anchor,[TOP,BOT]) ? BACK : UP,
proj = project_plane(point4d(anchor),[spindir,align]),
ang = v_theta(proj[1])-v_theta(proj[0])
)
ang
: // parent anchor is not a face, so must be an edge (corners not allowed)
let(
nativeback = apply(rot(to=parent_abstract_anchor[2],from=UP)
*affine3d_zrot(parent_abstract_anchor[3]), BACK)
)
nativeback*align<0 ? -180:0;
$idx = align_ind+len(align_list)*anch_ind;
$align=align;
goodcyl = $parent_geom[0] != "conoid" || is_undef(align) || align==CTR ? true
: let(
align=rot(from=$parent_geom[5],to=UP,p=align),
anchor=rot(from=$parent_geom[5],to=UP,p=anchor)
)
anchor==TOP || anchor==BOT || align==TOP || align==BOT;
badcorner = !in_list($parent_geom[0],["conoid","spheroid"]) && !is_undef(align) && align!=CTR && sum(v_abs(anchor))==3;
badsphere = $parent_geom[0]=="spheroid" && !is_undef(align) && align!=CTR;
dummy=assert(is_undef(align) || all_zero(v_mul(anchor,align)),
str("Invalid alignment: align value (",align,") includes component parallel to parent anchor (",anchor,")"))
assert(goodcyl, str("Cannot use align with an anchor on a curved edge or surface of a cylinder at parent anchor (",anchor,")"))
assert(!badcorner, str("Cannot use align at a corner anchor (",anchor,")"))
assert(!badsphere, "Cannot use align on spheres.");
str("Invalid alignment: align value (",align,") includes component parallel to parent anchor (",anchor,")"));
// Now compute position on the parent (including alignment but not inset) where the child will be anchored
pos = is_undef(align) ? anchor_data[1] : _find_anchor(anchor+align, $parent_geom)[1];
$attach_anchor = list_set(anchor_data, 1, pos); // Never used; For user informational use? Should this be set at all?
@ -1023,7 +963,7 @@ module attach(parent, child, overlap, align, spin=0, norot, inset=0, shiftout=0,
* affine3d_zrot(-parent_abstract_anchor[3])
* rot(from=parent_abstract_anchor[2],to=UP)
* rot(v=anchor,-spin),
align);
align);
// The $anchor_override anchor value forces an override of the *position* only for the anchor
// used when attachable() places the child
$anchor_override = all_zero(child_adjustment)? inside?child:undef
@ -3719,7 +3659,7 @@ function _get_cp(geom) =
/// Arguments:
/// anchor = Vector or named anchor string.
/// geom = The geometry description of the shape.
function _find_anchor(anchor, geom)=
function _find_anchor(anchor, geom) =
is_string(anchor)? (
anchor=="origin"? [anchor, CENTER, UP, 0] // Ok that this returns 3d anchor in the 2d case?
: let(
@ -3747,10 +3687,8 @@ function _find_anchor(anchor, geom)=
let(all_comps_good = [for (c=anchor) if (c!=sign(c)) 1]==[])
assert(all_comps_good, "All components of an anchor for a cuboid/prismoid must be -1, 0, or 1")
let(
size=geom[1],
size2=geom[2],
shift=point2d(geom[3]),
axis=point3d(geom[4]),
size=geom[1], size2=geom[2],
shift=point2d(geom[3]), axis=point3d(geom[4]),
override = geom[5](anchor)
)
let(
@ -3784,21 +3722,22 @@ function _find_anchor(anchor, geom)=
v3 = unit(line[1]-line[0],UP) * anch.z
)
unit(v3,UP),
edgeang = len(facevecs)==2 ? 180-vector_angle(facevecs[0], facevecs[1]) : undef,
final_dir = default(override[1],anch==CENTER?UP:rot(from=UP, to=axis, p=dir)),
final_pos = default(override[0],rot(from=UP, to=axis, p=pos)),
// If the anchor is on a face or horizontal edge we take the oang value for spin
// If the anchor is on a vertical or sloped edge or corner we want to align the spin to point upward along the edge
// Set "vertical" edge and corner anchors point along the edge
spin = anch.x!=0 && anch.y!=0 ? _compute_spin(final_dir, rot(from=UP, to=axis, p=edge))
// Horizontal anchors point clockwise
: anch.z!=0 && sum(v_abs(anch))==2 ? _compute_spin(final_dir, rot(from=UP, to=axis, p=anch.z*[anch.y,-anch.x,0]))
spin = anch.x!=0 && anch.y!=0 ? _compute_spin(final_dir, rot(from=UP, to=axis, p=edge)) // Set "vertical" edge and corner anchors point along the edge
: anch.z!=0 && sum(v_abs(anch))==2 ? _compute_spin(final_dir, rot(from=UP, to=axis, p=anch.z*[anch.y,-anch.x,0])) // Horizontal anchors point clockwise
: norm(anch)==3 ? _compute_spin(final_dir, final_dir==DOWN || final_dir==UP ? BACK : UP)
: oang // face anchors point UP/BACK
) [anchor, final_pos, final_dir, default(override[2],spin), if (is_def(edgeang)) [["edge_angle",edgeang],["edge_length",norm(edge)]]]
//spin = anchor.x!=0 && anchor.y!=0 ? _compute_spin(dir, edge)
// : anchor.z!=0 && (anchor.x!=0 || anchor.y!=0) ? _compute_spin(dir, _canonical_edge([anchor.y,anchor.x,0]))
// : oang
) [anchor, final_pos, final_dir, default(override[2],spin)]
) : type == "conoid"? ( //r1, r2, l, shift
assert(anchor.z == sign(anchor.z), "The Z component of an anchor for a cylinder/cone must be -1, 0, or 1")
let(
rr1=geom[1],
rr2=geom[2],
@ -3808,11 +3747,6 @@ function _find_anchor(anchor, geom)=
r1 = is_num(rr1)? [rr1,rr1] : point2d(rr1),
r2 = is_num(rr2)? [rr2,rr2] : point2d(rr2),
anch = rot(from=axis, to=UP, p=anchor),
axisname = axis==UP ? "Z"
: axis==RIGHT ? "X"
: axis==BACK ? "Y"
: "",
dummy = assert(anch.z == sign(anch.z), str("The ",axisname," component of an anchor for the cylinder/cone must be -1, 0, or 1")),
offset = rot(from=axis, to=UP, p=offset),
u = (anch.z+1)/2,
// Returns [point,tangent_dir]
@ -3974,8 +3908,8 @@ function _find_anchor(anchor, geom)=
edgedir = edge[1]-edge[0]
)
_compute_spin(direction, flip*edgedir)
)
[direction,spin,[["edge_angle",ang],["edge_length",norm(edge[0]-edge[1])]]]
)
[direction,spin]
: let( // This section handles corner anchors, currently spins just point up
vertices = vnf[0],
faces = vnf[1],
@ -3994,7 +3928,7 @@ function _find_anchor(anchor, geom)=
avep = sum(select(rpts,idxs))/len(idxs),
mpt = approx(point2d(anchor),[0,0])? [maxx,0,0] : avep,
pos = point3d(cp) + rot(from=RIGHT, to=anchor, p=mpt)
) [anchor, default(override[0],pos),default(override[1],dir[0]),default(override[2],dir[1]),if (len(dir)==3) dir[2]]
) [anchor, default(override[0],pos),default(override[1],dir[0]),default(override[2],dir[1])]
) : type == "trapezoid"? ( //size, size2, shift, override
let(all_comps_good = [for (c=anchor) if (c!=sign(c)) 1]==[])
assert(all_comps_good, "All components of an anchor for a rectangle/trapezoid must be -1, 0, or 1")

View file

@ -681,55 +681,6 @@ prismoid(150,60,100)
show_anchors(s=45);
```
Is is also possible to attach to edges and corners of the parent
object. The anchors for edges spin the child so its BACK direction is
aligned with the edge. If the edge belongs to a top or bottom
horizontal face, then the BACK directions will point clockwise around
the face, as seen from outside the shape. (This is the same direction
required for construction of valid faces in OpenSCAD.) Otherwise, the
BACK direction will point upwards.
Examine the red flags below, where only edge anchors appear on a
prismoid. The top face shows the red flags pointing clockwise.
The sloped side edges point along the edges, generally upward, and
the bottom ones appear to point counter-clockwise, but if we viewed
the shape from the bottom they would also appear clockwise.
```openscad-3D;Big
include <BOSL2/std.scad>
prismoid([100,175],[55,88], h=55)
for(i=[-1:1], j=[-1:1], k=[-1:1])
let(anchor=[i,j,k])
if (sum(v_abs(anchor))==2)
attach(anchor,BOT)anchor_arrow(40);
```
In this example cylinders sink half-way into the top edges of the
prismoid:
```openscad-3D;Big
include <BOSL2/std.scad>
$fn=16;
r=6;
prismoid([100,175],[55,88], h=55){
attach([TOP+RIGHT,TOP+LEFT],LEFT,overlap=r/2) cyl(r=r,l=88+2*r,rounding=r);
attach([TOP+FWD,TOP+BACK],LEFT,overlap=r/2) cyl(r=r,l=55+2*r, rounding=r);
}
```
This type of edge attachment is useful for attaching 3d edge masks to
edges:
```openscad-3D;Big
include <BOSL2/std.scad>
$fn=32;
diff()
cuboid(75)
attach([FRONT+LEFT, FRONT+RIGHT, BACK+LEFT, BACK+RIGHT],
FWD+LEFT,inside=true)
rounding_edge_mask(l=76, r1=8,r2=28);
```
## Parent-Child Anchor Attachment (Double Argument Attachment)
The `attach()` module has two different modes of operation,