discuss@lists.openscad.org

OpenSCAD general discussion Mailing-list

View all threads

sweep in BOSL2

L
larry
Fri, Sep 26, 2025 4:35 PM

On Fri, 2025-09-26 at 18:02 +0200, Peter Kriens via Discuss wrote:

Larry> What is a VNF

It is shape data. It allows you to calculate any shape once and then
use it multiple times. In this case the rounded_prism() is cut in
half, the profile created, and then attached at both ends.
vnf_polyhedron() is the module that displays it. Modules, however,
don't allow you to make a path that crosscut a shape. When you have a
vnf, you can do this since the vnf is just data. When you pass it to
projection() it gives you a 2d path, also as data. This path can then
be used in the path_sweep as profile. 

I understand about half (or less) of that. I will look into it some
more.

This is for me so powerful with BOSL2, it (almost) all works
together. And when you find stuff that doesn't work together they
tend to fix it quickly.

I tried to write this example code as clear as possible. So please
take a look. Now with the attach working, I think it is a great
example of the powers of BOSL2.

Adrian, man! You're brilliant!

include <BOSL2/std.scad>
include <BOSL2/rounding.scad>

aclip();

module aclip(
    r           = 100,              // mm spool radius
    clip_span   =  25,              // degree span on radius
    clip_h      =   6,              // height of the clip
    cap_bot     = [20,12],          // cap end bottom
    cap_top     = [6,6],            // cap end top
    cap_rounding=   2,              // cap rounding
) {

    cap = rounded_prism( 
        rect(cap_bot),
        rect(cap_top), 
        h           = clip_h,
        joint_sides = cap_rounding, 
        joint_top   = cap_rounding,
        joint_bot   = 0,
        k           = 0.9, // sorry Adrian
    );
        
    crosscut    = projection( yrot(90,cap), true ); // region
    path        = zrot(90, crosscut[0]);
    sweep       = turtle( [ 
            "arcleft", r, clip_span,
            
    ]);

    vnf_polyhedron( left_half( cap ))
    attach(RIGHT,"start-centroid")
    path_sweep( path, sweep )
    attach("end-centroid", LEFT)
    vnf_polyhedron( right_half( cap ) )
    ;
}

PastedGraphic-1.png

Interestingly you can now do the capping with any sweep path you
want:

PastedGraphic-6.png

The attach model should get the 3D nobel price ... :-)

Thanks!
Peter

On 26 Sep 2025, at 17:16, Adrian Mariano avm4@cornell.edu wrote:

You can get the attachment version to work by using “start-
centroid” and “end-centroid” for the anchors of the sweep. 

There may be a problem with vnf anchors. 

What is a vnf?  BOSL2 can’t work on 2d geometry because it can’t
access the point data. Instead you have to use a point list which
we call a path. The vnf is the 3d version of this.  For Peter’s
example that’s all you need to know. Internally it’s the vertices
‘n’ faces that you would pass to polyhedron() in native openscad to
create the shape. 

On Fri, Sep 26, 2025 at 09:19 Peter Kriens via Discuss
discuss@lists.openscad.org wrote:

One of the great things about BOSL2 I find that I very rarely
have to go to the trigonometry aspects. I can do it but it always
hurts my brain and need more coffee. Even more important, the
code tends to be very brittle for changes.

My favorite shape is rounded_prism, and when I look at your clip
I immediately see half a rounded_prism in the capped ends.
Logically I see it is a rounded_prism cut in half and then a
sweep of the crosscut inserted.

Since you can turn the rounded_prism into a vnf, you can use
projection() to get a crosscut profile of the middle, which
profile is then ideal to create the sweep. 

So I came up with this:

include <BOSL2/std.scad>
include <BOSL2/rounding.scad>

$fn = $preview ? 60 : 100;

module clip(
    r           = 100,              // mm spool radius
    clip_span   =  40,              // degree span on radius
    clip_h      =   6,              // height of the clip
    cap_bot     = [20,12],          // cap end bottom
    cap_top     = [6,6],            // cap end top
    cap_rounding=   2,              // cap rounding
    filament_r  = (1.75 + 0.05)/2,  // torus for the filament
    filament_shift=0.5,             // z-shift for torus to
make it 'clip'
) {

    cap = rounded_prism( 
        rect(cap_bot),
        rect(cap_top), 
        h           = clip_h, 
        joint_sides = cap_rounding, 
        joint_top   = cap_rounding,
        joint_bot   = 0,
        k           = 0.9 // sorry Adrian
    );
        
    crosscut    = projection( yrot(90,cap), true ); // region
    profile     = zrot(90, crosscut[0]);
    sweep       = turtle( [ 
            "arcleft", r, clip_span
            
    ]);
    end_of_sweep = point3d( sweep[ len(sweep)-1 ],0);

    difference() {
    
        vnf_polyhedron( left_half( cap ))
        path_sweep( profile, sweep )
        translate( end_of_sweep ) 
        zrot( clip_span ) 
        vnf_polyhedron( right_half( cap ) )
        ;
        
        // remove the filament torus
        up( clip_h/2 - filament_shift) 
        ymove(r)  // center of spool
        torus( or = r+filament_r, ir=r-filament_r ) 
        ;
    }
}

clip();

<PastedGraphic-1.png>

I was slightly disappointed since I started with attachments,
which was arguably simpler:

module clip(
    r           = 100,              // mm spool radius
    clip_span   =  25,              // degree span on radius
    clip_h      =   6,              // height of the clip
    cap_bot     = [20,12],          // cap end bottom
    cap_top     = [6,6],            // cap end top
    cap_rounding=   2,              // cap rounding
) {

    cap = rounded_prism( 
        rect(cap_bot),
        rect(cap_top), 
        h           = clip_h,
        joint_sides = cap_rounding, 
        joint_top   = cap_rounding,
        joint_bot   = 0,
        k           = 0.9, // sorry Adrian
    );
        
    crosscut    = projection( yrot(90,cap), true ); // ->
region
    profile     = zrot(90, crosscut[0]); // -> 2D path
    sweep       = turtle( [ 
            "arcleft", r, clip_span 
    ]);

    vnf_polyhedron( left_half( cap ) )
    attach(RIGHT,"start")
    path_sweep( profile, sweep )
    attach("end", LEFT)
    vnf_polyhedron( right_half( cap ) )
    ;
}

Unfortunately, the sweep did not properly attach to the
rounded_prism vnf :-( The anchors are not properly aligned. Maybe
Adrian can shed some light on this?

<PastedGraphic-2.png>

    Peter

On 24 Sep 2025, at 06:32, larry via Discuss
discuss@lists.openscad.org wrote:

On Sun, 2025-09-21 at 19:00 -0600, larry via Discuss wrote:

include <BOSL2/std.scad>
$fn= $preview ? 60 : 360;

spool_rad=100;
holeposition_rad=spool_rad-6;
hole_dia=6;
hole_hole_dist_max=33.9;
hole_hole_dist_min=21.9;

difference() {
union() {
rotate_extrude(angle=30) profile();
right(holeposition_rad) up(1.5) end_cap();;
zrot(30) right(holeposition_rad) up(1.5)
end_cap();
}
up(2.5)filament_slot();
}

Well, here I am again, with a puzzler (for me it's a puzzle).

I have come pretty far along in my code, but one bit of it I
arrived at
by trial and error. I found the rotation angle I needed for the
pins by
rendering the object and using the measurement tool to arrive
at the
right distance.

I never did take any trig in my schooling, so anything
requiring it has
to be either looking up how to do it or trial and error.

So, In the code, I use a rotation angle of 24.66 in the xrot
statement.
I do want to make this parametric, so I figured I'd use trig.

I have the three lengths of the triangle and want to find angle
A.
I tried the BOSL2 law_of_cosines() and I'm getting results that
are
nowhere near 24.66. Here's a snippet I tried:

!get_ang();

module get_ang() {
ang = law_of_cosines(a=27.9,b=96,c=96);
echo (ang);
}

This outputs ECHO: 81.6446

Any explanation gratefully received.

L


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

On Fri, 2025-09-26 at 18:02 +0200, Peter Kriens via Discuss wrote: > Larry> What is a VNF > > It is shape data. It allows you to calculate any shape once and then > use it multiple times. In this case the rounded_prism() is cut in > half, the profile created, and then attached at both ends. > vnf_polyhedron() is the module that displays it. Modules, however, > don't allow you to make a path that crosscut a shape. When you have a > vnf, you can do this since the vnf is just data. When you pass it to > projection() it gives you a 2d path, also as data. This path can then > be used in the path_sweep as profile.  I understand about half (or less) of that. I will look into it some more. > This is for me so powerful with BOSL2, it (almost) all works > together. And when you find stuff that doesn't work together they > tend to fix it quickly. > > I tried to write this example code as clear as possible. So please > take a look. Now with the attach working, I think it is a great > example of the powers of BOSL2. > > > > Adrian, man! You're brilliant! > > > include <BOSL2/std.scad> > > include <BOSL2/rounding.scad> > > > > aclip(); > > > module aclip( > >     r           = 100,              // mm spool radius > >     clip_span   =  25,              // degree span on radius > >     clip_h      =   6,              // height of the clip > >     cap_bot     = [20,12],          // cap end bottom > >     cap_top     = [6,6],            // cap end top > >     cap_rounding=   2,              // cap rounding > > ) { > > > >     cap = rounded_prism(  > >         rect(cap_bot), > >         rect(cap_top),  > >         h           = clip_h, > >         joint_sides = cap_rounding,  > >         joint_top   = cap_rounding, > >         joint_bot   = 0, > >         k           = 0.9, // sorry Adrian > >     ); > >          > >     crosscut    = projection( yrot(90,cap), true ); // region > >     path        = zrot(90, crosscut[0]); > >     sweep       = turtle( [  > >             "arcleft", r, clip_span, > >              > >     ]); > > > >     vnf_polyhedron( left_half( cap )) > >     attach(RIGHT,"start-centroid") > >     path_sweep( path, sweep ) > >     attach("end-centroid", LEFT) > >     vnf_polyhedron( right_half( cap ) ) > >     ; > > } > > PastedGraphic-1.png > > > Interestingly you can now do the capping with any sweep path you > want: > > > PastedGraphic-6.png > > The attach model should get the 3D nobel price ... :-) > > Thanks! > Peter > > > > > > On 26 Sep 2025, at 17:16, Adrian Mariano <avm4@cornell.edu> wrote: > > > > You can get the attachment version to work by using “start- > > centroid” and “end-centroid” for the anchors of the sweep.  > > > > There may be a problem with vnf anchors.  > > > > What is a vnf?  BOSL2 can’t work on 2d geometry because it can’t > > access the point data. Instead you have to use a point list which > > we call a path. The vnf is the 3d version of this.  For Peter’s > > example that’s all you need to know. Internally it’s the vertices > > ‘n’ faces that you would pass to polyhedron() in native openscad to > > create the shape.  > > > > On Fri, Sep 26, 2025 at 09:19 Peter Kriens via Discuss > > <discuss@lists.openscad.org> wrote: > > > One of the great things about BOSL2 I find that I very rarely > > > have to go to the trigonometry aspects. I can do it but it always > > > hurts my brain and need more coffee. Even more important, the > > > code tends to be very brittle for changes. > > > > > > My favorite shape is rounded_prism, and when I look at your clip > > > I immediately see half a rounded_prism in the capped ends. > > > Logically I see it is a rounded_prism cut in half and then a > > > sweep of the crosscut inserted. > > > > > > Since you can turn the rounded_prism into a vnf, you can use > > > projection() to get a crosscut profile of the middle, which > > > profile is then ideal to create the sweep.  > > > > > > So I came up with this: > > > > > > > > > > > > > > include <BOSL2/std.scad> > > > > include <BOSL2/rounding.scad> > > > > > > > > $fn = $preview ? 60 : 100; > > > > > > > > > > > > module clip( > > > >     r           = 100,              // mm spool radius > > > >     clip_span   =  40,              // degree span on radius > > > >     clip_h      =   6,              // height of the clip > > > >     cap_bot     = [20,12],          // cap end bottom > > > >     cap_top     = [6,6],            // cap end top > > > >     cap_rounding=   2,              // cap rounding > > > >     filament_r  = (1.75 + 0.05)/2,  // torus for the filament > > > >     filament_shift=0.5,             // z-shift for torus to > > > > make it 'clip' > > > > ) { > > > > > > > >     cap = rounded_prism(  > > > >         rect(cap_bot), > > > >         rect(cap_top),  > > > >         h           = clip_h,  > > > >         joint_sides = cap_rounding,  > > > >         joint_top   = cap_rounding, > > > >         joint_bot   = 0, > > > >         k           = 0.9 // sorry Adrian > > > >     ); > > > >          > > > >     crosscut    = projection( yrot(90,cap), true ); // region > > > >     profile     = zrot(90, crosscut[0]); > > > >     sweep       = turtle( [  > > > >             "arcleft", r, clip_span > > > >              > > > >     ]); > > > >     end_of_sweep = point3d( sweep[ len(sweep)-1 ],0); > > > > > > > >     difference() { > > > >      > > > >         vnf_polyhedron( left_half( cap )) > > > >         path_sweep( profile, sweep ) > > > >         translate( end_of_sweep )  > > > >         zrot( clip_span )  > > > >         vnf_polyhedron( right_half( cap ) ) > > > >         ; > > > >          > > > >         // remove the filament torus > > > >         up( clip_h/2 - filament_shift)  > > > >         ymove(r)  // center of spool > > > >         torus( or = r+filament_r, ir=r-filament_r )  > > > >         ; > > > >     } > > > > } > > > > > > > > clip(); > > > > > > > > > > <PastedGraphic-1.png> > > > > > > I was slightly disappointed since I started with attachments, > > > which was arguably simpler: > > > > > > > module clip( > > > >     r           = 100,              // mm spool radius > > > >     clip_span   =  25,              // degree span on radius > > > >     clip_h      =   6,              // height of the clip > > > >     cap_bot     = [20,12],          // cap end bottom > > > >     cap_top     = [6,6],            // cap end top > > > >     cap_rounding=   2,              // cap rounding > > > > ) { > > > > > > > >     cap = rounded_prism(  > > > >         rect(cap_bot), > > > >         rect(cap_top),  > > > >         h           = clip_h, > > > >         joint_sides = cap_rounding,  > > > >         joint_top   = cap_rounding, > > > >         joint_bot   = 0, > > > >         k           = 0.9, // sorry Adrian > > > >     ); > > > >          > > > >     crosscut    = projection( yrot(90,cap), true ); // -> > > > > region > > > >     profile     = zrot(90, crosscut[0]); // -> 2D path > > > >     sweep       = turtle( [  > > > >             "arcleft", r, clip_span  > > > >     ]); > > > > > > > >     vnf_polyhedron( left_half( cap ) ) > > > >     attach(RIGHT,"start") > > > >     path_sweep( profile, sweep ) > > > >     attach("end", LEFT) > > > >     vnf_polyhedron( right_half( cap ) ) > > > >     ; > > > > } > > > > > > > > > Unfortunately, the sweep did not properly attach to the > > > rounded_prism vnf :-( The anchors are not properly aligned. Maybe > > > Adrian can shed some light on this? > > > > > > <PastedGraphic-2.png> > > > > > > > > >     Peter > > > > > > > > > > > > > On 24 Sep 2025, at 06:32, larry via Discuss > > > > <discuss@lists.openscad.org> wrote: > > > > > > > > On Sun, 2025-09-21 at 19:00 -0600, larry via Discuss wrote: > > > > > include <BOSL2/std.scad> > > > > > $fn= $preview ? 60 : 360; > > > > > > > > > > spool_rad=100; > > > > > holeposition_rad=spool_rad-6; > > > > > hole_dia=6; > > > > > hole_hole_dist_max=33.9; > > > > > hole_hole_dist_min=21.9; > > > > > > > > > > difference() { > > > > > union() { > > > > > rotate_extrude(angle=30) profile(); > > > > > right(holeposition_rad) up(1.5) end_cap();; > > > > > zrot(30) right(holeposition_rad) up(1.5) > > > > > end_cap(); > > > > > } > > > > > up(2.5)filament_slot(); > > > > > } > > > > > > > > Well, here I am again, with a puzzler (for me it's a puzzle). > > > > > > > > I have come pretty far along in my code, but one bit of it I > > > > arrived at > > > > by trial and error. I found the rotation angle I needed for the > > > > pins by > > > > rendering the object and using the measurement tool to arrive > > > > at the > > > > right distance. > > > > > > > > I never did take any trig in my schooling, so anything > > > > requiring it has > > > > to be either looking up how to do it or trial and error. > > > > > > > > So, In the code, I use a rotation angle of 24.66 in the xrot > > > > statement. > > > > I do want to make this parametric, so I figured I'd use trig. > > > > > > > > I have the three lengths of the triangle and want to find angle > > > > A. > > > > I tried the BOSL2 law_of_cosines() and I'm getting results that > > > > are > > > > nowhere near 24.66. Here's a snippet I tried: > > > > > > > > !get_ang(); > > > > > > > > module get_ang() { > > > > ang = law_of_cosines(a=27.9,b=96,c=96); > > > > echo (ang); > > > > } > > > > > > > > This outputs ECHO: 81.6446 > > > > > > > > Any explanation gratefully received. > > > > > > > > L > > > > _______________________________________________ > > > > 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