discuss@lists.openscad.org

OpenSCAD general discussion Mailing-list

View all threads

A simple approach to creating fillets

DH
Daniel Harvey
Tue, Feb 14, 2023 4:27 AM

Hello,
It's possible that I have re-invented the wheel here, but I thought I would
share a simple solution I came up with to create fillets for the
intersection of two objects. It requires the objects to be defined with a
parametric size-offset, and it uses an iterative approach with hull() to
create a fillet. Here's an example with a cuboid (box()) embedded in a
cylinder (shaft()).

module shaft(dd=0) {
rotate([0,0,-10]) rotate([0,90,0]) cylinder(d=22+dd, h=100, $fn=60,
center=true);
}

module box(dd=0) {
translate([0,5,5]) cube([15+dd,18+dd,25+dd], center=true);
}

module filletSlice(ro, ang) {
p = ro * [(1-cos(ang)), (1-sin(ang))];
intersection() {
shaft(p.x);
box(p.y);
}
}

da = 10;
for (a=[0:da:90-da]) {
hull() {
filletSlice(2, a);
filletSlice(2, a+da);
}
}
shaft();
box();

Hello, It's possible that I have re-invented the wheel here, but I thought I would share a simple solution I came up with to create fillets for the intersection of two objects. It requires the objects to be defined with a parametric size-offset, and it uses an iterative approach with hull() to create a fillet. Here's an example with a cuboid (box()) embedded in a cylinder (shaft()). module shaft(dd=0) { rotate([0,0,-10]) rotate([0,90,0]) cylinder(d=22+dd, h=100, $fn=60, center=true); } module box(dd=0) { translate([0,5,5]) cube([15+dd,18+dd,25+dd], center=true); } module filletSlice(ro, ang) { p = ro * [(1-cos(ang)), (1-sin(ang))]; intersection() { shaft(p.x); box(p.y); } } da = 10; for (a=[0:da:90-da]) { hull() { filletSlice(2, a); filletSlice(2, a+da); } } shaft(); box();
SP
Sanjeev Prabhakar
Tue, Feb 14, 2023 12:20 PM

It looks great, although not gone in detail.
Does it work for all type of solid to solid intersections?

On Tue, 14 Feb, 2023, 9:58 am Daniel Harvey, dwaharvey@gmail.com wrote:

Hello,
It's possible that I have re-invented the wheel here, but I thought I
would share a simple solution I came up with to create fillets for the
intersection of two objects. It requires the objects to be defined with a
parametric size-offset, and it uses an iterative approach with hull() to
create a fillet. Here's an example with a cuboid (box()) embedded in a
cylinder (shaft()).

module shaft(dd=0) {
rotate([0,0,-10]) rotate([0,90,0]) cylinder(d=22+dd, h=100, $fn=60,
center=true);
}

module box(dd=0) {
translate([0,5,5]) cube([15+dd,18+dd,25+dd], center=true);
}

module filletSlice(ro, ang) {
p = ro * [(1-cos(ang)), (1-sin(ang))];
intersection() {
shaft(p.x);
box(p.y);
}
}

da = 10;
for (a=[0:da:90-da]) {
hull() {
filletSlice(2, a);
filletSlice(2, a+da);
}
}
shaft();
box();


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

It looks great, although not gone in detail. Does it work for all type of solid to solid intersections? On Tue, 14 Feb, 2023, 9:58 am Daniel Harvey, <dwaharvey@gmail.com> wrote: > Hello, > It's possible that I have re-invented the wheel here, but I thought I > would share a simple solution I came up with to create fillets for the > intersection of two objects. It requires the objects to be defined with a > parametric size-offset, and it uses an iterative approach with hull() to > create a fillet. Here's an example with a cuboid (box()) embedded in a > cylinder (shaft()). > > module shaft(dd=0) { > rotate([0,0,-10]) rotate([0,90,0]) cylinder(d=22+dd, h=100, $fn=60, > center=true); > } > > module box(dd=0) { > translate([0,5,5]) cube([15+dd,18+dd,25+dd], center=true); > } > > module filletSlice(ro, ang) { > p = ro * [(1-cos(ang)), (1-sin(ang))]; > intersection() { > shaft(p.x); > box(p.y); > } > } > > da = 10; > for (a=[0:da:90-da]) { > hull() { > filletSlice(2, a); > filletSlice(2, a+da); > } > } > shaft(); > box(); > > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org >
DH
Daniel Harvey
Tue, Feb 14, 2023 3:14 PM

There's the obvious limitation that if the area of intersection has native
curvature then the fillet will pull away from the part (because hull() {
object1() } != object1() in that area). So if eg object1() had a wave
pattern, like some corrugated decking material... the result would not be
good.
On a case by case basis this sort of thing could probably be dealt with by
iterating over another parameter, and intersecting with a third parametric
object that creates small interpolations of the negative curve. But I am
not sure how this will affect the computation time (geometric increase in
calls to hull(), though each call on a much smaller object).

On Tue, Feb 14, 2023 at 5:20 AM Sanjeev Prabhakar sprabhakar2006@gmail.com
wrote:

It looks great, although not gone in detail.
Does it work for all type of solid to solid intersections?

On Tue, 14 Feb, 2023, 9:58 am Daniel Harvey, dwaharvey@gmail.com wrote:

Hello,
It's possible that I have re-invented the wheel here, but I thought I
would share a simple solution I came up with to create fillets for the
intersection of two objects. It requires the objects to be defined with a
parametric size-offset, and it uses an iterative approach with hull() to
create a fillet. Here's an example with a cuboid (box()) embedded in a
cylinder (shaft()).

module shaft(dd=0) {
rotate([0,0,-10]) rotate([0,90,0]) cylinder(d=22+dd, h=100, $fn=60,
center=true);
}

module box(dd=0) {
translate([0,5,5]) cube([15+dd,18+dd,25+dd], center=true);
}

module filletSlice(ro, ang) {
p = ro * [(1-cos(ang)), (1-sin(ang))];
intersection() {
shaft(p.x);
box(p.y);
}
}

da = 10;
for (a=[0:da:90-da]) {
hull() {
filletSlice(2, a);
filletSlice(2, a+da);
}
}
shaft();
box();


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

There's the obvious limitation that if the area of intersection has native curvature then the fillet will pull away from the part (because hull() { object1() } != object1() in that area). So if eg object1() had a wave pattern, like some corrugated decking material... the result would not be good. On a case by case basis this sort of thing could probably be dealt with by iterating over another parameter, and intersecting with a third parametric object that creates small interpolations of the negative curve. But I am not sure how this will affect the computation time (geometric increase in calls to hull(), though each call on a much smaller object). On Tue, Feb 14, 2023 at 5:20 AM Sanjeev Prabhakar <sprabhakar2006@gmail.com> wrote: > It looks great, although not gone in detail. > Does it work for all type of solid to solid intersections? > > On Tue, 14 Feb, 2023, 9:58 am Daniel Harvey, <dwaharvey@gmail.com> wrote: > >> Hello, >> It's possible that I have re-invented the wheel here, but I thought I >> would share a simple solution I came up with to create fillets for the >> intersection of two objects. It requires the objects to be defined with a >> parametric size-offset, and it uses an iterative approach with hull() to >> create a fillet. Here's an example with a cuboid (box()) embedded in a >> cylinder (shaft()). >> >> module shaft(dd=0) { >> rotate([0,0,-10]) rotate([0,90,0]) cylinder(d=22+dd, h=100, $fn=60, >> center=true); >> } >> >> module box(dd=0) { >> translate([0,5,5]) cube([15+dd,18+dd,25+dd], center=true); >> } >> >> module filletSlice(ro, ang) { >> p = ro * [(1-cos(ang)), (1-sin(ang))]; >> intersection() { >> shaft(p.x); >> box(p.y); >> } >> } >> >> da = 10; >> for (a=[0:da:90-da]) { >> hull() { >> filletSlice(2, a); >> filletSlice(2, a+da); >> } >> } >> shaft(); >> box(); >> >> _______________________________________________ >> 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 >
AM
Adrian Mariano
Tue, Feb 14, 2023 10:01 PM

Daniel, I think what you really mean is that if the object is not convex in
the area around the intersection then you're in trouble.  There's no good
solution to this problem.  The hull() operation is called CONVEX hull for a
reason.  But I think this is an interesting approach, and I, at least, have
not seen it before.  (And I'm really interested in rounding.)

I wrote a version that assumes you have two children at unit scale and uses
scale() to make the joined object.  That doesn't require having a
parametrized module for each object, though it's limited in other ways.
With BOSL2 it would be natural to combine at least the translate and rotate
operators into a single matrix that you pass in.  I also added a chamfer
option.  (Note that there's no way to avoid the code duplication because
you can't pass children separately to a submodule.)

// Invoke with 2 children that are at unit scale and create a
// fillet joint between them, while applying specified transformations.
//
// r = radius of fillet (relative to scale of children)
// T0,R0,S0 = translation, rotation and scaling for object 0
// T1,R1,S1 = translation, rotation and scaling for object 1
// steps = number of steps in fillet
// chamfer = set true to get chamfer instead of rounding

module fillet_join(r, T0,R0,S0, T1,R1,S1, steps=10, chamfer=false)
{
assert($children==2);
da=1/steps;
for(a=[0:da:1-da/2]){
hull() {
first_offset = chamfer ? r * [a,1-a]
: r * [1-cos(90a), 1-sin(90a)];
first_scale0 = [for(s=S0) first_offset[0]+s];
first_scale1 = [for(s=S1) first_offset[1]+s];
second_offset = chamfer ? r * [a+da, 1-a-da]
: r * [1-cos(90*(a+da)),
1-sin(90*(a+da))];
second_scale0 = [for(s=S0) second_offset[0]+s];
second_scale1 = [for(s=S1) second_offset[1]+s];
intersection(){
translate(T0)rotate(R0)scale(first_scale0) children(0);
translate(T1)rotate(R1)scale(first_scale1) children(1);
}
intersection(){
translate(T0)rotate(R0)scale(second_scale0) children(0);
translate(T1)rotate(R1)scale(second_scale1) children(1);
}
}
}
translate(T0)rotate(R0)scale(S0) children(0);
translate(T1)rotate(R1)scale(S1) children(1);
}

fillet_join(3,[0,0,3], [0,90,-10], [22,22,100],
[0,6,6], [0,20,0], [15,20,28],chamfer=false)
{
cylinder(d=1,center=true,$fn=64);
cube(center=true);
}

[image: image.png]

On Tue, Feb 14, 2023 at 10:15 AM Daniel Harvey dwaharvey@gmail.com wrote:

There's the obvious limitation that if the area of intersection has native
curvature then the fillet will pull away from the part (because hull() {
object1() } != object1() in that area). So if eg object1() had a wave
pattern, like some corrugated decking material... the result would not be
good.
On a case by case basis this sort of thing could probably be dealt with by
iterating over another parameter, and intersecting with a third parametric
object that creates small interpolations of the negative curve. But I am
not sure how this will affect the computation time (geometric increase in
calls to hull(), though each call on a much smaller object).

On Tue, Feb 14, 2023 at 5:20 AM Sanjeev Prabhakar <
sprabhakar2006@gmail.com> wrote:

It looks great, although not gone in detail.
Does it work for all type of solid to solid intersections?

On Tue, 14 Feb, 2023, 9:58 am Daniel Harvey, dwaharvey@gmail.com wrote:

Hello,
It's possible that I have re-invented the wheel here, but I thought I
would share a simple solution I came up with to create fillets for the
intersection of two objects. It requires the objects to be defined with a
parametric size-offset, and it uses an iterative approach with hull() to
create a fillet. Here's an example with a cuboid (box()) embedded in a
cylinder (shaft()).

module shaft(dd=0) {
rotate([0,0,-10]) rotate([0,90,0]) cylinder(d=22+dd, h=100, $fn=60,
center=true);
}

module box(dd=0) {
translate([0,5,5]) cube([15+dd,18+dd,25+dd], center=true);
}

module filletSlice(ro, ang) {
p = ro * [(1-cos(ang)), (1-sin(ang))];
intersection() {
shaft(p.x);
box(p.y);
}
}

da = 10;
for (a=[0:da:90-da]) {
hull() {
filletSlice(2, a);
filletSlice(2, a+da);
}
}
shaft();
box();


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

Daniel, I think what you really mean is that if the object is not convex in the area around the intersection then you're in trouble. There's no good solution to this problem. The hull() operation is called CONVEX hull for a reason. But I think this is an interesting approach, and I, at least, have not seen it before. (And I'm really interested in rounding.) I wrote a version that assumes you have two children at unit scale and uses scale() to make the joined object. That doesn't require having a parametrized module for each object, though it's limited in other ways. With BOSL2 it would be natural to combine at least the translate and rotate operators into a single matrix that you pass in. I also added a chamfer option. (Note that there's no way to avoid the code duplication because you can't pass children separately to a submodule.) // Invoke with 2 children that are at unit scale and create a // fillet joint between them, while applying specified transformations. // // r = radius of fillet (relative to scale of children) // T0,R0,S0 = translation, rotation and scaling for object 0 // T1,R1,S1 = translation, rotation and scaling for object 1 // steps = number of steps in fillet // chamfer = set true to get chamfer instead of rounding module fillet_join(r, T0,R0,S0, T1,R1,S1, steps=10, chamfer=false) { assert($children==2); da=1/steps; for(a=[0:da:1-da/2]){ hull() { first_offset = chamfer ? r * [a,1-a] : r * [1-cos(90*a), 1-sin(90*a)]; first_scale0 = [for(s=S0) first_offset[0]+s]; first_scale1 = [for(s=S1) first_offset[1]+s]; second_offset = chamfer ? r * [a+da, 1-a-da] : r * [1-cos(90*(a+da)), 1-sin(90*(a+da))]; second_scale0 = [for(s=S0) second_offset[0]+s]; second_scale1 = [for(s=S1) second_offset[1]+s]; intersection(){ translate(T0)rotate(R0)scale(first_scale0) children(0); translate(T1)rotate(R1)scale(first_scale1) children(1); } intersection(){ translate(T0)rotate(R0)scale(second_scale0) children(0); translate(T1)rotate(R1)scale(second_scale1) children(1); } } } translate(T0)rotate(R0)scale(S0) children(0); translate(T1)rotate(R1)scale(S1) children(1); } fillet_join(3,[0,0,3], [0,90,-10], [22,22,100], [0,6,6], [0,20,0], [15,20,28],chamfer=false) { cylinder(d=1,center=true,$fn=64); cube(center=true); } [image: image.png] On Tue, Feb 14, 2023 at 10:15 AM Daniel Harvey <dwaharvey@gmail.com> wrote: > There's the obvious limitation that if the area of intersection has native > curvature then the fillet will pull away from the part (because hull() { > object1() } != object1() in that area). So if eg object1() had a wave > pattern, like some corrugated decking material... the result would not be > good. > On a case by case basis this sort of thing could probably be dealt with by > iterating over another parameter, and intersecting with a third parametric > object that creates small interpolations of the negative curve. But I am > not sure how this will affect the computation time (geometric increase in > calls to hull(), though each call on a much smaller object). > > On Tue, Feb 14, 2023 at 5:20 AM Sanjeev Prabhakar < > sprabhakar2006@gmail.com> wrote: > >> It looks great, although not gone in detail. >> Does it work for all type of solid to solid intersections? >> >> On Tue, 14 Feb, 2023, 9:58 am Daniel Harvey, <dwaharvey@gmail.com> wrote: >> >>> Hello, >>> It's possible that I have re-invented the wheel here, but I thought I >>> would share a simple solution I came up with to create fillets for the >>> intersection of two objects. It requires the objects to be defined with a >>> parametric size-offset, and it uses an iterative approach with hull() to >>> create a fillet. Here's an example with a cuboid (box()) embedded in a >>> cylinder (shaft()). >>> >>> module shaft(dd=0) { >>> rotate([0,0,-10]) rotate([0,90,0]) cylinder(d=22+dd, h=100, $fn=60, >>> center=true); >>> } >>> >>> module box(dd=0) { >>> translate([0,5,5]) cube([15+dd,18+dd,25+dd], center=true); >>> } >>> >>> module filletSlice(ro, ang) { >>> p = ro * [(1-cos(ang)), (1-sin(ang))]; >>> intersection() { >>> shaft(p.x); >>> box(p.y); >>> } >>> } >>> >>> da = 10; >>> for (a=[0:da:90-da]) { >>> hull() { >>> filletSlice(2, a); >>> filletSlice(2, a+da); >>> } >>> } >>> shaft(); >>> box(); >>> >>> _______________________________________________ >>> 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, Feb 15, 2023 1:49 AM

If the points of intersection between the 2 solids can be found then
creating fillet would be possible.
3 list of intersection points would be required
a. both the solids at their original dimensions
b.1st solid at original dimension and 2nd solid at offset = the fillet
radius (approximate)
c.1st solid at offset= the fillet radius and 2nd solid at original dimension

with the above 3 list of points
group the points e.g. first point of each list and create a fillet arc and
so on

finally create a polyheadron with all the fillet arcs

this works in most of the cases

On Wed, 15 Feb 2023, 03:32 Adrian Mariano, avm4@cornell.edu wrote:

Daniel, I think what you really mean is that if the object is not convex
in the area around the intersection then you're in trouble.  There's no
good solution to this problem.  The hull() operation is called CONVEX hull
for a reason.  But I think this is an interesting approach, and I, at
least, have not seen it before.  (And I'm really interested in rounding.)

I wrote a version that assumes you have two children at unit scale and
uses scale() to make the joined object.  That doesn't require having a
parametrized module for each object, though it's limited in other ways.
With BOSL2 it would be natural to combine at least the translate and rotate
operators into a single matrix that you pass in.  I also added a chamfer
option.  (Note that there's no way to avoid the code duplication because
you can't pass children separately to a submodule.)

// Invoke with 2 children that are at unit scale and create a
// fillet joint between them, while applying specified transformations.
//
// r = radius of fillet (relative to scale of children)
// T0,R0,S0 = translation, rotation and scaling for object 0
// T1,R1,S1 = translation, rotation and scaling for object 1
// steps = number of steps in fillet
// chamfer = set true to get chamfer instead of rounding

module fillet_join(r, T0,R0,S0, T1,R1,S1, steps=10, chamfer=false)
{
assert($children==2);
da=1/steps;
for(a=[0:da:1-da/2]){
hull() {
first_offset = chamfer ? r * [a,1-a]
: r * [1-cos(90a), 1-sin(90a)];
first_scale0 = [for(s=S0) first_offset[0]+s];
first_scale1 = [for(s=S1) first_offset[1]+s];
second_offset = chamfer ? r * [a+da, 1-a-da]
: r * [1-cos(90*(a+da)),
1-sin(90*(a+da))];
second_scale0 = [for(s=S0) second_offset[0]+s];
second_scale1 = [for(s=S1) second_offset[1]+s];
intersection(){
translate(T0)rotate(R0)scale(first_scale0) children(0);
translate(T1)rotate(R1)scale(first_scale1) children(1);
}
intersection(){
translate(T0)rotate(R0)scale(second_scale0) children(0);
translate(T1)rotate(R1)scale(second_scale1) children(1);
}
}
}
translate(T0)rotate(R0)scale(S0) children(0);
translate(T1)rotate(R1)scale(S1) children(1);
}

fillet_join(3,[0,0,3], [0,90,-10], [22,22,100],
[0,6,6], [0,20,0], [15,20,28],chamfer=false)
{
cylinder(d=1,center=true,$fn=64);
cube(center=true);
}

[image: image.png]

On Tue, Feb 14, 2023 at 10:15 AM Daniel Harvey dwaharvey@gmail.com
wrote:

There's the obvious limitation that if the area of intersection has
native curvature then the fillet will pull away from the part (because
hull() { object1() } != object1() in that area). So if eg object1() had a
wave pattern, like some corrugated decking material... the result would not
be good.
On a case by case basis this sort of thing could probably be dealt with
by iterating over another parameter, and intersecting with a third
parametric object that creates small interpolations of the negative curve.
But I am not sure how this will affect the computation time (geometric
increase in calls to hull(), though each call on a much smaller object).

On Tue, Feb 14, 2023 at 5:20 AM Sanjeev Prabhakar <
sprabhakar2006@gmail.com> wrote:

It looks great, although not gone in detail.
Does it work for all type of solid to solid intersections?

On Tue, 14 Feb, 2023, 9:58 am Daniel Harvey, dwaharvey@gmail.com
wrote:

Hello,
It's possible that I have re-invented the wheel here, but I thought I
would share a simple solution I came up with to create fillets for the
intersection of two objects. It requires the objects to be defined with a
parametric size-offset, and it uses an iterative approach with hull() to
create a fillet. Here's an example with a cuboid (box()) embedded in a
cylinder (shaft()).

module shaft(dd=0) {
rotate([0,0,-10]) rotate([0,90,0]) cylinder(d=22+dd, h=100, $fn=60,
center=true);
}

module box(dd=0) {
translate([0,5,5]) cube([15+dd,18+dd,25+dd], center=true);
}

module filletSlice(ro, ang) {
p = ro * [(1-cos(ang)), (1-sin(ang))];
intersection() {
shaft(p.x);
box(p.y);
}
}

da = 10;
for (a=[0:da:90-da]) {
hull() {
filletSlice(2, a);
filletSlice(2, a+da);
}
}
shaft();
box();


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

If the points of intersection between the 2 solids can be found then creating fillet would be possible. 3 list of intersection points would be required a. both the solids at their original dimensions b.1st solid at original dimension and 2nd solid at offset = the fillet radius (approximate) c.1st solid at offset= the fillet radius and 2nd solid at original dimension with the above 3 list of points group the points e.g. first point of each list and create a fillet arc and so on finally create a polyheadron with all the fillet arcs this works in most of the cases On Wed, 15 Feb 2023, 03:32 Adrian Mariano, <avm4@cornell.edu> wrote: > Daniel, I think what you really mean is that if the object is not convex > in the area around the intersection then you're in trouble. There's no > good solution to this problem. The hull() operation is called CONVEX hull > for a reason. But I think this is an interesting approach, and I, at > least, have not seen it before. (And I'm really interested in rounding.) > > I wrote a version that assumes you have two children at unit scale and > uses scale() to make the joined object. That doesn't require having a > parametrized module for each object, though it's limited in other ways. > With BOSL2 it would be natural to combine at least the translate and rotate > operators into a single matrix that you pass in. I also added a chamfer > option. (Note that there's no way to avoid the code duplication because > you can't pass children separately to a submodule.) > > // Invoke with 2 children that are at unit scale and create a > // fillet joint between them, while applying specified transformations. > // > // r = radius of fillet (relative to scale of children) > // T0,R0,S0 = translation, rotation and scaling for object 0 > // T1,R1,S1 = translation, rotation and scaling for object 1 > // steps = number of steps in fillet > // chamfer = set true to get chamfer instead of rounding > > module fillet_join(r, T0,R0,S0, T1,R1,S1, steps=10, chamfer=false) > { > assert($children==2); > da=1/steps; > for(a=[0:da:1-da/2]){ > hull() { > first_offset = chamfer ? r * [a,1-a] > : r * [1-cos(90*a), 1-sin(90*a)]; > first_scale0 = [for(s=S0) first_offset[0]+s]; > first_scale1 = [for(s=S1) first_offset[1]+s]; > second_offset = chamfer ? r * [a+da, 1-a-da] > : r * [1-cos(90*(a+da)), > 1-sin(90*(a+da))]; > second_scale0 = [for(s=S0) second_offset[0]+s]; > second_scale1 = [for(s=S1) second_offset[1]+s]; > intersection(){ > translate(T0)rotate(R0)scale(first_scale0) children(0); > translate(T1)rotate(R1)scale(first_scale1) children(1); > } > intersection(){ > translate(T0)rotate(R0)scale(second_scale0) children(0); > translate(T1)rotate(R1)scale(second_scale1) children(1); > } > } > } > translate(T0)rotate(R0)scale(S0) children(0); > translate(T1)rotate(R1)scale(S1) children(1); > } > > > fillet_join(3,[0,0,3], [0,90,-10], [22,22,100], > [0,6,6], [0,20,0], [15,20,28],chamfer=false) > { > cylinder(d=1,center=true,$fn=64); > cube(center=true); > } > > [image: image.png] > > > On Tue, Feb 14, 2023 at 10:15 AM Daniel Harvey <dwaharvey@gmail.com> > wrote: > >> There's the obvious limitation that if the area of intersection has >> native curvature then the fillet will pull away from the part (because >> hull() { object1() } != object1() in that area). So if eg object1() had a >> wave pattern, like some corrugated decking material... the result would not >> be good. >> On a case by case basis this sort of thing could probably be dealt with >> by iterating over another parameter, and intersecting with a third >> parametric object that creates small interpolations of the negative curve. >> But I am not sure how this will affect the computation time (geometric >> increase in calls to hull(), though each call on a much smaller object). >> >> On Tue, Feb 14, 2023 at 5:20 AM Sanjeev Prabhakar < >> sprabhakar2006@gmail.com> wrote: >> >>> It looks great, although not gone in detail. >>> Does it work for all type of solid to solid intersections? >>> >>> On Tue, 14 Feb, 2023, 9:58 am Daniel Harvey, <dwaharvey@gmail.com> >>> wrote: >>> >>>> Hello, >>>> It's possible that I have re-invented the wheel here, but I thought I >>>> would share a simple solution I came up with to create fillets for the >>>> intersection of two objects. It requires the objects to be defined with a >>>> parametric size-offset, and it uses an iterative approach with hull() to >>>> create a fillet. Here's an example with a cuboid (box()) embedded in a >>>> cylinder (shaft()). >>>> >>>> module shaft(dd=0) { >>>> rotate([0,0,-10]) rotate([0,90,0]) cylinder(d=22+dd, h=100, $fn=60, >>>> center=true); >>>> } >>>> >>>> module box(dd=0) { >>>> translate([0,5,5]) cube([15+dd,18+dd,25+dd], center=true); >>>> } >>>> >>>> module filletSlice(ro, ang) { >>>> p = ro * [(1-cos(ang)), (1-sin(ang))]; >>>> intersection() { >>>> shaft(p.x); >>>> box(p.y); >>>> } >>>> } >>>> >>>> da = 10; >>>> for (a=[0:da:90-da]) { >>>> hull() { >>>> filletSlice(2, a); >>>> filletSlice(2, a+da); >>>> } >>>> } >>>> shaft(); >>>> box(); >>>> >>>> _______________________________________________ >>>> 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 >
DH
Daniel Harvey
Wed, Feb 15, 2023 2:31 AM

Thanks for the embellishments Adrian. It is a pity that OpenSCAD doesn't
allow you to pass one module definition as an argument to another, as
Python does - and I was grasping for. Your approach cleans that up nicely.
Given the limitations of what OpenSCAD gives you access to, this seemed to
be like the simplest and most direct way to achieve this outcome.

On Tue, Feb 14, 2023 at 3:02 PM Adrian Mariano avm4@cornell.edu wrote:

Daniel, I think what you really mean is that if the object is not convex
in the area around the intersection then you're in trouble.  There's no
good solution to this problem.  The hull() operation is called CONVEX hull
for a reason.  But I think this is an interesting approach, and I, at
least, have not seen it before.  (And I'm really interested in rounding.)

I wrote a version that assumes you have two children at unit scale and
uses scale() to make the joined object.  That doesn't require having a
parametrized module for each object, though it's limited in other ways.
With BOSL2 it would be natural to combine at least the translate and rotate
operators into a single matrix that you pass in.  I also added a chamfer
option.  (Note that there's no way to avoid the code duplication because
you can't pass children separately to a submodule.)

// Invoke with 2 children that are at unit scale and create a
// fillet joint between them, while applying specified transformations.
//
// r = radius of fillet (relative to scale of children)
// T0,R0,S0 = translation, rotation and scaling for object 0
// T1,R1,S1 = translation, rotation and scaling for object 1
// steps = number of steps in fillet
// chamfer = set true to get chamfer instead of rounding

module fillet_join(r, T0,R0,S0, T1,R1,S1, steps=10, chamfer=false)
{
assert($children==2);
da=1/steps;
for(a=[0:da:1-da/2]){
hull() {
first_offset = chamfer ? r * [a,1-a]
: r * [1-cos(90a), 1-sin(90a)];
first_scale0 = [for(s=S0) first_offset[0]+s];
first_scale1 = [for(s=S1) first_offset[1]+s];
second_offset = chamfer ? r * [a+da, 1-a-da]
: r * [1-cos(90*(a+da)),
1-sin(90*(a+da))];
second_scale0 = [for(s=S0) second_offset[0]+s];
second_scale1 = [for(s=S1) second_offset[1]+s];
intersection(){
translate(T0)rotate(R0)scale(first_scale0) children(0);
translate(T1)rotate(R1)scale(first_scale1) children(1);
}
intersection(){
translate(T0)rotate(R0)scale(second_scale0) children(0);
translate(T1)rotate(R1)scale(second_scale1) children(1);
}
}
}
translate(T0)rotate(R0)scale(S0) children(0);
translate(T1)rotate(R1)scale(S1) children(1);
}

fillet_join(3,[0,0,3], [0,90,-10], [22,22,100],
[0,6,6], [0,20,0], [15,20,28],chamfer=false)
{
cylinder(d=1,center=true,$fn=64);
cube(center=true);
}

[image: image.png]

On Tue, Feb 14, 2023 at 10:15 AM Daniel Harvey dwaharvey@gmail.com
wrote:

There's the obvious limitation that if the area of intersection has
native curvature then the fillet will pull away from the part (because
hull() { object1() } != object1() in that area). So if eg object1() had a
wave pattern, like some corrugated decking material... the result would not
be good.
On a case by case basis this sort of thing could probably be dealt with
by iterating over another parameter, and intersecting with a third
parametric object that creates small interpolations of the negative curve.
But I am not sure how this will affect the computation time (geometric
increase in calls to hull(), though each call on a much smaller object).

On Tue, Feb 14, 2023 at 5:20 AM Sanjeev Prabhakar <
sprabhakar2006@gmail.com> wrote:

It looks great, although not gone in detail.
Does it work for all type of solid to solid intersections?

On Tue, 14 Feb, 2023, 9:58 am Daniel Harvey, dwaharvey@gmail.com
wrote:

Hello,
It's possible that I have re-invented the wheel here, but I thought I
would share a simple solution I came up with to create fillets for the
intersection of two objects. It requires the objects to be defined with a
parametric size-offset, and it uses an iterative approach with hull() to
create a fillet. Here's an example with a cuboid (box()) embedded in a
cylinder (shaft()).

module shaft(dd=0) {
rotate([0,0,-10]) rotate([0,90,0]) cylinder(d=22+dd, h=100, $fn=60,
center=true);
}

module box(dd=0) {
translate([0,5,5]) cube([15+dd,18+dd,25+dd], center=true);
}

module filletSlice(ro, ang) {
p = ro * [(1-cos(ang)), (1-sin(ang))];
intersection() {
shaft(p.x);
box(p.y);
}
}

da = 10;
for (a=[0:da:90-da]) {
hull() {
filletSlice(2, a);
filletSlice(2, a+da);
}
}
shaft();
box();


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

Thanks for the embellishments Adrian. It is a pity that OpenSCAD doesn't allow you to pass one module definition as an argument to another, as Python does - and I was grasping for. Your approach cleans that up nicely. Given the limitations of what OpenSCAD gives you access to, this seemed to be like the simplest and most direct way to achieve this outcome. On Tue, Feb 14, 2023 at 3:02 PM Adrian Mariano <avm4@cornell.edu> wrote: > Daniel, I think what you really mean is that if the object is not convex > in the area around the intersection then you're in trouble. There's no > good solution to this problem. The hull() operation is called CONVEX hull > for a reason. But I think this is an interesting approach, and I, at > least, have not seen it before. (And I'm really interested in rounding.) > > I wrote a version that assumes you have two children at unit scale and > uses scale() to make the joined object. That doesn't require having a > parametrized module for each object, though it's limited in other ways. > With BOSL2 it would be natural to combine at least the translate and rotate > operators into a single matrix that you pass in. I also added a chamfer > option. (Note that there's no way to avoid the code duplication because > you can't pass children separately to a submodule.) > > // Invoke with 2 children that are at unit scale and create a > // fillet joint between them, while applying specified transformations. > // > // r = radius of fillet (relative to scale of children) > // T0,R0,S0 = translation, rotation and scaling for object 0 > // T1,R1,S1 = translation, rotation and scaling for object 1 > // steps = number of steps in fillet > // chamfer = set true to get chamfer instead of rounding > > module fillet_join(r, T0,R0,S0, T1,R1,S1, steps=10, chamfer=false) > { > assert($children==2); > da=1/steps; > for(a=[0:da:1-da/2]){ > hull() { > first_offset = chamfer ? r * [a,1-a] > : r * [1-cos(90*a), 1-sin(90*a)]; > first_scale0 = [for(s=S0) first_offset[0]+s]; > first_scale1 = [for(s=S1) first_offset[1]+s]; > second_offset = chamfer ? r * [a+da, 1-a-da] > : r * [1-cos(90*(a+da)), > 1-sin(90*(a+da))]; > second_scale0 = [for(s=S0) second_offset[0]+s]; > second_scale1 = [for(s=S1) second_offset[1]+s]; > intersection(){ > translate(T0)rotate(R0)scale(first_scale0) children(0); > translate(T1)rotate(R1)scale(first_scale1) children(1); > } > intersection(){ > translate(T0)rotate(R0)scale(second_scale0) children(0); > translate(T1)rotate(R1)scale(second_scale1) children(1); > } > } > } > translate(T0)rotate(R0)scale(S0) children(0); > translate(T1)rotate(R1)scale(S1) children(1); > } > > > fillet_join(3,[0,0,3], [0,90,-10], [22,22,100], > [0,6,6], [0,20,0], [15,20,28],chamfer=false) > { > cylinder(d=1,center=true,$fn=64); > cube(center=true); > } > > [image: image.png] > > > On Tue, Feb 14, 2023 at 10:15 AM Daniel Harvey <dwaharvey@gmail.com> > wrote: > >> There's the obvious limitation that if the area of intersection has >> native curvature then the fillet will pull away from the part (because >> hull() { object1() } != object1() in that area). So if eg object1() had a >> wave pattern, like some corrugated decking material... the result would not >> be good. >> On a case by case basis this sort of thing could probably be dealt with >> by iterating over another parameter, and intersecting with a third >> parametric object that creates small interpolations of the negative curve. >> But I am not sure how this will affect the computation time (geometric >> increase in calls to hull(), though each call on a much smaller object). >> >> On Tue, Feb 14, 2023 at 5:20 AM Sanjeev Prabhakar < >> sprabhakar2006@gmail.com> wrote: >> >>> It looks great, although not gone in detail. >>> Does it work for all type of solid to solid intersections? >>> >>> On Tue, 14 Feb, 2023, 9:58 am Daniel Harvey, <dwaharvey@gmail.com> >>> wrote: >>> >>>> Hello, >>>> It's possible that I have re-invented the wheel here, but I thought I >>>> would share a simple solution I came up with to create fillets for the >>>> intersection of two objects. It requires the objects to be defined with a >>>> parametric size-offset, and it uses an iterative approach with hull() to >>>> create a fillet. Here's an example with a cuboid (box()) embedded in a >>>> cylinder (shaft()). >>>> >>>> module shaft(dd=0) { >>>> rotate([0,0,-10]) rotate([0,90,0]) cylinder(d=22+dd, h=100, $fn=60, >>>> center=true); >>>> } >>>> >>>> module box(dd=0) { >>>> translate([0,5,5]) cube([15+dd,18+dd,25+dd], center=true); >>>> } >>>> >>>> module filletSlice(ro, ang) { >>>> p = ro * [(1-cos(ang)), (1-sin(ang))]; >>>> intersection() { >>>> shaft(p.x); >>>> box(p.y); >>>> } >>>> } >>>> >>>> da = 10; >>>> for (a=[0:da:90-da]) { >>>> hull() { >>>> filletSlice(2, a); >>>> filletSlice(2, a+da); >>>> } >>>> } >>>> shaft(); >>>> box(); >>>> >>>> _______________________________________________ >>>> 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 >
DH
Daniel Harvey
Wed, Feb 15, 2023 2:33 AM

Sanjay, I agree with you, and getting a list of the intersection points was
what I was originally thinking about, but I'm not aware of any OpenSCAD way
to obtain that information. I imagine in a python notebook one could do it
(?), but I am doing everything in OpenSCAD directly and was looking for a
good/simple way to get this done.

On Tue, Feb 14, 2023 at 6:50 PM Sanjeev Prabhakar sprabhakar2006@gmail.com
wrote:

If the points of intersection between the 2 solids can be found then
creating fillet would be possible.
3 list of intersection points would be required
a. both the solids at their original dimensions
b.1st solid at original dimension and 2nd solid at offset = the fillet
radius (approximate)
c.1st solid at offset= the fillet radius and 2nd solid at original
dimension

with the above 3 list of points
group the points e.g. first point of each list and create a fillet arc and
so on

finally create a polyheadron with all the fillet arcs

this works in most of the cases

On Wed, 15 Feb 2023, 03:32 Adrian Mariano, avm4@cornell.edu wrote:

Daniel, I think what you really mean is that if the object is not convex
in the area around the intersection then you're in trouble.  There's no
good solution to this problem.  The hull() operation is called CONVEX hull
for a reason.  But I think this is an interesting approach, and I, at
least, have not seen it before.  (And I'm really interested in rounding.)

I wrote a version that assumes you have two children at unit scale and
uses scale() to make the joined object.  That doesn't require having a
parametrized module for each object, though it's limited in other ways.
With BOSL2 it would be natural to combine at least the translate and rotate
operators into a single matrix that you pass in.  I also added a chamfer
option.  (Note that there's no way to avoid the code duplication because
you can't pass children separately to a submodule.)

// Invoke with 2 children that are at unit scale and create a
// fillet joint between them, while applying specified transformations.
//
// r = radius of fillet (relative to scale of children)
// T0,R0,S0 = translation, rotation and scaling for object 0
// T1,R1,S1 = translation, rotation and scaling for object 1
// steps = number of steps in fillet
// chamfer = set true to get chamfer instead of rounding

module fillet_join(r, T0,R0,S0, T1,R1,S1, steps=10, chamfer=false)
{
assert($children==2);
da=1/steps;
for(a=[0:da:1-da/2]){
hull() {
first_offset = chamfer ? r * [a,1-a]
: r * [1-cos(90a), 1-sin(90a)];
first_scale0 = [for(s=S0) first_offset[0]+s];
first_scale1 = [for(s=S1) first_offset[1]+s];
second_offset = chamfer ? r * [a+da, 1-a-da]
: r * [1-cos(90*(a+da)),
1-sin(90*(a+da))];
second_scale0 = [for(s=S0) second_offset[0]+s];
second_scale1 = [for(s=S1) second_offset[1]+s];
intersection(){
translate(T0)rotate(R0)scale(first_scale0) children(0);
translate(T1)rotate(R1)scale(first_scale1) children(1);
}
intersection(){
translate(T0)rotate(R0)scale(second_scale0) children(0);
translate(T1)rotate(R1)scale(second_scale1) children(1);
}
}
}
translate(T0)rotate(R0)scale(S0) children(0);
translate(T1)rotate(R1)scale(S1) children(1);
}

fillet_join(3,[0,0,3], [0,90,-10], [22,22,100],
[0,6,6], [0,20,0], [15,20,28],chamfer=false)
{
cylinder(d=1,center=true,$fn=64);
cube(center=true);
}

[image: image.png]

On Tue, Feb 14, 2023 at 10:15 AM Daniel Harvey dwaharvey@gmail.com
wrote:

There's the obvious limitation that if the area of intersection has
native curvature then the fillet will pull away from the part (because
hull() { object1() } != object1() in that area). So if eg object1() had a
wave pattern, like some corrugated decking material... the result would not
be good.
On a case by case basis this sort of thing could probably be dealt with
by iterating over another parameter, and intersecting with a third
parametric object that creates small interpolations of the negative curve.
But I am not sure how this will affect the computation time (geometric
increase in calls to hull(), though each call on a much smaller object).

On Tue, Feb 14, 2023 at 5:20 AM Sanjeev Prabhakar <
sprabhakar2006@gmail.com> wrote:

It looks great, although not gone in detail.
Does it work for all type of solid to solid intersections?

On Tue, 14 Feb, 2023, 9:58 am Daniel Harvey, dwaharvey@gmail.com
wrote:

Hello,
It's possible that I have re-invented the wheel here, but I thought I
would share a simple solution I came up with to create fillets for the
intersection of two objects. It requires the objects to be defined with a
parametric size-offset, and it uses an iterative approach with hull() to
create a fillet. Here's an example with a cuboid (box()) embedded in a
cylinder (shaft()).

module shaft(dd=0) {
rotate([0,0,-10]) rotate([0,90,0]) cylinder(d=22+dd, h=100,
$fn=60, center=true);
}

module box(dd=0) {
translate([0,5,5]) cube([15+dd,18+dd,25+dd], center=true);
}

module filletSlice(ro, ang) {
p = ro * [(1-cos(ang)), (1-sin(ang))];
intersection() {
shaft(p.x);
box(p.y);
}
}

da = 10;
for (a=[0:da:90-da]) {
hull() {
filletSlice(2, a);
filletSlice(2, a+da);
}
}
shaft();
box();


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


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

Sanjay, I agree with you, and getting a list of the intersection points was what I was originally thinking about, but I'm not aware of any OpenSCAD way to obtain that information. I imagine in a python notebook one could do it (?), but I am doing everything in OpenSCAD directly and was looking for a good/simple way to get this done. On Tue, Feb 14, 2023 at 6:50 PM Sanjeev Prabhakar <sprabhakar2006@gmail.com> wrote: > If the points of intersection between the 2 solids can be found then > creating fillet would be possible. > 3 list of intersection points would be required > a. both the solids at their original dimensions > b.1st solid at original dimension and 2nd solid at offset = the fillet > radius (approximate) > c.1st solid at offset= the fillet radius and 2nd solid at original > dimension > > with the above 3 list of points > group the points e.g. first point of each list and create a fillet arc and > so on > > finally create a polyheadron with all the fillet arcs > > this works in most of the cases > > On Wed, 15 Feb 2023, 03:32 Adrian Mariano, <avm4@cornell.edu> wrote: > >> Daniel, I think what you really mean is that if the object is not convex >> in the area around the intersection then you're in trouble. There's no >> good solution to this problem. The hull() operation is called CONVEX hull >> for a reason. But I think this is an interesting approach, and I, at >> least, have not seen it before. (And I'm really interested in rounding.) >> >> I wrote a version that assumes you have two children at unit scale and >> uses scale() to make the joined object. That doesn't require having a >> parametrized module for each object, though it's limited in other ways. >> With BOSL2 it would be natural to combine at least the translate and rotate >> operators into a single matrix that you pass in. I also added a chamfer >> option. (Note that there's no way to avoid the code duplication because >> you can't pass children separately to a submodule.) >> >> // Invoke with 2 children that are at unit scale and create a >> // fillet joint between them, while applying specified transformations. >> // >> // r = radius of fillet (relative to scale of children) >> // T0,R0,S0 = translation, rotation and scaling for object 0 >> // T1,R1,S1 = translation, rotation and scaling for object 1 >> // steps = number of steps in fillet >> // chamfer = set true to get chamfer instead of rounding >> >> module fillet_join(r, T0,R0,S0, T1,R1,S1, steps=10, chamfer=false) >> { >> assert($children==2); >> da=1/steps; >> for(a=[0:da:1-da/2]){ >> hull() { >> first_offset = chamfer ? r * [a,1-a] >> : r * [1-cos(90*a), 1-sin(90*a)]; >> first_scale0 = [for(s=S0) first_offset[0]+s]; >> first_scale1 = [for(s=S1) first_offset[1]+s]; >> second_offset = chamfer ? r * [a+da, 1-a-da] >> : r * [1-cos(90*(a+da)), >> 1-sin(90*(a+da))]; >> second_scale0 = [for(s=S0) second_offset[0]+s]; >> second_scale1 = [for(s=S1) second_offset[1]+s]; >> intersection(){ >> translate(T0)rotate(R0)scale(first_scale0) children(0); >> translate(T1)rotate(R1)scale(first_scale1) children(1); >> } >> intersection(){ >> translate(T0)rotate(R0)scale(second_scale0) children(0); >> translate(T1)rotate(R1)scale(second_scale1) children(1); >> } >> } >> } >> translate(T0)rotate(R0)scale(S0) children(0); >> translate(T1)rotate(R1)scale(S1) children(1); >> } >> >> >> fillet_join(3,[0,0,3], [0,90,-10], [22,22,100], >> [0,6,6], [0,20,0], [15,20,28],chamfer=false) >> { >> cylinder(d=1,center=true,$fn=64); >> cube(center=true); >> } >> >> [image: image.png] >> >> >> On Tue, Feb 14, 2023 at 10:15 AM Daniel Harvey <dwaharvey@gmail.com> >> wrote: >> >>> There's the obvious limitation that if the area of intersection has >>> native curvature then the fillet will pull away from the part (because >>> hull() { object1() } != object1() in that area). So if eg object1() had a >>> wave pattern, like some corrugated decking material... the result would not >>> be good. >>> On a case by case basis this sort of thing could probably be dealt with >>> by iterating over another parameter, and intersecting with a third >>> parametric object that creates small interpolations of the negative curve. >>> But I am not sure how this will affect the computation time (geometric >>> increase in calls to hull(), though each call on a much smaller object). >>> >>> On Tue, Feb 14, 2023 at 5:20 AM Sanjeev Prabhakar < >>> sprabhakar2006@gmail.com> wrote: >>> >>>> It looks great, although not gone in detail. >>>> Does it work for all type of solid to solid intersections? >>>> >>>> On Tue, 14 Feb, 2023, 9:58 am Daniel Harvey, <dwaharvey@gmail.com> >>>> wrote: >>>> >>>>> Hello, >>>>> It's possible that I have re-invented the wheel here, but I thought I >>>>> would share a simple solution I came up with to create fillets for the >>>>> intersection of two objects. It requires the objects to be defined with a >>>>> parametric size-offset, and it uses an iterative approach with hull() to >>>>> create a fillet. Here's an example with a cuboid (box()) embedded in a >>>>> cylinder (shaft()). >>>>> >>>>> module shaft(dd=0) { >>>>> rotate([0,0,-10]) rotate([0,90,0]) cylinder(d=22+dd, h=100, >>>>> $fn=60, center=true); >>>>> } >>>>> >>>>> module box(dd=0) { >>>>> translate([0,5,5]) cube([15+dd,18+dd,25+dd], center=true); >>>>> } >>>>> >>>>> module filletSlice(ro, ang) { >>>>> p = ro * [(1-cos(ang)), (1-sin(ang))]; >>>>> intersection() { >>>>> shaft(p.x); >>>>> box(p.y); >>>>> } >>>>> } >>>>> >>>>> da = 10; >>>>> for (a=[0:da:90-da]) { >>>>> hull() { >>>>> filletSlice(2, a); >>>>> filletSlice(2, a+da); >>>>> } >>>>> } >>>>> shaft(); >>>>> box(); >>>>> >>>>> _______________________________________________ >>>>> 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 >> > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org >
AM
Adrian Mariano
Wed, Feb 15, 2023 2:43 AM

Daniel, it's not that you need to be able to pass modules, but at least it
would be cleaner if you could pass the children rather than just the union
of all the children to a called module.  Maybe there is a way to streamline
my code a bit by applying the transformation to each object separately in a
module---I think it would only be a slight improvement.  Of course, the
real ideal is to have access to the geometry data explicitly in your
modules, which is not (yet?) possible.  Note that a few months ago, Sanjeev
and I  had a lengthy discussion about rounding the joint between two
objects.  Both Sanjeev and I wrote code to do it, but Sanjeev has moved to
doing everything in Python and using OpenSCAD just as a display engine.
Both of us assumed that the objects were available as point lists, not as
OpenSCAD geometry, so it was possible to actually compute those
intersections and make fillets work even for concave objects, though there
are some complications that can still arise when your fillet ends up
self-intersecting.  To see my results take a a look at join_prism() from
the BOSL2 library:

https://github.com/revarbat/BOSL2/wiki/rounding.scad#functionmodule-join_prism

There are 55 examples to show how it works.  :)    But for convex objects
your approach can handle cases that my code cannot, like objects that
half-intersect each other.  And it doesn't require that the objects be one
of prism, plane or sphere.

On Tue, Feb 14, 2023 at 9:34 PM Daniel Harvey dwaharvey@gmail.com wrote:

Sanjay, I agree with you, and getting a list of the intersection points
was what I was originally thinking about, but I'm not aware of any OpenSCAD
way to obtain that information. I imagine in a python notebook one could do
it (?), but I am doing everything in OpenSCAD directly and was looking for
a good/simple way to get this done.

On Tue, Feb 14, 2023 at 6:50 PM Sanjeev Prabhakar <
sprabhakar2006@gmail.com> wrote:

If the points of intersection between the 2 solids can be found then
creating fillet would be possible.
3 list of intersection points would be required
a. both the solids at their original dimensions
b.1st solid at original dimension and 2nd solid at offset = the fillet
radius (approximate)
c.1st solid at offset= the fillet radius and 2nd solid at original
dimension

with the above 3 list of points
group the points e.g. first point of each list and create a fillet arc
and so on

finally create a polyheadron with all the fillet arcs

this works in most of the cases

On Wed, 15 Feb 2023, 03:32 Adrian Mariano, avm4@cornell.edu wrote:

Daniel, I think what you really mean is that if the object is not convex
in the area around the intersection then you're in trouble.  There's no
good solution to this problem.  The hull() operation is called CONVEX hull
for a reason.  But I think this is an interesting approach, and I, at
least, have not seen it before.  (And I'm really interested in rounding.)

I wrote a version that assumes you have two children at unit scale and
uses scale() to make the joined object.  That doesn't require having a
parametrized module for each object, though it's limited in other ways.
With BOSL2 it would be natural to combine at least the translate and rotate
operators into a single matrix that you pass in.  I also added a chamfer
option.  (Note that there's no way to avoid the code duplication because
you can't pass children separately to a submodule.)

// Invoke with 2 children that are at unit scale and create a
// fillet joint between them, while applying specified transformations.
//
// r = radius of fillet (relative to scale of children)
// T0,R0,S0 = translation, rotation and scaling for object 0
// T1,R1,S1 = translation, rotation and scaling for object 1
// steps = number of steps in fillet
// chamfer = set true to get chamfer instead of rounding

module fillet_join(r, T0,R0,S0, T1,R1,S1, steps=10, chamfer=false)
{
assert($children==2);
da=1/steps;
for(a=[0:da:1-da/2]){
hull() {
first_offset = chamfer ? r * [a,1-a]
: r * [1-cos(90a), 1-sin(90a)];
first_scale0 = [for(s=S0) first_offset[0]+s];
first_scale1 = [for(s=S1) first_offset[1]+s];
second_offset = chamfer ? r * [a+da, 1-a-da]
: r * [1-cos(90*(a+da)),
1-sin(90*(a+da))];
second_scale0 = [for(s=S0) second_offset[0]+s];
second_scale1 = [for(s=S1) second_offset[1]+s];
intersection(){
translate(T0)rotate(R0)scale(first_scale0) children(0);
translate(T1)rotate(R1)scale(first_scale1) children(1);
}
intersection(){
translate(T0)rotate(R0)scale(second_scale0) children(0);
translate(T1)rotate(R1)scale(second_scale1) children(1);
}
}
}
translate(T0)rotate(R0)scale(S0) children(0);
translate(T1)rotate(R1)scale(S1) children(1);
}

fillet_join(3,[0,0,3], [0,90,-10], [22,22,100],
[0,6,6], [0,20,0], [15,20,28],chamfer=false)
{
cylinder(d=1,center=true,$fn=64);
cube(center=true);
}

[image: image.png]

On Tue, Feb 14, 2023 at 10:15 AM Daniel Harvey dwaharvey@gmail.com
wrote:

There's the obvious limitation that if the area of intersection has
native curvature then the fillet will pull away from the part (because
hull() { object1() } != object1() in that area). So if eg object1() had a
wave pattern, like some corrugated decking material... the result would not
be good.
On a case by case basis this sort of thing could probably be dealt with
by iterating over another parameter, and intersecting with a third
parametric object that creates small interpolations of the negative curve.
But I am not sure how this will affect the computation time (geometric
increase in calls to hull(), though each call on a much smaller object).

On Tue, Feb 14, 2023 at 5:20 AM Sanjeev Prabhakar <
sprabhakar2006@gmail.com> wrote:

It looks great, although not gone in detail.
Does it work for all type of solid to solid intersections?

On Tue, 14 Feb, 2023, 9:58 am Daniel Harvey, dwaharvey@gmail.com
wrote:

Hello,
It's possible that I have re-invented the wheel here, but I thought I
would share a simple solution I came up with to create fillets for the
intersection of two objects. It requires the objects to be defined with a
parametric size-offset, and it uses an iterative approach with hull() to
create a fillet. Here's an example with a cuboid (box()) embedded in a
cylinder (shaft()).

module shaft(dd=0) {
rotate([0,0,-10]) rotate([0,90,0]) cylinder(d=22+dd, h=100,
$fn=60, center=true);
}

module box(dd=0) {
translate([0,5,5]) cube([15+dd,18+dd,25+dd], center=true);
}

module filletSlice(ro, ang) {
p = ro * [(1-cos(ang)), (1-sin(ang))];
intersection() {
shaft(p.x);
box(p.y);
}
}

da = 10;
for (a=[0:da:90-da]) {
hull() {
filletSlice(2, a);
filletSlice(2, a+da);
}
}
shaft();
box();


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


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

Daniel, it's not that you need to be able to pass modules, but at least it would be cleaner if you could pass the children rather than just the union of all the children to a called module. Maybe there is a way to streamline my code a bit by applying the transformation to each object separately in a module---I think it would only be a slight improvement. Of course, the real ideal is to have access to the geometry data explicitly in your modules, which is not (yet?) possible. Note that a few months ago, Sanjeev and I had a lengthy discussion about rounding the joint between two objects. Both Sanjeev and I wrote code to do it, but Sanjeev has moved to doing everything in Python and using OpenSCAD just as a display engine. Both of us assumed that the objects were available as point lists, not as OpenSCAD geometry, so it was possible to actually compute those intersections and make fillets work even for concave objects, though there are some complications that can still arise when your fillet ends up self-intersecting. To see my results take a a look at join_prism() from the BOSL2 library: https://github.com/revarbat/BOSL2/wiki/rounding.scad#functionmodule-join_prism There are 55 examples to show how it works. :) But for convex objects your approach can handle cases that my code cannot, like objects that half-intersect each other. And it doesn't require that the objects be one of prism, plane or sphere. On Tue, Feb 14, 2023 at 9:34 PM Daniel Harvey <dwaharvey@gmail.com> wrote: > Sanjay, I agree with you, and getting a list of the intersection points > was what I was originally thinking about, but I'm not aware of any OpenSCAD > way to obtain that information. I imagine in a python notebook one could do > it (?), but I am doing everything in OpenSCAD directly and was looking for > a good/simple way to get this done. > > On Tue, Feb 14, 2023 at 6:50 PM Sanjeev Prabhakar < > sprabhakar2006@gmail.com> wrote: > >> If the points of intersection between the 2 solids can be found then >> creating fillet would be possible. >> 3 list of intersection points would be required >> a. both the solids at their original dimensions >> b.1st solid at original dimension and 2nd solid at offset = the fillet >> radius (approximate) >> c.1st solid at offset= the fillet radius and 2nd solid at original >> dimension >> >> with the above 3 list of points >> group the points e.g. first point of each list and create a fillet arc >> and so on >> >> finally create a polyheadron with all the fillet arcs >> >> this works in most of the cases >> >> On Wed, 15 Feb 2023, 03:32 Adrian Mariano, <avm4@cornell.edu> wrote: >> >>> Daniel, I think what you really mean is that if the object is not convex >>> in the area around the intersection then you're in trouble. There's no >>> good solution to this problem. The hull() operation is called CONVEX hull >>> for a reason. But I think this is an interesting approach, and I, at >>> least, have not seen it before. (And I'm really interested in rounding.) >>> >>> I wrote a version that assumes you have two children at unit scale and >>> uses scale() to make the joined object. That doesn't require having a >>> parametrized module for each object, though it's limited in other ways. >>> With BOSL2 it would be natural to combine at least the translate and rotate >>> operators into a single matrix that you pass in. I also added a chamfer >>> option. (Note that there's no way to avoid the code duplication because >>> you can't pass children separately to a submodule.) >>> >>> // Invoke with 2 children that are at unit scale and create a >>> // fillet joint between them, while applying specified transformations. >>> // >>> // r = radius of fillet (relative to scale of children) >>> // T0,R0,S0 = translation, rotation and scaling for object 0 >>> // T1,R1,S1 = translation, rotation and scaling for object 1 >>> // steps = number of steps in fillet >>> // chamfer = set true to get chamfer instead of rounding >>> >>> module fillet_join(r, T0,R0,S0, T1,R1,S1, steps=10, chamfer=false) >>> { >>> assert($children==2); >>> da=1/steps; >>> for(a=[0:da:1-da/2]){ >>> hull() { >>> first_offset = chamfer ? r * [a,1-a] >>> : r * [1-cos(90*a), 1-sin(90*a)]; >>> first_scale0 = [for(s=S0) first_offset[0]+s]; >>> first_scale1 = [for(s=S1) first_offset[1]+s]; >>> second_offset = chamfer ? r * [a+da, 1-a-da] >>> : r * [1-cos(90*(a+da)), >>> 1-sin(90*(a+da))]; >>> second_scale0 = [for(s=S0) second_offset[0]+s]; >>> second_scale1 = [for(s=S1) second_offset[1]+s]; >>> intersection(){ >>> translate(T0)rotate(R0)scale(first_scale0) children(0); >>> translate(T1)rotate(R1)scale(first_scale1) children(1); >>> } >>> intersection(){ >>> translate(T0)rotate(R0)scale(second_scale0) children(0); >>> translate(T1)rotate(R1)scale(second_scale1) children(1); >>> } >>> } >>> } >>> translate(T0)rotate(R0)scale(S0) children(0); >>> translate(T1)rotate(R1)scale(S1) children(1); >>> } >>> >>> >>> fillet_join(3,[0,0,3], [0,90,-10], [22,22,100], >>> [0,6,6], [0,20,0], [15,20,28],chamfer=false) >>> { >>> cylinder(d=1,center=true,$fn=64); >>> cube(center=true); >>> } >>> >>> [image: image.png] >>> >>> >>> On Tue, Feb 14, 2023 at 10:15 AM Daniel Harvey <dwaharvey@gmail.com> >>> wrote: >>> >>>> There's the obvious limitation that if the area of intersection has >>>> native curvature then the fillet will pull away from the part (because >>>> hull() { object1() } != object1() in that area). So if eg object1() had a >>>> wave pattern, like some corrugated decking material... the result would not >>>> be good. >>>> On a case by case basis this sort of thing could probably be dealt with >>>> by iterating over another parameter, and intersecting with a third >>>> parametric object that creates small interpolations of the negative curve. >>>> But I am not sure how this will affect the computation time (geometric >>>> increase in calls to hull(), though each call on a much smaller object). >>>> >>>> On Tue, Feb 14, 2023 at 5:20 AM Sanjeev Prabhakar < >>>> sprabhakar2006@gmail.com> wrote: >>>> >>>>> It looks great, although not gone in detail. >>>>> Does it work for all type of solid to solid intersections? >>>>> >>>>> On Tue, 14 Feb, 2023, 9:58 am Daniel Harvey, <dwaharvey@gmail.com> >>>>> wrote: >>>>> >>>>>> Hello, >>>>>> It's possible that I have re-invented the wheel here, but I thought I >>>>>> would share a simple solution I came up with to create fillets for the >>>>>> intersection of two objects. It requires the objects to be defined with a >>>>>> parametric size-offset, and it uses an iterative approach with hull() to >>>>>> create a fillet. Here's an example with a cuboid (box()) embedded in a >>>>>> cylinder (shaft()). >>>>>> >>>>>> module shaft(dd=0) { >>>>>> rotate([0,0,-10]) rotate([0,90,0]) cylinder(d=22+dd, h=100, >>>>>> $fn=60, center=true); >>>>>> } >>>>>> >>>>>> module box(dd=0) { >>>>>> translate([0,5,5]) cube([15+dd,18+dd,25+dd], center=true); >>>>>> } >>>>>> >>>>>> module filletSlice(ro, ang) { >>>>>> p = ro * [(1-cos(ang)), (1-sin(ang))]; >>>>>> intersection() { >>>>>> shaft(p.x); >>>>>> box(p.y); >>>>>> } >>>>>> } >>>>>> >>>>>> da = 10; >>>>>> for (a=[0:da:90-da]) { >>>>>> hull() { >>>>>> filletSlice(2, a); >>>>>> filletSlice(2, a+da); >>>>>> } >>>>>> } >>>>>> shaft(); >>>>>> box(); >>>>>> >>>>>> _______________________________________________ >>>>>> 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 >>> >> _______________________________________________ >> 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, Feb 15, 2023 3:38 AM

It is possible to get intersection points if you create objects (or solid)
with defined points list rather than openscad primitives like cylinders and
cubes.

It is slightly complicated to work that way initially but soon it becomes
natural.

For intersection you need simply a method to calculate intersection point
between a plane (maybe an enclosed section lying in a plane) and a line in
3d space. This is possible in openscad.

I shifted to python as it is a little simpler to do geometric calculations,
but I think everything can be done in openscad as well.

On Wed, 15 Feb, 2023, 8:04 am Daniel Harvey, dwaharvey@gmail.com wrote:

Sanjay, I agree with you, and getting a list of the intersection points
was what I was originally thinking about, but I'm not aware of any OpenSCAD
way to obtain that information. I imagine in a python notebook one could do
it (?), but I am doing everything in OpenSCAD directly and was looking for
a good/simple way to get this done.

On Tue, Feb 14, 2023 at 6:50 PM Sanjeev Prabhakar <
sprabhakar2006@gmail.com> wrote:

If the points of intersection between the 2 solids can be found then
creating fillet would be possible.
3 list of intersection points would be required
a. both the solids at their original dimensions
b.1st solid at original dimension and 2nd solid at offset = the fillet
radius (approximate)
c.1st solid at offset= the fillet radius and 2nd solid at original
dimension

with the above 3 list of points
group the points e.g. first point of each list and create a fillet arc
and so on

finally create a polyheadron with all the fillet arcs

this works in most of the cases

On Wed, 15 Feb 2023, 03:32 Adrian Mariano, avm4@cornell.edu wrote:

Daniel, I think what you really mean is that if the object is not convex
in the area around the intersection then you're in trouble.  There's no
good solution to this problem.  The hull() operation is called CONVEX hull
for a reason.  But I think this is an interesting approach, and I, at
least, have not seen it before.  (And I'm really interested in rounding.)

I wrote a version that assumes you have two children at unit scale and
uses scale() to make the joined object.  That doesn't require having a
parametrized module for each object, though it's limited in other ways.
With BOSL2 it would be natural to combine at least the translate and rotate
operators into a single matrix that you pass in.  I also added a chamfer
option.  (Note that there's no way to avoid the code duplication because
you can't pass children separately to a submodule.)

// Invoke with 2 children that are at unit scale and create a
// fillet joint between them, while applying specified transformations.
//
// r = radius of fillet (relative to scale of children)
// T0,R0,S0 = translation, rotation and scaling for object 0
// T1,R1,S1 = translation, rotation and scaling for object 1
// steps = number of steps in fillet
// chamfer = set true to get chamfer instead of rounding

module fillet_join(r, T0,R0,S0, T1,R1,S1, steps=10, chamfer=false)
{
assert($children==2);
da=1/steps;
for(a=[0:da:1-da/2]){
hull() {
first_offset = chamfer ? r * [a,1-a]
: r * [1-cos(90a), 1-sin(90a)];
first_scale0 = [for(s=S0) first_offset[0]+s];
first_scale1 = [for(s=S1) first_offset[1]+s];
second_offset = chamfer ? r * [a+da, 1-a-da]
: r * [1-cos(90*(a+da)),
1-sin(90*(a+da))];
second_scale0 = [for(s=S0) second_offset[0]+s];
second_scale1 = [for(s=S1) second_offset[1]+s];
intersection(){
translate(T0)rotate(R0)scale(first_scale0) children(0);
translate(T1)rotate(R1)scale(first_scale1) children(1);
}
intersection(){
translate(T0)rotate(R0)scale(second_scale0) children(0);
translate(T1)rotate(R1)scale(second_scale1) children(1);
}
}
}
translate(T0)rotate(R0)scale(S0) children(0);
translate(T1)rotate(R1)scale(S1) children(1);
}

fillet_join(3,[0,0,3], [0,90,-10], [22,22,100],
[0,6,6], [0,20,0], [15,20,28],chamfer=false)
{
cylinder(d=1,center=true,$fn=64);
cube(center=true);
}

[image: image.png]

On Tue, Feb 14, 2023 at 10:15 AM Daniel Harvey dwaharvey@gmail.com
wrote:

There's the obvious limitation that if the area of intersection has
native curvature then the fillet will pull away from the part (because
hull() { object1() } != object1() in that area). So if eg object1() had a
wave pattern, like some corrugated decking material... the result would not
be good.
On a case by case basis this sort of thing could probably be dealt with
by iterating over another parameter, and intersecting with a third
parametric object that creates small interpolations of the negative curve.
But I am not sure how this will affect the computation time (geometric
increase in calls to hull(), though each call on a much smaller object).

On Tue, Feb 14, 2023 at 5:20 AM Sanjeev Prabhakar <
sprabhakar2006@gmail.com> wrote:

It looks great, although not gone in detail.
Does it work for all type of solid to solid intersections?

On Tue, 14 Feb, 2023, 9:58 am Daniel Harvey, dwaharvey@gmail.com
wrote:

Hello,
It's possible that I have re-invented the wheel here, but I thought I
would share a simple solution I came up with to create fillets for the
intersection of two objects. It requires the objects to be defined with a
parametric size-offset, and it uses an iterative approach with hull() to
create a fillet. Here's an example with a cuboid (box()) embedded in a
cylinder (shaft()).

module shaft(dd=0) {
rotate([0,0,-10]) rotate([0,90,0]) cylinder(d=22+dd, h=100,
$fn=60, center=true);
}

module box(dd=0) {
translate([0,5,5]) cube([15+dd,18+dd,25+dd], center=true);
}

module filletSlice(ro, ang) {
p = ro * [(1-cos(ang)), (1-sin(ang))];
intersection() {
shaft(p.x);
box(p.y);
}
}

da = 10;
for (a=[0:da:90-da]) {
hull() {
filletSlice(2, a);
filletSlice(2, a+da);
}
}
shaft();
box();


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


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

It is possible to get intersection points if you create objects (or solid) with defined points list rather than openscad primitives like cylinders and cubes. It is slightly complicated to work that way initially but soon it becomes natural. For intersection you need simply a method to calculate intersection point between a plane (maybe an enclosed section lying in a plane) and a line in 3d space. This is possible in openscad. I shifted to python as it is a little simpler to do geometric calculations, but I think everything can be done in openscad as well. On Wed, 15 Feb, 2023, 8:04 am Daniel Harvey, <dwaharvey@gmail.com> wrote: > Sanjay, I agree with you, and getting a list of the intersection points > was what I was originally thinking about, but I'm not aware of any OpenSCAD > way to obtain that information. I imagine in a python notebook one could do > it (?), but I am doing everything in OpenSCAD directly and was looking for > a good/simple way to get this done. > > On Tue, Feb 14, 2023 at 6:50 PM Sanjeev Prabhakar < > sprabhakar2006@gmail.com> wrote: > >> If the points of intersection between the 2 solids can be found then >> creating fillet would be possible. >> 3 list of intersection points would be required >> a. both the solids at their original dimensions >> b.1st solid at original dimension and 2nd solid at offset = the fillet >> radius (approximate) >> c.1st solid at offset= the fillet radius and 2nd solid at original >> dimension >> >> with the above 3 list of points >> group the points e.g. first point of each list and create a fillet arc >> and so on >> >> finally create a polyheadron with all the fillet arcs >> >> this works in most of the cases >> >> On Wed, 15 Feb 2023, 03:32 Adrian Mariano, <avm4@cornell.edu> wrote: >> >>> Daniel, I think what you really mean is that if the object is not convex >>> in the area around the intersection then you're in trouble. There's no >>> good solution to this problem. The hull() operation is called CONVEX hull >>> for a reason. But I think this is an interesting approach, and I, at >>> least, have not seen it before. (And I'm really interested in rounding.) >>> >>> I wrote a version that assumes you have two children at unit scale and >>> uses scale() to make the joined object. That doesn't require having a >>> parametrized module for each object, though it's limited in other ways. >>> With BOSL2 it would be natural to combine at least the translate and rotate >>> operators into a single matrix that you pass in. I also added a chamfer >>> option. (Note that there's no way to avoid the code duplication because >>> you can't pass children separately to a submodule.) >>> >>> // Invoke with 2 children that are at unit scale and create a >>> // fillet joint between them, while applying specified transformations. >>> // >>> // r = radius of fillet (relative to scale of children) >>> // T0,R0,S0 = translation, rotation and scaling for object 0 >>> // T1,R1,S1 = translation, rotation and scaling for object 1 >>> // steps = number of steps in fillet >>> // chamfer = set true to get chamfer instead of rounding >>> >>> module fillet_join(r, T0,R0,S0, T1,R1,S1, steps=10, chamfer=false) >>> { >>> assert($children==2); >>> da=1/steps; >>> for(a=[0:da:1-da/2]){ >>> hull() { >>> first_offset = chamfer ? r * [a,1-a] >>> : r * [1-cos(90*a), 1-sin(90*a)]; >>> first_scale0 = [for(s=S0) first_offset[0]+s]; >>> first_scale1 = [for(s=S1) first_offset[1]+s]; >>> second_offset = chamfer ? r * [a+da, 1-a-da] >>> : r * [1-cos(90*(a+da)), >>> 1-sin(90*(a+da))]; >>> second_scale0 = [for(s=S0) second_offset[0]+s]; >>> second_scale1 = [for(s=S1) second_offset[1]+s]; >>> intersection(){ >>> translate(T0)rotate(R0)scale(first_scale0) children(0); >>> translate(T1)rotate(R1)scale(first_scale1) children(1); >>> } >>> intersection(){ >>> translate(T0)rotate(R0)scale(second_scale0) children(0); >>> translate(T1)rotate(R1)scale(second_scale1) children(1); >>> } >>> } >>> } >>> translate(T0)rotate(R0)scale(S0) children(0); >>> translate(T1)rotate(R1)scale(S1) children(1); >>> } >>> >>> >>> fillet_join(3,[0,0,3], [0,90,-10], [22,22,100], >>> [0,6,6], [0,20,0], [15,20,28],chamfer=false) >>> { >>> cylinder(d=1,center=true,$fn=64); >>> cube(center=true); >>> } >>> >>> [image: image.png] >>> >>> >>> On Tue, Feb 14, 2023 at 10:15 AM Daniel Harvey <dwaharvey@gmail.com> >>> wrote: >>> >>>> There's the obvious limitation that if the area of intersection has >>>> native curvature then the fillet will pull away from the part (because >>>> hull() { object1() } != object1() in that area). So if eg object1() had a >>>> wave pattern, like some corrugated decking material... the result would not >>>> be good. >>>> On a case by case basis this sort of thing could probably be dealt with >>>> by iterating over another parameter, and intersecting with a third >>>> parametric object that creates small interpolations of the negative curve. >>>> But I am not sure how this will affect the computation time (geometric >>>> increase in calls to hull(), though each call on a much smaller object). >>>> >>>> On Tue, Feb 14, 2023 at 5:20 AM Sanjeev Prabhakar < >>>> sprabhakar2006@gmail.com> wrote: >>>> >>>>> It looks great, although not gone in detail. >>>>> Does it work for all type of solid to solid intersections? >>>>> >>>>> On Tue, 14 Feb, 2023, 9:58 am Daniel Harvey, <dwaharvey@gmail.com> >>>>> wrote: >>>>> >>>>>> Hello, >>>>>> It's possible that I have re-invented the wheel here, but I thought I >>>>>> would share a simple solution I came up with to create fillets for the >>>>>> intersection of two objects. It requires the objects to be defined with a >>>>>> parametric size-offset, and it uses an iterative approach with hull() to >>>>>> create a fillet. Here's an example with a cuboid (box()) embedded in a >>>>>> cylinder (shaft()). >>>>>> >>>>>> module shaft(dd=0) { >>>>>> rotate([0,0,-10]) rotate([0,90,0]) cylinder(d=22+dd, h=100, >>>>>> $fn=60, center=true); >>>>>> } >>>>>> >>>>>> module box(dd=0) { >>>>>> translate([0,5,5]) cube([15+dd,18+dd,25+dd], center=true); >>>>>> } >>>>>> >>>>>> module filletSlice(ro, ang) { >>>>>> p = ro * [(1-cos(ang)), (1-sin(ang))]; >>>>>> intersection() { >>>>>> shaft(p.x); >>>>>> box(p.y); >>>>>> } >>>>>> } >>>>>> >>>>>> da = 10; >>>>>> for (a=[0:da:90-da]) { >>>>>> hull() { >>>>>> filletSlice(2, a); >>>>>> filletSlice(2, a+da); >>>>>> } >>>>>> } >>>>>> shaft(); >>>>>> box(); >>>>>> >>>>>> _______________________________________________ >>>>>> 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 >>> >> _______________________________________________ >> 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 >
JB
Jordan Brown
Wed, Feb 15, 2023 8:19 AM

On 2/14/2023 6:31 PM, Daniel Harvey wrote:

It is a pity that OpenSCAD doesn't allow you to pass one module
definition as an argument to another, as Python does - and I was
grasping for.

Excuse me for a moment while I get pedantic.  People often get confused
about what "module" means, and especially with the upcoming work in
PR#4478 https://github.com/openscad/openscad/pull/4478 it's important
to keep the concepts straight.

Modules are executable subprograms.  They might happen to always produce
the same output, but they may not.  "cube" is a module - sometimes it
produces 1x1x1 cubes, sometimes 10x10x10, and sometimes 9x4x1.

Geometric objects (still looking for a good phrase there) are the
results of executing modules.  Once you have executed cube(1), the
result is a 1x1 cube (in the current coordinate system) and nothing will
ever change that.

By way of analogy, consider this function:

function five() = 5;

This function will always return the number 5, but it is not the number
5 - it is an executable subprogram that happens to always yield the same
result.


Today's OpenSCAD does have one form for passing something in this area -
the "child" mechanism:

rotate(45) cube(10);

That looks like it's passing a geometric object to rotate, but really
it's not - it's passing something that's more like a parameter-less
module.  This is most easily seen with modules that invoke their
children more than once:

module dup(dx) {
    children();
    translate([dx,0,0]) children();
}

If you invoke this with a simple child, it could be working on geometric
objects:

dup(5) cube(2);

does the obvious thing.

But what do these do?

dup(5) echo("hello");
dup(5) cube(rands(1,3,1)[0]);

The "passing a geometric object" model would say that the first would
echo "hello", while the second would generate a random-sized cube, and
then duplicate it... but that's not what happens.  Instead, each
invocation of "children()" causes the children to be evaluated, so what
you get are two echos of "hello" and two independently random cubes.

The same is true if you set $ variables in the parent module; the child
can receive them and take action based on them.

The children may not be evaluated at all...

module maybe(bool) {
    if (bool) children();
}

maybe(false) echo("you never see this");

4478 includes several mechanisms offering more features for both kinds
of constructs, and it becomes even more important to keep them straight.

4478 lets you use geometric objects as data values:

c = {{ cube(rands(1,3,1)[0]); }}      // Maybe not final syntax.

and then because it's just a data value, you can put it in an array,
pass it as a parameter, return it from a function, and so on.

You can later add it to the model:

c;

Note that that geometric value gets evaluated once, so "c" represents
some one random-sized cube.  No matter how many times you add it to the
model, it's always the same size.  (In the current coordinate system, of
course.)

4478 also lets you use modules as data values (as you can with functions
today):

m = module () { cube(rands(1,3,1)[0]); };

Again, this "module reference" is a data value.  You can put it in an
array, pass it as a parameter, et cetera.  At some later point you can
invoke it and add the resulting geometry to the model:

m();

But it's a module.  Until you invoke it, it isn't geometry.  Each time
you invoke it, it gets evaluated and produces whatever geometry it
produces.  Here, each time you invoke it you get a random-sized cube,
and two invocations will yield different results.

I hope that makes the distinction a little clearer, and makes it clear
why I want people to understand the distinction.

On 2/14/2023 6:31 PM, Daniel Harvey wrote: > It is a pity that OpenSCAD doesn't allow you to pass one module > definition as an argument to another, as Python does - and I was > grasping for. Excuse me for a moment while I get pedantic.  People often get confused about what "module" means, and especially with the upcoming work in PR#4478 <https://github.com/openscad/openscad/pull/4478> it's important to keep the concepts straight. Modules are executable subprograms.  They might happen to always produce the same output, but they may not.  "cube" is a module - sometimes it produces 1x1x1 cubes, sometimes 10x10x10, and sometimes 9x4x1. Geometric objects (still looking for a good phrase there) are the *results* of executing modules.  Once you have executed cube(1), the result is a 1x1 cube (in the current coordinate system) and nothing will ever change that. By way of analogy, consider this function: function five() = 5; This function will always return the number 5, but it is not the number 5 - it is an executable subprogram that happens to always yield the same result. ------------------------------------------------------------------------ Today's OpenSCAD does have one form for passing something in this area - the "child" mechanism: rotate(45) cube(10); That looks like it's passing a geometric object to rotate, but really it's not - it's passing something that's more like a parameter-less module.  This is most easily seen with modules that invoke their children more than once: module dup(dx) { children(); translate([dx,0,0]) children(); } If you invoke this with a simple child, it could be working on geometric objects: dup(5) cube(2); does the obvious thing. But what do these do? dup(5) echo("hello"); dup(5) cube(rands(1,3,1)[0]); The "passing a geometric object" model would say that the first would echo "hello", while the second would generate a random-sized cube, and then duplicate it... but that's not what happens.  Instead, each invocation of "children()" causes the children to be evaluated, so what you get are two echos of "hello" and two independently random cubes. The same is true if you set $ variables in the parent module; the child can receive them and take action based on them. The children may not be evaluated at all... module maybe(bool) { if (bool) children(); } maybe(false) echo("you never see this"); ------------------------------------------------------------------------ 4478 includes several mechanisms offering more features for both kinds of constructs, and it becomes even more important to keep them straight. 4478 lets you use geometric objects as data values: c = {{ cube(rands(1,3,1)[0]); }} // Maybe not final syntax. and then because it's just a data value, you can put it in an array, pass it as a parameter, return it from a function, and so on. You can later add it to the model: c; Note that that geometric value gets evaluated *once*, so "c" represents some one random-sized cube.  No matter how many times you add it to the model, it's always the same size.  (In the current coordinate system, of course.) 4478 also lets you use modules as data values (as you can with functions today): m = module () { cube(rands(1,3,1)[0]); }; Again, this "module reference" is a data value.  You can put it in an array, pass it as a parameter, et cetera.  At some later point you can invoke it and add the resulting geometry to the model: m(); But it's a module.  Until you invoke it, it isn't geometry.  *Each* time you invoke it, it gets evaluated and produces whatever geometry it produces.  Here, each time you invoke it you get a random-sized cube, and two invocations will yield different results. I hope that makes the distinction a little clearer, and makes it clear why I want people to understand the distinction.