doc fixes, add spin to attach_prism()

This commit is contained in:
Adrian Mariano 2025-11-14 06:11:18 -05:00
parent 0deea857d7
commit c0981763e7
3 changed files with 30 additions and 19 deletions

View file

@ -779,22 +779,20 @@ function _make_anchor_legal(anchor,geom) =
// do `attach(RIGHT,BOT)` this puts the bottom of the child onto the right anchor of the parent.
// When an object is attached to the top or bottom, its BACK direction remains pointing BACK.
// When an object is attached to one of the other anchors its FRONT is pointed DOWN and its
// BACK pointed UP. You can change this using the `spin=` argument to attach(). Note that this spin
// BACK pointed UP. You can change this using the `spin=` argument to attach(). This spin
// rotates around the attachment vector and is not the same as the spin argument to the child, which
// will usually rotate around some other direction that may be hard to predict. For 2D objects you cannot
// give spin because it is not possible to spin around the attachment vector; spinning the object around the Z axis
// would change the child orientation so that the anchors are no longer parallel. Furthermore, any spin
// will usually rotate around some other direction that may be hard to predict. Any spin
// parameter you give to the child is ignored so that the attachment condition of parallel anchors is preserved.
// For 2D objects you cannot give spin because it is not possible to spin around the attachment vector;
// spinning the object around the Z axis would change the child orientation so that the anchors are no longer parallel.
// .
// As with {{align()}} you can use the `align=` parameter to align the child to an edge or corner of the
// face where that child is attached. For example, `attach(TOP,BOT,align=RIGHT)` would stand the child
// up on the top while aligning it with the right edge of the top face, and `attach(RIGHT,BOT,align=TOP)`, which
// stand the object on the right face while aligning with the top edge. If you apply spin using the
// argument to `attach()`, then it is taken into account for the alignment. However, if you apply spin with
// argument to `attach()`, then it is taken into account for the alignment. However, if you apply spin as
// a parameter to the child, it is **not** taken into account. The special spin value "align"
// spins the child so that the child's BACK direction is pointed toward the aligned edge on the parent.
// 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.
// .
@ -845,7 +843,7 @@ function _make_anchor_legal(anchor,geom) =
// overlap = Amount to sink child into the parent. Equivalent to `down(X)` after the attach. This defaults to the value in `$overlap`, which is `0` by default.
// inside = If `child` is given you can set `inside=true` to attach the child to the inside of the parent for diff() operations. Default: false
// shiftout = Shift an inside object outward so that it overlaps all the aligned faces. Default: 0
// spin = Amount to rotate the parent around the axis of the parent anchor. Can set to "align" to align the child's BACK with the parent aligned edge. (Permitted only in 3D.)
// spin = Angle to rotate the child around the axis of the parent anchor. Can set to "align" to align the child's BACK with the parent aligned edge. (Permitted only in 3D.)
// Side Effects:
// `$anchor` set to the parent anchor value used for the child.
// `$align` set to the align value used for the child.

View file

@ -46,6 +46,7 @@ function _inset_corner(corner, mask_angle, inset, excess, flat_top) =
// If called as a function, returns a 2D path of the outline of the mask shape.
// .
// The roundover can be specified by radius, diameter, height, cut, or joint length.
// .
// ![Types of Roundovers](images/rounding/figure_1_1.png)
// .
// If you need roundings to agree on edges of different mask_angle, e.g. to round the base of a prismoid, then you need all of the
@ -253,10 +254,12 @@ function mask2d_roundover(r, inset=0, mask_angle=90, excess=0.01, clip_angle, fl
// If called as a function, returns a 2D path of the outline of the mask shape.
// .
// The roundover can be specified by joint length or cut distance. (Radius is not meaningful for this type of mask.) You must also specify the
// continuous curvature smoothness parameter, `k`, which defaults to 0.5. This diagram shows a roundover for the default k value.
// continuous curvature smoothness parameter, `k`, which defaults to 0.5. This diagram shows a roundover for the default k value.
// .
// ![Types of Roundovers](images/rounding/figure_1_2.png)
// .
// With `k=0.75` the transition into the roundover is shorter and faster. The cut length is bigger for the same joint length.
// .
// ![Types of Roundovers](images/rounding/figure_1_3.png)
// .
// The diagrams above show symmetric roundovers, but you can also create asymmetric roundovers by giving a list of two values for `joint`. In this
@ -375,6 +378,7 @@ module mask2d_smooth(mask_angle, cut, joint, height, h, k=0.5, excess=.01, inset
// If called as a function, returns a 2D path of the outline of the mask shape.
// This is particularly useful to make partially rounded bottoms, that don't need support to print.
// The roundover can be specified by radius, diameter, height, cut, or joint length.
// .
// ![Types of Roundovers](images/rounding/figure_1_1.png)
// Arguments:
// r = Radius of the rounding.

View file

@ -2226,7 +2226,7 @@ function _rp_compute_patches(top, bot, rtop, rsides, ktop, ksides, concave) =
// value and the rounding is symmetric around each edge. However, you can specify a 2-vector for the joint distance to produce asymmetric
// rounding which is different on the two sides of the edge. This may be useful when one one edge in your polygon is much larger than another.
// For the top and bottom you can specify negative joint distances. If you give a scalar negative value, then the roundover flares
// outward. If you give a vector value then a negative value, then if `joint_top[0]` is negative the shape flares outward, but if
// outward. If you give a vector value then if `joint_top[0]` is negative the shape flares outward, but if
// `joint_top[1]` is negative, the shape flares upward. At least one value must be non-negative. The same rules apply for joint_bot.
// The joint_sides parameter must be entirely nonnegative.
// .
@ -4878,7 +4878,7 @@ module prism_connector(profile, desc1, anchor1, desc2, anchor2, shift1, shift2,
// when the anchor point is not on the surface.
// .
// If you specify a length or height then he prism normally appears in the anchor direction, perpendicular to the parent object. You can
// adjust its angle by setting the transoformation. For example, `T=xrot(20)` will rotate the prism so it is a 20 deg angle. It will shift
// adjust its angle by setting the transformation. For example, `T=xrot(20)` will rotate the prism so it is a 20 deg angle. It will shift
// to the right as seen from above. The transformation applies in the anchored coordinate system where Z is perpendicular to the parent
// and Y points in the spin direction. When `T` is a rotation the face of the prism will be perpendicular to the prism axis.
// You can also specify the prism endpoint as a point in space, again in the anchored coordinate system. In this case you cannot give
@ -4900,6 +4900,11 @@ module prism_connector(profile, desc1, anchor1, desc2, anchor2, shift1, shift2,
// Normally {{join_prism()}} will issue an error in this situation. The `debug` parameter is passed through to {{join_prism()}} and
// tells that module to display invalid self-intersecting geometry to help you understand the problem.
// .
// The `overlap` parameter creates an extension of the prism into the parent object. Unlike `overlap` for {{attach()}} it actually extends
// the prism rather than shifting it by the overlap. When connecting to curved parent objects, be sure the overlap is sufficient or you may
// create a hole in between the prism and its parent. When subtracting a prism to create a hole, insufficient overlap will leave parts of
// the parent object behind, blocking the hole.
// .
// When connecting to an edge, artifacts may occur at the corners where the prism doesn't meet the object in the ideal fashion.
// Adjsting the points on your prism profile so that a point falls close to the corner will achieve the best result, and make sure
// that `smooth_normals` is disabled (the default for edges) because it results in a completely incorrect fillet in this case.
@ -4920,6 +4925,7 @@ module prism_connector(profile, desc1, anchor1, desc2, anchor2, shift1, shift2,
// inside = if true attach the prism on the inside of the parent for diff() operations. Default: false
// shift = shift anchor point, a scalar for cylinders, extrusions, or edges, a 2-vector for faces, not permitted for spheres
// scale = scale the profile by this factor at the end. Default: 1
// spin = angle to rotate the prism around its axis before attaching it. Default: 0
// edge_r = when attaching to an edge, assume it has a circular rounding with this radius
// n = number of facets to use for fillets and roundings
// n_base = number of facets to use for fillets at the base
@ -4947,6 +4953,9 @@ module prism_connector(profile, desc1, anchor1, desc2, anchor2, shift1, shift2,
// Example(3D): Attaching to sphere with scaling of the prism
// sphere(d=20)
// attach_prism(circle(r=4,$fn=64), RIGHT+TOP+FWD, fillet=2, rounding=1.5, l=7, scale=.5);
// Example(3D): Here we've attached a rectangular prism to a cylinder. It makes a nice joint at the sides but the top doesn't look right. This is because {{rect()}} only provides four points, which is not sufficient to match the curvature of the cylinder. You need to resample with {{subdivide_path()}} or some other reampling method as shown in the next example.
// cyl(d=10,h=8)
// attach_prism(rect(4), FWD+RIGHT, 1/2, rounding=1/2, l=4, edge_r=2);
// Example(3D): Attaching to an extrusion. Here we used a rounded rectangle and resample it to ensure enough points to match the curve of the ellipse.
// $fn=128;
// rr = subdivide_path(rect(7,rounding=2), maxlen=.5);
@ -4968,14 +4977,14 @@ module prism_connector(profile, desc1, anchor1, desc2, anchor2, shift1, shift2,
// Example(3D): Adjusting prism angle with a transformation. The prism end is perpendicular to the prism axis.
// cuboid(20)
// attach_prism(circle(r=4,$fn=32), FWD, fillet=1, rounding=1.5, l=10, T=xrot(-20));
// Example(3D): Creating a hole
// Example(3D): Creating a hole. The default overlap is too small to fully clear out the hole.
// diff()
// cyl(d=20,h=22,$fn=128*2)
// attach_prism(circle(r=6,$fn=64), RIGHT+FWD, inside=true,
// fillet=2, rounding=3, l=8, overlap=2);
module attach_prism(profile, anchor, fillet=0, rounding=0, inside=false, l, length, h, height, endpoint, T=IDENT, shift=0, overlap=1,
n,n_base, n_end, k, k_base, k_end, uniform=true, smooth_normals, edge_r, debug=false, scale=1)
n,n_base, n_end, k, k_base, k_end, uniform=true, smooth_normals, edge_r, debug=false, scale=1, spin=0)
{
length = one_defined([l, h, length, height],"l,h,length,height",dflt=undef);
profile = force_path(profile,"profile");
@ -4999,7 +5008,7 @@ module attach_prism(profile, anchor, fillet=0, rounding=0, inside=false, l, leng
type = _get_obj_type(undef,$parent_geom,anchor,profile,edge_r);
offset = in_list(type,["cyl","sphere"]) ? (inside?-1:1)*$parent_geom[1] : 0;
base_r = (inside?-1:1)*(in_list(type,["cyl","sphere"]) ? $parent_geom[1] : 1);
spin = -90;
spinfix = -90;
base_edge = _is_geom_an_edge($parent_geom,anchor);
smooth_normals = default(smooth_normals, !base_edge);
@ -5009,13 +5018,13 @@ module attach_prism(profile, anchor, fillet=0, rounding=0, inside=false, l, leng
: assert(is_finite(shift) || is_vector(shift,2), "Value for shift for a planar face must be a scalar or 2-vector")
force_list(shift,2,0);
T = is_def(endpoint) ? move([endpoint.y-shift.y,-endpoint.x-shift.x])
: zrot(spin)*T;
: zrot(spinfix)*T;
mod_type = is_list(type) && inside ? zrot(180,type) : type;
anchors = [named_anchor("end", is_def(endpoint) ? yrot(inside?180:0,endpoint) : point3d(shift)+apply(yrot(inside?180:0)*zrot(-spin)*T,[0,0,(inside?1:1)*length]),
is_def(endpoint) ? (inside?-1:1)*UP : unit( apply(yrot(inside?180:0)*zrot(-spin)*T,[0,0,length])-apply(zrot(-spin)*T,CTR)),
anchors = [named_anchor("end", is_def(endpoint) ? yrot(inside?180:0,endpoint) : point3d(shift)+apply(yrot(inside?180:0)*zrot(-spinfix)*T,[0,0,(inside?1:1)*length]),
is_def(endpoint) ? (inside?-1:1)*UP : unit( apply(yrot(inside?180:0)*zrot(-spinfix)*T,[0,0,length])-apply(zrot(-spinfix)*T,CTR)),
inside && is_undef(endpoint) ? 180 : 0)
];
vnf= join_prism(zrot(spin,profile), mod_type, base_r=base_r,
vnf= join_prism(zrot(spin+spinfix,profile), mod_type, base_r=base_r,
l=is_def(endpoint)?endpoint.z:length,
prism_end_T=T,
base_fillet=fillet,
@ -5028,7 +5037,7 @@ module attach_prism(profile, anchor, fillet=0, rounding=0, inside=false, l, leng
translate(shift)
yrot(inside?180:0)
down(offset)
zrot(-spin)
zrot(-spinfix)
vnf_polyhedron(vnf);
children();
}