discuss@lists.openscad.org

OpenSCAD general discussion Mailing-list

View all threads

chamfering joints with hull()

TA
Todd Allen
Sat, Dec 6, 2025 10:23 PM

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);
}

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]] ]) { translate(pos1) cube(10, center=true); translate(pos2) rotate(a=[20,20,0]) cube(5, center=true); } // EXAMPLE 2 translate([size1*2,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); }
AM
Adrian Mariano
Sun, Dec 7, 2025 10:39 PM

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

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 = [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]] > ]) > { > translate(pos1) > cube(10, center=true); > translate(pos2) > rotate(a=[20,20,0]) cube(5, center=true); > } > > // EXAMPLE 2 > translate([size1*2,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
TA
Todd Allen
Sun, Dec 7, 2025 11:03 PM

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);
}

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 = [size1*0.5+size2*0.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 = [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]] > ]) > { > translate(pos1) > cube(10, center=true); > translate(pos2) > rotate(a=[20,20,0]) cube(5, center=true); > } > > // EXAMPLE 2 > translate([size1*2,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); > } >
TA
Todd Allen
Sun, Dec 7, 2025 11:21 PM

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

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 = [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]] >> ]) >> { >> translate(pos1) >> cube(10, center=true); >> translate(pos2) >> rotate(a=[20,20,0]) cube(5, center=true); >> } >> >> // EXAMPLE 2 >> translate([size1*2,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
TA
Todd Allen
Tue, Dec 9, 2025 6:30 PM

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

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 = [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]] >> ]) >> { >> translate(pos1) >> cube(10, center=true); >> translate(pos2) >> rotate(a=[20,20,0]) cube(5, center=true); >> } >> >> // EXAMPLE 2 >> translate([size1*2,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
PK
Peter Kriens
Wed, Dec 10, 2025 9:54 AM

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

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 = [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]] >>> ]) >>> { >>> translate(pos1) >>> cube(10, center=true); >>> translate(pos2) >>> rotate(a=[20,20,0]) cube(5, center=true); >>> } >>> >>> // EXAMPLE 2 >>> translate([size1*2,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
AM
Adrian Mariano
Wed, Dec 10, 2025 11:28 AM

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

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 = [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]] >>> ]) >>> { >>> translate(pos1) >>> cube(10, center=true); >>> translate(pos2) >>> rotate(a=[20,20,0]) cube(5, center=true); >>> } >>> >>> // EXAMPLE 2 >>> translate([size1*2,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
TA
Todd Allen
Wed, Dec 10, 2025 8:00 PM

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

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 = [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]] >>> ]) >>> { >>> translate(pos1) >>> cube(10, center=true); >>> translate(pos2) >>> rotate(a=[20,20,0]) cube(5, center=true); >>> } >>> >>> // EXAMPLE 2 >>> translate([size1*2,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 > > >
SP
Sanjeev Prabhakar
Wed, Dec 10, 2025 11:58 PM

👌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


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 = [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]] >>>> ]) >>>> { >>>> translate(pos1) >>>> cube(10, center=true); >>>> translate(pos2) >>>> rotate(a=[20,20,0]) cube(5, center=true); >>>> } >>>> >>>> // EXAMPLE 2 >>>> translate([size1*2,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
R
Rudolf
Fri, Dec 12, 2025 12:00 AM

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]]
     ])
 {
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 = [size1*0.5+size2*0.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 = [size1*0.5+size2*0.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]] >     ]) > { >