Hello all,
I've tried (again) to learn how attaching and anchoring works with BOSL2,
as I have a feeling that it will solve much of the tediousness I experience
when programming models with openscad. Unlike previous attempts at learning
this, this time I sat down and read both the manual and the
https://github.com/BelfrySCAD/BOSL2/wiki/Tutorial-Attachments tutorial
front to back (I'll admit that I sort of glossed over the parts of the
manual where it just became too much of a jargon mumble for me to
understand). And while I do feel that I sort of get the nuances of the
terminology now, in the first test project I want to apply it to, I'm
already hitting a roadblock pretty much straight away.
I have a snap-in clip hook (sorry don't know a better word) which consists
of a few cubes, plus a filleted and extruded 2d shape (example of complete
part in fig 1 below). I thought I could make the clip a separate module,
and the base and sides another, define attachment points and which way is
'up' on both. So like figs 2 and 3 below. And then say 'instantiate module
'base' as well as module 'clip', and position it so that points A and B
touch'. And then I could maybe also define an attachment point at the back
of the base of the clip, and use it with the BOSL2 fillet() module with the
right position and alignment, so that I get the result in fig 4. While in
this concrete example the number of lines of codes wouldn't be drastically
different, my idea of the goal of attachments (and what I'd like to use it
for) is that I could move to a mental model where I first construct simple
parts at the origin, and then assemble them together in a final step, using
attachment points defined in the smaller parts - so without having to do
translations and rotations that depend on the exact sizes of the individual
parts, which are quite often details that are local yet have to be stored
in global variables to make this positioning possible, at least if you want
to prevent a lot of ad hoc argument passing.
There are lots of examples of how to set various points on simple shapes in
the tutorial, but how do I go about setting attachment points on 'compound
shapes', even ones as simple as those presented here?
I've included the stripped down code at the bottom to clarify what I've
been doing.
Thanks.
Fig 1:
[image: image.png]
Fig 2:
[image: image.png]
Fig 3:
[image: image.png]
Fig 4:
[image: image.png]
include <BOSL2-master/std.scad>
include <BOSL2-master/transforms.scad>
clip_width = 10;
clip_height = 30;
clip_thickness = 2; // Thickness of the 'spring' part
hook_height = 10;
hook_depth = 2.5;
hook_press_length = 7;
hook_fillet_radius = 1;
hook_clearance = 0.2; // Distance to keep between parts that should fit
into each other snugly but without friction.
base_depth = 7;
base_width = 20;
base_height = 10;
side_clip_distance = 1; // Distance between the clip and the stems next to
it.
female_wall_thickness = 2;
female_play = 0.2;
// Calculated variables
side_width = (base_width - clip_width - (2 * side_clip_distance)) / 2;
// This is the width of the stems on the left and right of the clip
// Copied from OpenSCAD manual for offset(), but there, the r/-r are
swapped and that version doesn't work.
module fillet_2d_shape(r) {
offset(r = r) {
offset(delta = -r) {
children();
}
}
}
module hook2(extra_clearance) {
up(base_height) xrot(90) yrot(90)
union() {
linear_extrude(clip_width + (2 * extra_clearance), center=false)
union() {
//p1 = [0, 0];
//p2 = [clip_thickness, 0];
p2 = [clip_thickness, clip_height - hook_height -
hook_press_length];
p3 = [clip_thickness, clip_height];
p4 = [0, clip_height];
p5 = [-hook_depth, clip_height - hook_height];
p6 = [-hook_depth, clip_height - hook_height -
hook_press_length];
p7 = [0, clip_height - hook_height - hook_press_length];
fillet_2d_shape(hook_fillet_radius)
polygon(points = [ p2, p3, p4, p5, p6, p7 ]);
square([clip_thickness, clip_height - hook_height]);
};
up(clip_width / 2) right(clip_thickness)
fillet(clip_width, base_depth - clip_thickness, orient=UP);
}
}
module frame(extra_clearance) {
cube([base_width + (2 * extra_clearance), base_depth + (2 *
extra_clearance), base_height + extra_clearance]);
// Sides
up(base_height)
cube([side_width, base_depth + (2 * extra_clearance), clip_height +
extra_clearance]);
up(base_height) right(base_width - side_width + (2 * extra_clearance))
cube([side_width, base_depth + (2 * extra_clearance), clip_height +
extra_clearance]);
}
module snap_fit_male(extra_clearance) {
frame(extra_clearance);
right(side_width + side_clip_distance)
hook2(extra_clearance);
}
module snap_fit_female() {
difference() {
total_female_width = base_width + (2 * female_wall_thickness) + (2
hook_clearance);
cube([ total_female_width,
base_depth + (2 * female_wall_thickness) + (2 * hook_clearance),
base_height + clip_height + female_wall_thickness]);
// Render the male part with slight clearance, so that it fits less
loose.
right(female_wall_thickness + hook_clearance)
back(female_wall_thickness + hook_clearance)
union() {
hull()
frame(hook_clearance);
snap_fit_male(hook_clearance);
}
// Cut an extra 'groove' on the backside, so that the clip (when it
slides in) has some more room to be pressed
// down into the female enclosure.
groove_width = clip_width + (side_clip_distance * 2);
groove_depth = 1;
groove_length = clip_height;
back(base_depth + hook_clearance + female_wall_thickness)
right((total_female_width / 2) - (groove_width / 2)) up(groove_depth)
#cube([groove_width, groove_depth, groove_length]);
// Chamfer the front inside a little bit, so the clip can slide in
more easily.
chamfer_angle = 60;
//sin(20) = x / female_wall_thickness
y_offset = sin(chamfer_angle) * female_wall_thickness;
z_offset = cos(chamfer_angle) * female_wall_thickness;
back(y_offset + (female_wall_thickness / 2)) down(z_offset)
xrot(chamfer_angle) right((total_female_width / 2) -
(groove_width / 2)) back()
#cube([groove_width, female_wall_thickness * 2,
female_wall_thickness]);
}
}
snap_fit_male(0);
right(50)
snap_fit_female();
To create an object with anchor points you use the attachable() module,
possibly with named anchors to provide for special attachment points.
However, I think you probably want to reserve the use of this module for
actual finished parts, or components that will get a lot of use. It's not
the easiest process to create well-behaved attachable modules, so I don't
think it makes sense to do it for intermediate one-off parts of a larger
model. (It will basically be no easier than manually placing the part
where it needed to go.)
In the case of the object you show, I'd probably create a cuboid base.
That has attachable point A available. Then you create the two side parts
by attaching them with align(). Then you can position() the fillet on top
and likewise the extruded part (which needs to be constructed so B is at
the origin). If you plan to use the extruded part repeatedly it could make
sense to wrap it with attachable() and create the You might be able to get
linear_sweep to put an attachment point at B, but it is probably not worth
the trouble, and could fail down the road if you change the dimensions of
the part.
Once you have the final part constructed, then it makes sense to wrap it in
attachable() and create any named anchors that seem useful.
Your code could make more use of attachments. I would make the basic
shape like this:
cuboid([10,5,5]){
xflip_copy() align(TOP+RIGHT) cuboid([2,5,10]);
}
When constructing a part I usually use position() or align() for every
part that I add to the basic part, because positions relative to the part
make more sense than absolute positions.
On Wed, Jan 31, 2024 at 10:46 AM Roel Vanhout via Discuss <
discuss@lists.openscad.org> wrote:
Hello all,
I've tried (again) to learn how attaching and anchoring works with BOSL2,
as I have a feeling that it will solve much of the tediousness I experience
when programming models with openscad. Unlike previous attempts at learning
this, this time I sat down and read both the manual and the
https://github.com/BelfrySCAD/BOSL2/wiki/Tutorial-Attachments tutorial
front to back (I'll admit that I sort of glossed over the parts of the
manual where it just became too much of a jargon mumble for me to
understand). And while I do feel that I sort of get the nuances of the
terminology now, in the first test project I want to apply it to, I'm
already hitting a roadblock pretty much straight away.
I have a snap-in clip hook (sorry don't know a better word) which consists
of a few cubes, plus a filleted and extruded 2d shape (example of complete
part in fig 1 below). I thought I could make the clip a separate module,
and the base and sides another, define attachment points and which way is
'up' on both. So like figs 2 and 3 below. And then say 'instantiate module
'base' as well as module 'clip', and position it so that points A and B
touch'. And then I could maybe also define an attachment point at the back
of the base of the clip, and use it with the BOSL2 fillet() module with the
right position and alignment, so that I get the result in fig 4. While in
this concrete example the number of lines of codes wouldn't be drastically
different, my idea of the goal of attachments (and what I'd like to use it
for) is that I could move to a mental model where I first construct simple
parts at the origin, and then assemble them together in a final step, using
attachment points defined in the smaller parts - so without having to do
translations and rotations that depend on the exact sizes of the individual
parts, which are quite often details that are local yet have to be stored
in global variables to make this positioning possible, at least if you want
to prevent a lot of ad hoc argument passing.
There are lots of examples of how to set various points on simple shapes
in the tutorial, but how do I go about setting attachment points on
'compound shapes', even ones as simple as those presented here?
I've included the stripped down code at the bottom to clarify what I've
been doing.
Thanks.
Fig 1:
[image: image.png]
Fig 2:
[image: image.png]
Fig 3:
[image: image.png]
Fig 4:
[image: image.png]
include <BOSL2-master/std.scad>
include <BOSL2-master/transforms.scad>
clip_width = 10;
clip_height = 30;
clip_thickness = 2; // Thickness of the 'spring' part
hook_height = 10;
hook_depth = 2.5;
hook_press_length = 7;
hook_fillet_radius = 1;
hook_clearance = 0.2; // Distance to keep between parts that should fit
into each other snugly but without friction.
base_depth = 7;
base_width = 20;
base_height = 10;
side_clip_distance = 1; // Distance between the clip and the stems next to
it.
female_wall_thickness = 2;
female_play = 0.2;
// Calculated variables
side_width = (base_width - clip_width - (2 * side_clip_distance)) / 2;
// This is the width of the stems on the left and right of the clip
// Copied from OpenSCAD manual for offset(), but there, the r/-r are
swapped and that version doesn't work.
module fillet_2d_shape(r) {
offset(r = r) {
offset(delta = -r) {
children();
}
}
}
module hook2(extra_clearance) {
up(base_height) xrot(90) yrot(90)
union() {
linear_extrude(clip_width + (2 * extra_clearance),
center=false)
union() {
//p1 = [0, 0];
//p2 = [clip_thickness, 0];
p2 = [clip_thickness, clip_height - hook_height -
hook_press_length];
p3 = [clip_thickness, clip_height];
p4 = [0, clip_height];
p5 = [-hook_depth, clip_height - hook_height];
p6 = [-hook_depth, clip_height - hook_height -
hook_press_length];
p7 = [0, clip_height - hook_height -
hook_press_length];
fillet_2d_shape(hook_fillet_radius)
polygon(points = [ p2, p3, p4, p5, p6, p7 ]);
square([clip_thickness, clip_height - hook_height]);
};
up(clip_width / 2) right(clip_thickness)
fillet(clip_width, base_depth - clip_thickness, orient=UP);
}
}
module frame(extra_clearance) {
cube([base_width + (2 * extra_clearance), base_depth + (2 *
extra_clearance), base_height + extra_clearance]);
// Sides
up(base_height)
cube([side_width, base_depth + (2 * extra_clearance), clip_height
module snap_fit_male(extra_clearance) {
frame(extra_clearance);
right(side_width + side_clip_distance)
hook2(extra_clearance);
}
module snap_fit_female() {
difference() {
total_female_width = base_width + (2 * female_wall_thickness) + (2
hook_clearance);
cube([ total_female_width,
base_depth + (2 * female_wall_thickness) + (2 *
hook_clearance),
base_height + clip_height + female_wall_thickness]);
// Render the male part with slight clearance, so that it fits
less loose.
right(female_wall_thickness + hook_clearance)
back(female_wall_thickness + hook_clearance)
union() {
hull()
frame(hook_clearance);
snap_fit_male(hook_clearance);
}
// Cut an extra 'groove' on the backside, so that the clip (when
it slides in) has some more room to be pressed
// down into the female enclosure.
groove_width = clip_width + (side_clip_distance * 2);
groove_depth = 1;
groove_length = clip_height;
back(base_depth + hook_clearance + female_wall_thickness)
right((total_female_width / 2) - (groove_width / 2)) up(groove_depth)
#cube([groove_width, groove_depth, groove_length]);
// Chamfer the front inside a little bit, so the clip can slide in
more easily.
chamfer_angle = 60;
//sin(20) = x / female_wall_thickness
y_offset = sin(chamfer_angle) * female_wall_thickness;
z_offset = cos(chamfer_angle) * female_wall_thickness;
back(y_offset + (female_wall_thickness / 2)) down(z_offset)
xrot(chamfer_angle) right((total_female_width / 2) -
(groove_width / 2)) back()
#cube([groove_width, female_wall_thickness * 2,
female_wall_thickness]);
}
}
snap_fit_male(0);
right(50)
snap_fit_female();
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org