The projection() result would have to go to rotate_extrude and then it
wouldn't be so easy to put rounded caps in it. But it's trivial to
construct the path that is equal to that projection, as shown by this code
which makes the path and gives it to stroke() to draw the red outline:
include<BOSL2/std.scad>
$fn= $preview ? 60 : 180;
spool_rad=100;
holeposition_rad=spool_rad-6;
hole_dia=6;
hole_hole_dist_max=33.9;
hole_hole_dist_min=21.9;
module profile() {
projection()
//back(1.5) right(holeposition_rad)
xrot(-90)
cyl(h=3,d1=hole_dia*1.8,d2=hole_dia,rounding2=1);
stroke(trapezoid(h=3,w1=hole_dia*1.8,w2=hole_dia,rounding=[1,1,0,0]),width=.1,color="red",closed=true);
}
profile();
The output of trapezoid is a path that can go to rotate_sweep or path_sweep.
produces:
[image: image.png]
On Sun, Sep 21, 2025 at 7:00 PM Jordan Brown via Discuss <
discuss@lists.openscad.org> wrote:
On 9/21/2025 3:54 PM, larry via Discuss wrote:
projection() back(1.5) right(holeposition_rad) xrot(-90)
cyl(h=3,d1=hole_dia*1.8,d2=hole_dia,rounding2=1);
}
projection() produces actual OpenSCAD geometry. BOSL2's sweep functions
require lists of points.
You could rotate_extrude() or linear_extrude() that projection, but if you
really wanted a sweep along an arbitrary path then that won't help you.
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
On Sun, 2025-09-21 at 16:00 -0700, Jordan Brown wrote:
On 9/21/2025 3:54 PM, larry via Discuss wrote:
projection() back(1.5) right(holeposition_rad) xrot(-90)
cyl(h=3,d1=hole_dia*1.8,d2=hole_dia,rounding2=1);
}
projection() produces actual OpenSCAD geometry. BOSL2's sweep
functions require lists of points.
Ahh. OK.
You could rotate_extrude() or linear_extrude() that projection, but
if you really wanted a sweep along an arbitrary path then that won't
help you.
rotate_extrude worked!
Here's the code for the basic object. It previews in .167 seconds and
renders in 1.257 seconds.
Thanks Adrian!
//---
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();
}
module end_cap() {
cyl(h=3,d1=hole_dia*1.8,d2=hole_dia,rounding2=1);
}
module profile() {
projection() back(1.5) right(holeposition_rad) xrot(-90)
end_cap();
}
module filament_slot() {
rotate_extrude() right(holeposition_rad) circle(1.84/2);
}
//---
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
On 9/23/2025 9:32 PM, larry via Discuss wrote:
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.
Capsule summary of trig:
Given a right triangle with sides A, B, and C:
...
C ..... |
..... | B
..T |
--------------+
A
and calling the angle between A and C "T"...
The sine of an angle is the opposite side divided by the hypotenuse, or
in this case sin(T) is B/C.
The cosine of an angle is the adjacent side divided by the hypotenuse,
or in this case cos(T) is A/C.
The tangent of an angle is the opposite side divided by the adjacent
side, or in this case tan(T) is B/A.
"arc" just means "inverse"; the arc sine of a number is the angle that
has that sine, and so on.
And the Pythagorean Theorem is useful too: A² + B² = C².
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.
For those dimensions, I get an angle for the pointy end of 16.7° and the
two big angles being 81.6°. So that matches BOSL2's result.
I drew the triangle like so (not to scale):
^
/|\
/ |T\
96 / | \ 96
/ | \
/ | \
-----+-----
27.9
so that's two identical right triangles, each with the hypotenuse being
96 and one other side being 27.9/2.
Calling half of the top - the angle of the right triangle - T, sin(T) =
(27.9/2) / 96. So T is asin((27.9/2)/96), which is about 8.4°, That's
only half of the top, so all of the top is about 16.7°. The angles of a
triangle total to 180°, so the other two angles are each (180 - 16.7)/2,
which is about 81.6°. (I actually did the calculation with OpenSCAD and
the result was exactly the 81.6446° that you got.) Or you could more
directly calculate the big angle using cosine - its cosine is
(27.9/2)/96, and the arc cosine of that is again 81.6446.
Here's a quick OpenSCAD program that draws the triangle, assembling
sides with those dimensions at the angles calculated.
base = 27.9;
side = 96;
T = asin((base/2)/side);
theta = T*2;
a = (180-theta)/2;
echo(T, theta, a);
square([base, 1], center=true);
translate([-base/2, 0]) rotate(a-90) translate([-0.5,0]) square([1, side]);
translate([base/2, 0]) rotate(90-a) translate([-0.5,0]) square([1, side]);
So anyhow, I think something is wrong in either how you're looking at
the problem or in your measurements.
Note that the law of cosines function produces angle C, the angle opposite
side C, which is one of the large angles, not the pointy angle.
ang = law_of_cosines(c=27.9,b=96,a=96);
echo (ang);
displays 16.7.
On Wed, Sep 24, 2025 at 1:54 AM Jordan Brown via Discuss <
discuss@lists.openscad.org> wrote:
On 9/23/2025 9:32 PM, larry via Discuss wrote:
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.
Capsule summary of trig:
Given a right triangle with sides A, B, and C:
...
C ..... |
..... | B
..T |
--------------+
A
and calling the angle between A and C "T"...
The sine of an angle is the opposite side divided by the hypotenuse, or in
this case sin(T) is B/C.
The cosine of an angle is the adjacent side divided by the hypotenuse, or
in this case cos(T) is A/C.
The tangent of an angle is the opposite side divided by the adjacent side,
or in this case tan(T) is B/A.
"arc" just means "inverse"; the arc sine of a number is the angle that has
that sine, and so on.
And the Pythagorean Theorem is useful too: A² + B² = C².
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.
For those dimensions, I get an angle for the pointy end of 16.7° and the
two big angles being 81.6°. So that matches BOSL2's result.
I drew the triangle like so (not to scale):
^
/|\
/ |T\
96 / | \ 96
/ | \
/ | \
-----+-----
27.9
so that's two identical right triangles, each with the hypotenuse being 96
and one other side being 27.9/2.
Calling half of the top - the angle of the right triangle - T, sin(T) =
(27.9/2) / 96. So T is asin((27.9/2)/96), which is about 8.4°, That's
only half of the top, so all of the top is about 16.7°. The angles of a
triangle total to 180°, so the other two angles are each (180 - 16.7)/2,
which is about 81.6°. (I actually did the calculation with OpenSCAD and
the result was exactly the 81.6446° that you got.) Or you could more
directly calculate the big angle using cosine - its cosine is (27.9/2)/96,
and the arc cosine of that is again 81.6446.
Here's a quick OpenSCAD program that draws the triangle, assembling sides
with those dimensions at the angles calculated.
base = 27.9;
side = 96;
T = asin((base/2)/side);
theta = T*2;
a = (180-theta)/2;
echo(T, theta, a);
square([base, 1], center=true);
translate([-base/2, 0]) rotate(a-90) translate([-0.5,0]) square([1, side]);
translate([base/2, 0]) rotate(90-a) translate([-0.5,0]) square([1, side]);
So anyhow, I think something is wrong in either how you're looking at the
problem or in your measurements.
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
On Wed, 2025-09-24 at 06:23 -0400, Adrian Mariano via Discuss wrote:
Note that the law of cosines function produces angle C, the angle
opposite side C, which is one of the large angles, not the pointy
angle.
ang = law_of_cosines(c=27.9,b=96,a=96);
echo (ang);
displays 16.7.
That's exactly what I got when I used that same statement. It gives me
angle A (using the terminology in the BOSL2 description (attached) and
in three triangle calculators.
My problem was that I had been using 24.66, but I just figured out my
problem. Somehow I measured the hole spacing incorrectly, or perhaps I
calculated it badly, as I measured the hole distance with calipers,
using the inner and outer sides and subtracting the hole diameter.
So after tweaking it for better accuracy, my rotate_extrude is:
rotate_extrude(law_of_cosines(c=39.5,b=96,a=96)) profile();
Thank you for your patience, and please accept my apologies.
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();

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?

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
On Fri, 2025-09-26 at 15:18 +0200, Peter Kriens 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.
A rounded_prism is a great idea, and should produce a result as good as
or better than my rounded cone.
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.
I have never used a vnf and frankly, I have no idea what it is for what
it does. I made the profile by rotating the rounded cone and projecting
it, then used that to sweep.
I initially cut the cone in half, but then realized that there was no
need for it, and just put one where I made it and rotated a copy.
So here's my (almost) finished code for an Overture cardboard spool. I
say almost because I am still tweaking the cut for the filament channel
height to make it easy to snap the filament in but just enough to
ensure it will stay put until I pop it out.
I am seriously thinking I might not bother with the pins on the ends,
as it's quite easy to just super-glue the flat bottomed piece onto the
spool using a CA glue in a small bottle with a brush in the cap.
//----
include <BOSL2/std.scad>
include <BOSL2/math.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;
echo (law_of_cosines(c=40,b=96,a=96));
xrot(180) down(3) //uncomment for printable
difference() {
union() {
rotate_extrude(law_of_cosines(c=39.6,b=96,a=96))
profile();
right(holeposition_rad) up(1.5) end_cap();;
zrot(law_of_cosines(c=39.6,b=96,a=96))
right(holeposition_rad) up(1.5) end_cap();
right(holeposition_rad) pin();
zrot(law_of_cosines(c=39.6,b=96,a=96))
right(holeposition_rad) pin();
}
up(2.7)filament_slot();
}
module end_cap() {
}
module profile() {
projection() back(1.5) right(holeposition_rad) xrot(-90)
end_cap();
}
module filament_slot() {
rotate_extrude() right(holeposition_rad) circle(1.84/2);
}
module pin() {
difference() {
union() {
down(1.6) cyl(h=5,d=5.9);
down(3.9)torus(id=5.4,od=6.5);
}
down(3.6)cuboid([7,1,7]);
}
}
//----
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
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();
[image: 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?
[image: 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
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.
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 ) )
;
}

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

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 mailto: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 mailto: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 mailto:discuss-leave@lists.openscad.org
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org mailto:discuss-leave@lists.openscad.org