Here's an example of how I sometimes chamfer joints using hull(). I have
found this useful but it would be more useful if a similar method could be
applied between parent and child objects using BOSL2's
positioning/alignment/attachment but I don't yet see a good way and would
love it if someone could help me do it.
module centered_scale(center_point, scale_vector) {
translate(center_point)
scale(scale_vector)
translate(-1*center_point)
children(0);
}
// chamfered joining of objects
// unions objects with a hull of those objects limited to the intersection
of the objects after scaling
// adjust object scale factors to change the size and angle of the chamfer
module hulled_join(centered_scales) {
union() {
children();
hull() intersection() {
intersection_for(i=[0:1:$children-1])
centered_scale(centered_scales[i][0], centered_scales[i][1])
children(i);
union()
children();
}
}
}
size1 = 10;
size2 = 5;
pos1 = [0,0,0];
pos2 = [size10.5+size20.3,0,0];
// EXAMPLE 1
hulled_join([
[pos1, (1+1.5/size1)[1,1,1]],
[pos2, (1+1.0/size2)[1,1,1]]
])
{
translate(pos1)
cube(10, center=true);
translate(pos2)
rotate(a=[20,20,0]) cube(5, center=true);
}
// EXAMPLE 2
translate([size12,0,0])
hulled_join([
[pos1, (1+1.0/size1)[1,1,1]],
[pos2, (1+1.3/size2)*[1,1,1]]
], $fn=128)
{
translate(pos1)
sphere(d=size1);
translate(pos2)
rotate(a=[90,20,0]) scale([1,0.5,1]) cylinder(h=size1, d=size2,
center=true);
}
You might be able to use descriptions to do this somehow, but I'm not
sure. See
https://github.com/BelfrySCAD/BOSL2/wiki/attachments.scad#section-attachable-descriptions-for-operating-on-attachables-or-restoring-a-previous-state
for descriptions. Mostly descriptions were implemented to support
prism_connector, so the examples of using them are mostly there:
https://github.com/BelfrySCAD/BOSL2/wiki/rounding.scad#module-prism_connector
On Sat, Dec 6, 2025 at 5:24 PM Todd Allen via Discuss <
discuss@lists.openscad.org> wrote:
Here's an example of how I sometimes chamfer joints using hull(). I have
found this useful but it would be more useful if a similar method could be
applied between parent and child objects using BOSL2's
positioning/alignment/attachment but I don't yet see a good way and would
love it if someone could help me do it.
module centered_scale(center_point, scale_vector) {
translate(center_point)
scale(scale_vector)
translate(-1*center_point)
children(0);
}
// chamfered joining of objects
// unions objects with a hull of those objects limited to the intersection
of the objects after scaling
// adjust object scale factors to change the size and angle of the chamfer
module hulled_join(centered_scales) {
union() {
children();
hull() intersection() {
intersection_for(i=[0:1:$children-1])
centered_scale(centered_scales[i][0],
centered_scales[i][1])
children(i);
union()
children();
}
}
}
size1 = 10;
size2 = 5;
pos1 = [0,0,0];
pos2 = [size10.5+size20.3,0,0];
// EXAMPLE 1
hulled_join([
[pos1, (1+1.5/size1)[1,1,1]],
[pos2, (1+1.0/size2)[1,1,1]]
])
{
translate(pos1)
cube(10, center=true);
translate(pos2)
rotate(a=[20,20,0]) cube(5, center=true);
}
// EXAMPLE 2
translate([size12,0,0])
hulled_join([
[pos1, (1+1.0/size1)[1,1,1]],
[pos2, (1+1.3/size2)*[1,1,1]]
], $fn=128)
{
translate(pos1)
sphere(d=size1);
translate(pos2)
rotate(a=[90,20,0]) scale([1,0.5,1]) cylinder(h=size1, d=size2,
center=true);
}
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
The previous code I posted to chamfer joints I had only used with 2
objects. Here's revised code that should work with 3 or more objects.
module centered_scale(center_point, scale_vector) {
translate(center_point)
scale(scale_vector)
translate(-1*center_point)
children(0);
}
// chamfered joining of objects
// unions objects with a hull of those objects limited to the intersection
of the objects after scaling
// adjust object scale factors to change the size and angle of chamfers
// all=true then joints between all children are chamfered
// all=false only the joints between the 1st child and the other children
are chamfered
module hulled_join(centered_scales, all=false) {
union() {
children();
for(i=[0:1:all?$children-2:0])
for(j=[i+1:1:$children-1])
hull() intersection() {
centered_scale(centered_scales[i][0],
centered_scales[i][1]) children(i);
centered_scale(centered_scales[j][0],
centered_scales[j][1]) children(j);
union() {
children(i);
children(j);
}
}
}
}
size1 = 10;
size2 = 5;
pos1 = [0,0,0];
pos2 = [size10.5+size20.3,0,0];
// EXAMPLE 1
translate([-size1,0,0])
hulled_join([
[pos1, (1+2.0/size1)[1,1,1]],
[pos2, (1+1.0/size2)[1,1,1]],
[pos2, (1+1.0/size2)*[1,1,1]]
], $fn=128)
{
translate(pos1)
sphere(d=size1);
translate(pos2)
rotate(a=[90,20,0]) scale([1,0.5,1]) cylinder(h=size1, d=size2,
center=true);
translate(pos2)
rotate(a=[90,20,90]) scale([0.5,1,1]) cylinder(h=size1, d=size2,
center=true);
}
// EXAMPLE 2
translate([size1,0,0])
hulled_join([
[pos1, (1+1.0/size1)[1,1,1]],
[pos2, (1+2.0/size2)[1,1,1]],
[pos2, (1+2.0/size2)*[1,1,1]]
], all=true, $fn=128)
{
translate(pos1)
sphere(d=size1);
translate(pos2)
rotate(a=[90,20,0]) scale([1,0.5,1]) cylinder(h=size1, d=size2,
center=true);
translate(pos2)
rotate(a=[90,20,90]) scale([0.5,1,1]) cylinder(h=size1, d=size2,
center=true);
}
[image: hulljoin.png]
On Sat, Dec 6, 2025 at 4:23 PM Todd Allen speedebikes@gmail.com wrote:
Here's an example of how I sometimes chamfer joints using hull(). I have
found this useful but it would be more useful if a similar method could be
applied between parent and child objects using BOSL2's
positioning/alignment/attachment but I don't yet see a good way and would
love it if someone could help me do it.
module centered_scale(center_point, scale_vector) {
translate(center_point)
scale(scale_vector)
translate(-1*center_point)
children(0);
}
// chamfered joining of objects
// unions objects with a hull of those objects limited to the intersection
of the objects after scaling
// adjust object scale factors to change the size and angle of the chamfer
module hulled_join(centered_scales) {
union() {
children();
hull() intersection() {
intersection_for(i=[0:1:$children-1])
centered_scale(centered_scales[i][0],
centered_scales[i][1])
children(i);
union()
children();
}
}
}
size1 = 10;
size2 = 5;
pos1 = [0,0,0];
pos2 = [size10.5+size20.3,0,0];
// EXAMPLE 1
hulled_join([
[pos1, (1+1.5/size1)[1,1,1]],
[pos2, (1+1.0/size2)[1,1,1]]
])
{
translate(pos1)
cube(10, center=true);
translate(pos2)
rotate(a=[20,20,0]) cube(5, center=true);
}
// EXAMPLE 2
translate([size12,0,0])
hulled_join([
[pos1, (1+1.0/size1)[1,1,1]],
[pos2, (1+1.3/size2)*[1,1,1]]
], $fn=128)
{
translate(pos1)
sphere(d=size1);
translate(pos2)
rotate(a=[90,20,0]) scale([1,0.5,1]) cylinder(h=size1, d=size2,
center=true);
}
I will try it. Thanks! Although I expect if I find a solution it will be
ugly.
On Sun, Dec 7, 2025 at 4:39 PM Adrian Mariano via Discuss <
discuss@lists.openscad.org> wrote:
You might be able to use descriptions to do this somehow, but I'm not
sure. See
https://github.com/BelfrySCAD/BOSL2/wiki/attachments.scad#section-attachable-descriptions-for-operating-on-attachables-or-restoring-a-previous-state
for descriptions. Mostly descriptions were implemented to support
prism_connector, so the examples of using them are mostly there:
https://github.com/BelfrySCAD/BOSL2/wiki/rounding.scad#module-prism_connector
On Sat, Dec 6, 2025 at 5:24 PM Todd Allen via Discuss <
discuss@lists.openscad.org> wrote:
Here's an example of how I sometimes chamfer joints using hull(). I have
found this useful but it would be more useful if a similar method could be
applied between parent and child objects using BOSL2's
positioning/alignment/attachment but I don't yet see a good way and would
love it if someone could help me do it.
module centered_scale(center_point, scale_vector) {
translate(center_point)
scale(scale_vector)
translate(-1*center_point)
children(0);
}
// chamfered joining of objects
// unions objects with a hull of those objects limited to the
intersection of the objects after scaling
// adjust object scale factors to change the size and angle of the chamfer
module hulled_join(centered_scales) {
union() {
children();
hull() intersection() {
intersection_for(i=[0:1:$children-1])
centered_scale(centered_scales[i][0],
centered_scales[i][1])
children(i);
union()
children();
}
}
}
size1 = 10;
size2 = 5;
pos1 = [0,0,0];
pos2 = [size10.5+size20.3,0,0];
// EXAMPLE 1
hulled_join([
[pos1, (1+1.5/size1)[1,1,1]],
[pos2, (1+1.0/size2)[1,1,1]]
])
{
translate(pos1)
cube(10, center=true);
translate(pos2)
rotate(a=[20,20,0]) cube(5, center=true);
}
// EXAMPLE 2
translate([size12,0,0])
hulled_join([
[pos1, (1+1.0/size1)[1,1,1]],
[pos2, (1+1.3/size2)*[1,1,1]]
], $fn=128)
{
translate(pos1)
sphere(d=size1);
translate(pos2)
rotate(a=[90,20,0]) scale([1,0.5,1]) cylinder(h=size1, d=size2,
center=true);
}
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
Success! Sort of. I chamfered the joints of an attachables example but
did it with significant changes/additions to the example. I think this is
a viable template that can be applied to other attachable cases somewhat
robotically with acceptable effort but I need to do a few to get a sense of
the limitations or universality of this approach. Any thoughts on this
will be appreciated.
[image: 465e530a-ad54-4e4c-b9ea-a9f4bd639c1d.png]
include <BOSL2/std.scad>
// Example from:
//
https://github.com/BelfrySCAD/BOSL2/wiki/attachments.scad#function-desc_dir
back(30)
prismoid(20,10,h=15)
attach(RIGHT,BOT) cuboid([4,4,15])
position(TOP) cyl(d=12,h=5,orient=desc_dir(),anchor=BACK);
// same example rewritten for chamfering joints
module body(ao=false) {prismoid(20,10,h=15, anchor=ao?ao:BOT) children();}
module arm(ao=false) {cuboid([4,4,20], anchor=ao?ao:CTR) children();}
module hand(ao=false) {cyl(d=12,h=5,orient=desc_dir(), anchor=ao?ao:BACK)
children();}
body() let(body_desc=parent())
attach(RIGHT,BOT) arm() let(arm_desc=parent())
position(TOP) hand() let(hand_desc=parent())
restore() {
body_p=desc_point(body_desc,anchor=CTR);
arm_p=desc_point(arm_desc,anchor=CTR);
hand_p=desc_point(hand_desc,anchor=CTR);
scaled_body_desc = transform_desc(scale(1.2*[1,1,1],
cp=body_p), body_desc);
scaled_arm_desc = transform_desc(scale(1.6*[1,1,1], cp=arm_p),
arm_desc);
scaled_hand_desc = transform_desc(scale(1.2*[1,1,1],
cp=hand_p), hand_desc);
hulled_join_attachables([
// arm first to allow default case of only computing
chamfers between first child and the other children
[arm_desc,scaled_arm_desc],
[body_desc,scaled_body_desc],
[hand_desc,scaled_hand_desc],
], all=false) {
arm(CTR);
body(CTR);
hand(CTR);
}
};
// chamfered joining of attachables
// base_scaled_descs = [[base_desc, scaled_desc],] for each child
// hulls pairs of base objects limited to the intersection of their scaled
forms
// adjust scale factors to change the size and angle of chamfers
// all=true then joints between all children are chamfered
// all=false only the joints between the 1st child and the other children
are chamfered
module hulled_join_attachables(base_scaled_descs, all=false) {
union() {
for(i=[0:1:all?$children-2:0])
for(j=[i+1:1:$children-1])
hull() intersection() {
restore(base_scaled_descs[i][1]) children(i);
restore(base_scaled_descs[j][1]) children(j);
union() {
restore(base_scaled_descs[i][0]) children(i);
restore(base_scaled_descs[j][0]) children(j);
}
}
}
}
On Sun, Dec 7, 2025 at 4:39 PM Adrian Mariano via Discuss <
discuss@lists.openscad.org> wrote:
You might be able to use descriptions to do this somehow, but I'm not
sure. See
https://github.com/BelfrySCAD/BOSL2/wiki/attachments.scad#section-attachable-descriptions-for-operating-on-attachables-or-restoring-a-previous-state
for descriptions. Mostly descriptions were implemented to support
prism_connector, so the examples of using them are mostly there:
https://github.com/BelfrySCAD/BOSL2/wiki/rounding.scad#module-prism_connector
On Sat, Dec 6, 2025 at 5:24 PM Todd Allen via Discuss <
discuss@lists.openscad.org> wrote:
Here's an example of how I sometimes chamfer joints using hull(). I have
found this useful but it would be more useful if a similar method could be
applied between parent and child objects using BOSL2's
positioning/alignment/attachment but I don't yet see a good way and would
love it if someone could help me do it.
module centered_scale(center_point, scale_vector) {
translate(center_point)
scale(scale_vector)
translate(-1*center_point)
children(0);
}
// chamfered joining of objects
// unions objects with a hull of those objects limited to the
intersection of the objects after scaling
// adjust object scale factors to change the size and angle of the chamfer
module hulled_join(centered_scales) {
union() {
children();
hull() intersection() {
intersection_for(i=[0:1:$children-1])
centered_scale(centered_scales[i][0],
centered_scales[i][1])
children(i);
union()
children();
}
}
}
size1 = 10;
size2 = 5;
pos1 = [0,0,0];
pos2 = [size10.5+size20.3,0,0];
// EXAMPLE 1
hulled_join([
[pos1, (1+1.5/size1)[1,1,1]],
[pos2, (1+1.0/size2)[1,1,1]]
])
{
translate(pos1)
cube(10, center=true);
translate(pos2)
rotate(a=[20,20,0]) cube(5, center=true);
}
// EXAMPLE 2
translate([size12,0,0])
hulled_join([
[pos1, (1+1.0/size1)[1,1,1]],
[pos2, (1+1.3/size2)*[1,1,1]]
], $fn=128)
{
translate(pos1)
sphere(d=size1);
translate(pos2)
rotate(a=[90,20,0]) scale([1,0.5,1]) cylinder(h=size1, d=size2,
center=true);
}
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
This is trivial to do with prism_connector but gives you (very nice looking!) filleting. Is there a reason you specifically need chamfering?
I think this code can be seriously simplified. However, I'd first need to know that I am not missing something here.
Peter
On 9 Dec 2025, at 19:30, Todd Allen via Discuss discuss@lists.openscad.org wrote:
Success! Sort of. I chamfered the joints of an attachables example but did it with significant changes/additions to the example. I think this is a viable template that can be applied to other attachable cases somewhat robotically with acceptable effort but I need to do a few to get a sense of the limitations or universality of this approach. Any thoughts on this will be appreciated.
<465e530a-ad54-4e4c-b9ea-a9f4bd639c1d.png>
include <BOSL2/std.scad>
// Example from:
// https://github.com/BelfrySCAD/BOSL2/wiki/attachments.scad#function-desc_dir
back(30)
prismoid(20,10,h=15)
attach(RIGHT,BOT) cuboid([4,4,15])
position(TOP) cyl(d=12,h=5,orient=desc_dir(),anchor=BACK);
// same example rewritten for chamfering joints
module body(ao=false) {prismoid(20,10,h=15, anchor=ao?ao:BOT) children();}
module arm(ao=false) {cuboid([4,4,20], anchor=ao?ao:CTR) children();}
module hand(ao=false) {cyl(d=12,h=5,orient=desc_dir(), anchor=ao?ao:BACK) children();}
body() let(body_desc=parent())
attach(RIGHT,BOT) arm() let(arm_desc=parent())
position(TOP) hand() let(hand_desc=parent())
restore() {
body_p=desc_point(body_desc,anchor=CTR);
arm_p=desc_point(arm_desc,anchor=CTR);
hand_p=desc_point(hand_desc,anchor=CTR);
scaled_body_desc = transform_desc(scale(1.2*[1,1,1], cp=body_p), body_desc);
scaled_arm_desc = transform_desc(scale(1.6*[1,1,1], cp=arm_p), arm_desc);
scaled_hand_desc = transform_desc(scale(1.2*[1,1,1], cp=hand_p), hand_desc);
hulled_join_attachables([
// arm first to allow default case of only computing chamfers between first child and the other children
[arm_desc,scaled_arm_desc],
[body_desc,scaled_body_desc],
[hand_desc,scaled_hand_desc],
], all=false) {
arm(CTR);
body(CTR);
hand(CTR);
}
};
// chamfered joining of attachables
// base_scaled_descs = [[base_desc, scaled_desc],] for each child
// hulls pairs of base objects limited to the intersection of their scaled forms
// adjust scale factors to change the size and angle of chamfers
// all=true then joints between all children are chamfered
// all=false only the joints between the 1st child and the other children are chamfered
module hulled_join_attachables(base_scaled_descs, all=false) {
union() {
for(i=[0:1:all?$children-2:0])
for(j=[i+1:1:$children-1])
hull() intersection() {
restore(base_scaled_descs[i][1]) children(i);
restore(base_scaled_descs[j][1]) children(j);
union() {
restore(base_scaled_descs[i][0]) children(i);
restore(base_scaled_descs[j][0]) children(j);
}
}
}
}
On Sun, Dec 7, 2025 at 4:39 PM Adrian Mariano via Discuss <discuss@lists.openscad.org mailto:discuss@lists.openscad.org> wrote:
You might be able to use descriptions to do this somehow, but I'm not sure. See https://github.com/BelfrySCAD/BOSL2/wiki/attachments.scad#section-attachable-descriptions-for-operating-on-attachables-or-restoring-a-previous-state for descriptions. Mostly descriptions were implemented to support prism_connector, so the examples of using them are mostly there: https://github.com/BelfrySCAD/BOSL2/wiki/rounding.scad#module-prism_connector
On Sat, Dec 6, 2025 at 5:24 PM Todd Allen via Discuss <discuss@lists.openscad.org mailto:discuss@lists.openscad.org> wrote:
Here's an example of how I sometimes chamfer joints using hull(). I have found this useful but it would be more useful if a similar method could be applied between parent and child objects using BOSL2's positioning/alignment/attachment but I don't yet see a good way and would love it if someone could help me do it.
module centered_scale(center_point, scale_vector) {
translate(center_point)
scale(scale_vector)
translate(-1*center_point)
children(0);
}
// chamfered joining of objects
// unions objects with a hull of those objects limited to the intersection of the objects after scaling
// adjust object scale factors to change the size and angle of the chamfer
module hulled_join(centered_scales) {
union() {
children();
hull() intersection() {
intersection_for(i=[0:1:$children-1])
centered_scale(centered_scales[i][0], centered_scales[i][1])
children(i);
union()
children();
}
}
}
size1 = 10;
size2 = 5;
pos1 = [0,0,0];
pos2 = [size10.5+size20.3,0,0];
// EXAMPLE 1
hulled_join([
[pos1, (1+1.5/size1)[1,1,1]],
[pos2, (1+1.0/size2)[1,1,1]]
])
{
translate(pos1)
cube(10, center=true);
translate(pos2)
rotate(a=[20,20,0]) cube(5, center=true);
}
// EXAMPLE 2
translate([size12,0,0])
hulled_join([
[pos1, (1+1.0/size1)[1,1,1]],
[pos2, (1+1.3/size2)*[1,1,1]]
], $fn=128)
{
translate(pos1)
sphere(d=size1);
translate(pos2)
rotate(a=[90,20,0]) scale([1,0.5,1]) cylinder(h=size1, d=size2, center=true);
}
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org mailto:discuss-leave@lists.openscad.org_______________________________________________
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org mailto:discuss-leave@lists.openscad.org_______________________________________________
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
The earlier example showed things that are impossible with
prism_connector(). I think you can create chamfers with prism_connector by
setting the facet count to 1.
On Wed, Dec 10, 2025 at 4:55 AM Peter Kriens via Discuss <
discuss@lists.openscad.org> wrote:
This is trivial to do with prism_connector but gives you (very nice
looking!) filleting. Is there a reason you specifically need chamfering?
I think this code can be seriously simplified. However, I'd first need to
know that I am not missing something here.
Peter
On 9 Dec 2025, at 19:30, Todd Allen via Discuss <
discuss@lists.openscad.org> wrote:
Success! Sort of. I chamfered the joints of an attachables example but
did it with significant changes/additions to the example. I think this is
a viable template that can be applied to other attachable cases somewhat
robotically with acceptable effort but I need to do a few to get a sense of
the limitations or universality of this approach. Any thoughts on this
will be appreciated.
<465e530a-ad54-4e4c-b9ea-a9f4bd639c1d.png>
include <BOSL2/std.scad>
// Example from:
//
https://github.com/BelfrySCAD/BOSL2/wiki/attachments.scad#function-desc_dir
back(30)
prismoid(20,10,h=15)
attach(RIGHT,BOT) cuboid([4,4,15])
position(TOP) cyl(d=12,h=5,orient=desc_dir(),anchor=BACK);
// same example rewritten for chamfering joints
module body(ao=false) {prismoid(20,10,h=15, anchor=ao?ao:BOT) children();}
module arm(ao=false) {cuboid([4,4,20], anchor=ao?ao:CTR) children();}
module hand(ao=false) {cyl(d=12,h=5,orient=desc_dir(), anchor=ao?ao:BACK)
children();}
body() let(body_desc=parent())
attach(RIGHT,BOT) arm() let(arm_desc=parent())
position(TOP) hand() let(hand_desc=parent())
restore() {
body_p=desc_point(body_desc,anchor=CTR);
arm_p=desc_point(arm_desc,anchor=CTR);
hand_p=desc_point(hand_desc,anchor=CTR);
scaled_body_desc = transform_desc(scale(1.2*[1,1,1],
cp=body_p), body_desc);
scaled_arm_desc = transform_desc(scale(1.6*[1,1,1], cp=arm_p),
arm_desc);
scaled_hand_desc = transform_desc(scale(1.2*[1,1,1],
cp=hand_p), hand_desc);
hulled_join_attachables([
// arm first to allow default case of only computing
chamfers between first child and the other children
[arm_desc,scaled_arm_desc],
[body_desc,scaled_body_desc],
[hand_desc,scaled_hand_desc],
], all=false) {
arm(CTR);
body(CTR);
hand(CTR);
}
};
// chamfered joining of attachables
// base_scaled_descs = [[base_desc, scaled_desc],] for each child
// hulls pairs of base objects limited to the intersection of their scaled
forms
// adjust scale factors to change the size and angle of chamfers
// all=true then joints between all children are chamfered
// all=false only the joints between the 1st child and the other children
are chamfered
module hulled_join_attachables(base_scaled_descs, all=false) {
union() {
for(i=[0:1:all?$children-2:0])
for(j=[i+1:1:$children-1])
hull() intersection() {
restore(base_scaled_descs[i][1]) children(i);
restore(base_scaled_descs[j][1]) children(j);
union() {
restore(base_scaled_descs[i][0]) children(i);
restore(base_scaled_descs[j][0]) children(j);
}
}
}
}
On Sun, Dec 7, 2025 at 4:39 PM Adrian Mariano via Discuss <
discuss@lists.openscad.org> wrote:
You might be able to use descriptions to do this somehow, but I'm not
sure. See
https://github.com/BelfrySCAD/BOSL2/wiki/attachments.scad#section-attachable-descriptions-for-operating-on-attachables-or-restoring-a-previous-state
for descriptions. Mostly descriptions were implemented to support
prism_connector, so the examples of using them are mostly there:
https://github.com/BelfrySCAD/BOSL2/wiki/rounding.scad#module-prism_connector
On Sat, Dec 6, 2025 at 5:24 PM Todd Allen via Discuss <
discuss@lists.openscad.org> wrote:
Here's an example of how I sometimes chamfer joints using hull(). I
have found this useful but it would be more useful if a similar method
could be applied between parent and child objects using BOSL2's
positioning/alignment/attachment but I don't yet see a good way and would
love it if someone could help me do it.
module centered_scale(center_point, scale_vector) {
translate(center_point)
scale(scale_vector)
translate(-1*center_point)
children(0);
}
// chamfered joining of objects
// unions objects with a hull of those objects limited to the
intersection of the objects after scaling
// adjust object scale factors to change the size and angle of the
chamfer
module hulled_join(centered_scales) {
union() {
children();
hull() intersection() {
intersection_for(i=[0:1:$children-1])
centered_scale(centered_scales[i][0],
centered_scales[i][1])
children(i);
union()
children();
}
}
}
size1 = 10;
size2 = 5;
pos1 = [0,0,0];
pos2 = [size10.5+size20.3,0,0];
// EXAMPLE 1
hulled_join([
[pos1, (1+1.5/size1)[1,1,1]],
[pos2, (1+1.0/size2)[1,1,1]]
])
{
translate(pos1)
cube(10, center=true);
translate(pos2)
rotate(a=[20,20,0]) cube(5, center=true);
}
// EXAMPLE 2
translate([size12,0,0])
hulled_join([
[pos1, (1+1.0/size1)[1,1,1]],
[pos2, (1+1.3/size2)*[1,1,1]]
], $fn=128)
{
translate(pos1)
sphere(d=size1);
translate(pos2)
rotate(a=[90,20,0]) scale([1,0.5,1]) cylinder(h=size1, d=size2,
center=true);
}
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
99% of my modeling is for 3d printing with inexpensive consumer grade
FDM printers which don't accurately reproduce sharp edges and corners.
For assemblies of interlocking snap fit parts I find I can use tighter
tolerances between surfaces when I minimize sharp transitions in the
geometry. I find it helpful to have at least a 0.1 mm chamfer wherever
surfaces meet. Larger chamfers improve strength of stressed features such
as tabs, pins and dovetails, etc. and all exterior features look and feel
better when edges are filleted or chamfered. BOSL2 has been very helpful
as it offers many options to produce solids with a variety of edge and
corner treatment options, especially negative roundings and chamfers which
are great when features are perpendicular to flat surfaces. But the more
one works with rounded, curved and tapered features the more one encounters
situations where it is challenging to produce desired transitions wherever
those features meet. Prism_connector can be a lifesaver in certain
circumstances but it is a bit cumbersome and computationally expensive to
use extensively throughout a model.
My experience has been that chamfered seams/edges are often a lot better
than nothing and the additional gain of fillets or rounding is often small
enough not to bother with if something can be chamfered. Thus my interest
in this technique which can produce chamfers of customizable size and angle
for many complex joints. I haven't yet done it but I'm fairly certain I
could generate somewhat rounded effects by applying it multiple times to a
joint with different sizes/angles of chamfer. So if you can improve on the
ease of use of this technique, the speed of execution or have a
different/better way to do similar tasks it would improve my modeling for
which I would be very grateful.
Here's some pics from my most recent BOSL2 enabled project, an enveloping
worm drive strap vise. The case is produced by a hull chamfered joint of
the boxes around each of the worm and driven gears.
[image: StrapVise open.jpg]
[image: StrapVise parts.jpg]
[image: StrapVise guts.jpg]
[image: aee4534d-43a3-44f5-91a1-907e4058cfdd.jpg]
[image: StrapVise case.jpg]
[image: jar opener.jpg]
On Wed, Dec 10, 2025 at 3:54 AM Peter Kriens peter.kriens@aqute.biz wrote:
This is trivial to do with prism_connector but gives you (very nice
looking!) filleting. Is there a reason you specifically need chamfering?
I think this code can be seriously simplified. However, I'd first need to
know that I am not missing something here.
Peter
On 9 Dec 2025, at 19:30, Todd Allen via Discuss <
discuss@lists.openscad.org> wrote:
Success! Sort of. I chamfered the joints of an attachables example but
did it with significant changes/additions to the example. I think this is
a viable template that can be applied to other attachable cases somewhat
robotically with acceptable effort but I need to do a few to get a sense of
the limitations or universality of this approach. Any thoughts on this
will be appreciated.
<465e530a-ad54-4e4c-b9ea-a9f4bd639c1d.png>
include <BOSL2/std.scad>
// Example from:
//
https://github.com/BelfrySCAD/BOSL2/wiki/attachments.scad#function-desc_dir
back(30)
prismoid(20,10,h=15)
attach(RIGHT,BOT) cuboid([4,4,15])
position(TOP) cyl(d=12,h=5,orient=desc_dir(),anchor=BACK);
// same example rewritten for chamfering joints
module body(ao=false) {prismoid(20,10,h=15, anchor=ao?ao:BOT) children();}
module arm(ao=false) {cuboid([4,4,20], anchor=ao?ao:CTR) children();}
module hand(ao=false) {cyl(d=12,h=5,orient=desc_dir(), anchor=ao?ao:BACK)
children();}
body() let(body_desc=parent())
attach(RIGHT,BOT) arm() let(arm_desc=parent())
position(TOP) hand() let(hand_desc=parent())
restore() {
body_p=desc_point(body_desc,anchor=CTR);
arm_p=desc_point(arm_desc,anchor=CTR);
hand_p=desc_point(hand_desc,anchor=CTR);
scaled_body_desc = transform_desc(scale(1.2*[1,1,1],
cp=body_p), body_desc);
scaled_arm_desc = transform_desc(scale(1.6*[1,1,1], cp=arm_p),
arm_desc);
scaled_hand_desc = transform_desc(scale(1.2*[1,1,1],
cp=hand_p), hand_desc);
hulled_join_attachables([
// arm first to allow default case of only computing
chamfers between first child and the other children
[arm_desc,scaled_arm_desc],
[body_desc,scaled_body_desc],
[hand_desc,scaled_hand_desc],
], all=false) {
arm(CTR);
body(CTR);
hand(CTR);
}
};
// chamfered joining of attachables
// base_scaled_descs = [[base_desc, scaled_desc],] for each child
// hulls pairs of base objects limited to the intersection of their scaled
forms
// adjust scale factors to change the size and angle of chamfers
// all=true then joints between all children are chamfered
// all=false only the joints between the 1st child and the other children
are chamfered
module hulled_join_attachables(base_scaled_descs, all=false) {
union() {
for(i=[0:1:all?$children-2:0])
for(j=[i+1:1:$children-1])
hull() intersection() {
restore(base_scaled_descs[i][1]) children(i);
restore(base_scaled_descs[j][1]) children(j);
union() {
restore(base_scaled_descs[i][0]) children(i);
restore(base_scaled_descs[j][0]) children(j);
}
}
}
}
On Sun, Dec 7, 2025 at 4:39 PM Adrian Mariano via Discuss <
discuss@lists.openscad.org> wrote:
You might be able to use descriptions to do this somehow, but I'm not
sure. See
https://github.com/BelfrySCAD/BOSL2/wiki/attachments.scad#section-attachable-descriptions-for-operating-on-attachables-or-restoring-a-previous-state
for descriptions. Mostly descriptions were implemented to support
prism_connector, so the examples of using them are mostly there:
https://github.com/BelfrySCAD/BOSL2/wiki/rounding.scad#module-prism_connector
On Sat, Dec 6, 2025 at 5:24 PM Todd Allen via Discuss <
discuss@lists.openscad.org> wrote:
Here's an example of how I sometimes chamfer joints using hull(). I
have found this useful but it would be more useful if a similar method
could be applied between parent and child objects using BOSL2's
positioning/alignment/attachment but I don't yet see a good way and would
love it if someone could help me do it.
module centered_scale(center_point, scale_vector) {
translate(center_point)
scale(scale_vector)
translate(-1*center_point)
children(0);
}
// chamfered joining of objects
// unions objects with a hull of those objects limited to the
intersection of the objects after scaling
// adjust object scale factors to change the size and angle of the
chamfer
module hulled_join(centered_scales) {
union() {
children();
hull() intersection() {
intersection_for(i=[0:1:$children-1])
centered_scale(centered_scales[i][0],
centered_scales[i][1])
children(i);
union()
children();
}
}
}
size1 = 10;
size2 = 5;
pos1 = [0,0,0];
pos2 = [size10.5+size20.3,0,0];
// EXAMPLE 1
hulled_join([
[pos1, (1+1.5/size1)[1,1,1]],
[pos2, (1+1.0/size2)[1,1,1]]
])
{
translate(pos1)
cube(10, center=true);
translate(pos2)
rotate(a=[20,20,0]) cube(5, center=true);
}
// EXAMPLE 2
translate([size12,0,0])
hulled_join([
[pos1, (1+1.0/size1)[1,1,1]],
[pos2, (1+1.3/size2)*[1,1,1]]
], $fn=128)
{
translate(pos1)
sphere(d=size1);
translate(pos2)
rotate(a=[90,20,0]) scale([1,0.5,1]) cylinder(h=size1, d=size2,
center=true);
}
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
👌Very nice project
On Thu, 11 Dec, 2025, 1:31 am Todd Allen via Discuss, <
discuss@lists.openscad.org> wrote:
99% of my modeling is for 3d printing with inexpensive consumer grade
FDM printers which don't accurately reproduce sharp edges and corners.
For assemblies of interlocking snap fit parts I find I can use tighter
tolerances between surfaces when I minimize sharp transitions in the
geometry. I find it helpful to have at least a 0.1 mm chamfer wherever
surfaces meet. Larger chamfers improve strength of stressed features such
as tabs, pins and dovetails, etc. and all exterior features look and feel
better when edges are filleted or chamfered. BOSL2 has been very helpful
as it offers many options to produce solids with a variety of edge and
corner treatment options, especially negative roundings and chamfers which
are great when features are perpendicular to flat surfaces. But the more
one works with rounded, curved and tapered features the more one encounters
situations where it is challenging to produce desired transitions wherever
those features meet. Prism_connector can be a lifesaver in certain
circumstances but it is a bit cumbersome and computationally expensive to
use extensively throughout a model.
My experience has been that chamfered seams/edges are often a lot better
than nothing and the additional gain of fillets or rounding is often small
enough not to bother with if something can be chamfered. Thus my interest
in this technique which can produce chamfers of customizable size and angle
for many complex joints. I haven't yet done it but I'm fairly certain I
could generate somewhat rounded effects by applying it multiple times to a
joint with different sizes/angles of chamfer. So if you can improve on the
ease of use of this technique, the speed of execution or have a
different/better way to do similar tasks it would improve my modeling for
which I would be very grateful.
Here's some pics from my most recent BOSL2 enabled project, an enveloping
worm drive strap vise. The case is produced by a hull chamfered joint of
the boxes around each of the worm and driven gears.
[image: StrapVise open.jpg]
[image: StrapVise parts.jpg]
[image: StrapVise guts.jpg]
[image: aee4534d-43a3-44f5-91a1-907e4058cfdd.jpg]
[image: StrapVise case.jpg]
[image: jar opener.jpg]
On Wed, Dec 10, 2025 at 3:54 AM Peter Kriens peter.kriens@aqute.biz
wrote:
This is trivial to do with prism_connector but gives you (very nice
looking!) filleting. Is there a reason you specifically need chamfering?
I think this code can be seriously simplified. However, I'd first need to
know that I am not missing something here.
Peter
On 9 Dec 2025, at 19:30, Todd Allen via Discuss <
discuss@lists.openscad.org> wrote:
Success! Sort of. I chamfered the joints of an attachables example but
did it with significant changes/additions to the example. I think this is
a viable template that can be applied to other attachable cases somewhat
robotically with acceptable effort but I need to do a few to get a sense of
the limitations or universality of this approach. Any thoughts on this
will be appreciated.
<465e530a-ad54-4e4c-b9ea-a9f4bd639c1d.png>
include <BOSL2/std.scad>
// Example from:
//
https://github.com/BelfrySCAD/BOSL2/wiki/attachments.scad#function-desc_dir
back(30)
prismoid(20,10,h=15)
attach(RIGHT,BOT) cuboid([4,4,15])
position(TOP) cyl(d=12,h=5,orient=desc_dir(),anchor=BACK);
// same example rewritten for chamfering joints
module body(ao=false) {prismoid(20,10,h=15, anchor=ao?ao:BOT) children();}
module arm(ao=false) {cuboid([4,4,20], anchor=ao?ao:CTR) children();}
module hand(ao=false) {cyl(d=12,h=5,orient=desc_dir(), anchor=ao?ao:BACK)
children();}
body() let(body_desc=parent())
attach(RIGHT,BOT) arm() let(arm_desc=parent())
position(TOP) hand() let(hand_desc=parent())
restore() {
body_p=desc_point(body_desc,anchor=CTR);
arm_p=desc_point(arm_desc,anchor=CTR);
hand_p=desc_point(hand_desc,anchor=CTR);
scaled_body_desc = transform_desc(scale(1.2*[1,1,1],
cp=body_p), body_desc);
scaled_arm_desc = transform_desc(scale(1.6*[1,1,1],
cp=arm_p), arm_desc);
scaled_hand_desc = transform_desc(scale(1.2*[1,1,1],
cp=hand_p), hand_desc);
hulled_join_attachables([
// arm first to allow default case of only computing
chamfers between first child and the other children
[arm_desc,scaled_arm_desc],
[body_desc,scaled_body_desc],
[hand_desc,scaled_hand_desc],
], all=false) {
arm(CTR);
body(CTR);
hand(CTR);
}
};
// chamfered joining of attachables
// base_scaled_descs = [[base_desc, scaled_desc],] for each child
// hulls pairs of base objects limited to the intersection of their
scaled forms
// adjust scale factors to change the size and angle of chamfers
// all=true then joints between all children are chamfered
// all=false only the joints between the 1st child and the other children
are chamfered
module hulled_join_attachables(base_scaled_descs, all=false) {
union() {
for(i=[0:1:all?$children-2:0])
for(j=[i+1:1:$children-1])
hull() intersection() {
restore(base_scaled_descs[i][1]) children(i);
restore(base_scaled_descs[j][1]) children(j);
union() {
restore(base_scaled_descs[i][0]) children(i);
restore(base_scaled_descs[j][0]) children(j);
}
}
}
}
On Sun, Dec 7, 2025 at 4:39 PM Adrian Mariano via Discuss <
discuss@lists.openscad.org> wrote:
You might be able to use descriptions to do this somehow, but I'm not
sure. See
https://github.com/BelfrySCAD/BOSL2/wiki/attachments.scad#section-attachable-descriptions-for-operating-on-attachables-or-restoring-a-previous-state
for descriptions. Mostly descriptions were implemented to support
prism_connector, so the examples of using them are mostly there:
https://github.com/BelfrySCAD/BOSL2/wiki/rounding.scad#module-prism_connector
On Sat, Dec 6, 2025 at 5:24 PM Todd Allen via Discuss <
discuss@lists.openscad.org> wrote:
Here's an example of how I sometimes chamfer joints using hull(). I
have found this useful but it would be more useful if a similar method
could be applied between parent and child objects using BOSL2's
positioning/alignment/attachment but I don't yet see a good way and would
love it if someone could help me do it.
module centered_scale(center_point, scale_vector) {
translate(center_point)
scale(scale_vector)
translate(-1*center_point)
children(0);
}
// chamfered joining of objects
// unions objects with a hull of those objects limited to the
intersection of the objects after scaling
// adjust object scale factors to change the size and angle of the
chamfer
module hulled_join(centered_scales) {
union() {
children();
hull() intersection() {
intersection_for(i=[0:1:$children-1])
centered_scale(centered_scales[i][0],
centered_scales[i][1])
children(i);
union()
children();
}
}
}
size1 = 10;
size2 = 5;
pos1 = [0,0,0];
pos2 = [size10.5+size20.3,0,0];
// EXAMPLE 1
hulled_join([
[pos1, (1+1.5/size1)[1,1,1]],
[pos2, (1+1.0/size2)[1,1,1]]
])
{
translate(pos1)
cube(10, center=true);
translate(pos2)
rotate(a=[20,20,0]) cube(5, center=true);
}
// EXAMPLE 2
translate([size12,0,0])
hulled_join([
[pos1, (1+1.0/size1)[1,1,1]],
[pos2, (1+1.3/size2)*[1,1,1]]
], $fn=128)
{
translate(pos1)
sphere(d=size1);
translate(pos2)
rotate(a=[90,20,0]) scale([1,0.5,1]) cylinder(h=size1, d=size2,
center=true);
}
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
I like the idea behind your approach and kind of rewrote it into a more
generic solution by introducing a global variable $camfer and
camfer-enabled modules cube_(), cylinder_() and sphere_() that allow to
be scaled by $camfer.
$fn=100;
$camfer=1;
size1 = 10;
size2 = 5;
pos1 = [0,0,0];
pos2 = [size10.5+size20.3,0,0];
module camfer(x=1.2)
{
for(i=[0:$children-1])
children(i);
for(i=[0:$children-1], j=[0:$children-1])
if(i<j)
hull()
{
intersection()
{
children(i);
children(j, $camfer=x);
}
intersection()
{
children(i, $camfer=x);
children(j);
}
}
}
module cube_(size, center) scale($camfer)cube(size, center);
module sphere_(r, d) scale($camfer)sphere(r=r, d=d);
module cylinder_(h, r, d, center) scale($camfer)cylinder(h=h, r=r, d=d,
center=center);
camfer()
{
translate(pos1) cube_(10, center=true);
translate(pos2) rotate(a=[20,20,0]) cube_([6, 5, 5], center=true);
}
translate([20, 0, 0])
camfer()
{
translate(pos1) sphere_(d=size1);
translate(pos2) rotate(a=[90,20,0]) scale([1,0.5,1])
cylinder_(h=size1, d=size2, center=true);
translate(pos2) rotate(a=[90,20,90]) scale([0.5,1,1])
cylinder_(h=size1, d=size2, center=true);
}
Am 08.12.2025 um 00:03 schrieb Todd Allen via Discuss:
module centered_scale(center_point, scale_vector) {
translate(center_point)
scale(scale_vector)
translate(-1*center_point)
children(0);
}
// chamfered joining of objects
// unions objects with a hull of those objects limited to the
intersection of the objects after scaling
// adjust object scale factors to change the size and angle of chamfers
// all=true then joints between all children are chamfered
// all=false only the joints between the 1st child and the other
children are chamfered
module hulled_join(centered_scales, all=false) {
union() {
children();
for(i=[0:1:all?$children-2:0])
for(j=[i+1:1:$children-1])
hull() intersection() {
centered_scale(centered_scales[i][0],
centered_scales[i][1]) children(i);
centered_scale(centered_scales[j][0],
centered_scales[j][1]) children(j);
union() {
children(i);
children(j);
}
}
}
}
size1 = 10;
size2 = 5;
pos1 = [0,0,0];
pos2 = [size10.5+size20.3,0,0];
// EXAMPLE 1
translate([-size1,0,0])
hulled_join([
[pos1, (1+2.0/size1)[1,1,1]],
[pos2, (1+1.0/size2)[1,1,1]],
[pos2, (1+1.0/size2)*[1,1,1]]
], $fn=128)
{
translate(pos1)
sphere(d=size1);
translate(pos2)
rotate(a=[90,20,0]) scale([1,0.5,1]) cylinder(h=size1,
d=size2, center=true);
translate(pos2)
rotate(a=[90,20,90]) scale([0.5,1,1]) cylinder(h=size1,
d=size2, center=true);
}
// EXAMPLE 2
translate([size1,0,0])
hulled_join([
[pos1, (1+1.0/size1)[1,1,1]],
[pos2, (1+2.0/size2)[1,1,1]],
[pos2, (1+2.0/size2)*[1,1,1]]
], all=true, $fn=128)
{
translate(pos1)
sphere(d=size1);
translate(pos2)
rotate(a=[90,20,0]) scale([1,0.5,1]) cylinder(h=size1, d=size2,
center=true);
translate(pos2)
rotate(a=[90,20,90]) scale([0.5,1,1]) cylinder(h=size1, d=size2,
center=true);
}
hulljoin.png
On Sat, Dec 6, 2025 at 4:23 PM Todd Allen speedebikes@gmail.com wrote:
Here's an example of how I sometimes chamfer joints using hull().
I have found this useful but it would be more useful if a similar
method could be applied between parent and child objects using
BOSL2's positioning/alignment/attachment but I don't yet see a
good way and would love it if someone could help me do it.
module centered_scale(center_point, scale_vector) {
translate(center_point)
scale(scale_vector)
translate(-1*center_point)
children(0);
}
// chamfered joining of objects
// unions objects with a hull of those objects limited to the
intersection of the objects after scaling
// adjust object scale factors to change the size and angle of the
chamfer
module hulled_join(centered_scales) {
union() {
children();
hull() intersection() {
intersection_for(i=[0:1:$children-1])
centered_scale(centered_scales[i][0],
centered_scales[i][1])
children(i);
union()
children();
}
}
}
size1 = 10;
size2 = 5;
pos1 = [0,0,0];
pos2 = [size1*0.5+size2*0.3,0,0];
// EXAMPLE 1
hulled_join([
[pos1, (1+1.5/size1)*[1,1,1]],
[pos2, (1+1.0/size2)*[1,1,1]]
])
{