Here is my version of the model:
[image: Screenshot 2025-01-23 at 6.21.24 AM.png]
[image: Screenshot 2025-01-23 at 6.22.22 AM.png]
here is the python code:
sec=corner_radius(pts1([[0,0,.1],[20,0,.1],[0,20,.1],[-20,0,.1]]),5)
sol1=linear_extrude(sec,20)
sol2=o_solid([0,-1,0],circle(2.5),20,-5,-10,15,[0,30,0])
f1=cpo(ip_fillet(sol1,sol2,-2,2))[:-1]
sol2=f1+[sol2[1]]
sol21=surface_offset(sol2,.5)
sol2=swp_prism_h(sol2,sol21)
sol11=surface_offset(sol1,.49)
sol1=swp_prism_h(sol1,sol11)
with open('trial.scad','w+') as f:
f.write(f'''
include<dependencies2.scad>
// color("blue")p_line3d({sol2[1]},.2);
difference(){{
{swp_c(sol1)}
{swp(sol21)}
}}
{swp_c(sol2)}
''')
A bit of 'closure' on this question I asked last week. I tried to
understand and use the suggestions that were posted, and although I did get
some ideas from them, I couldn't quite wrap my head around them enough to
make them my own. But, in the end I've managed to produce pretty much
exactly what I wanted in plain OpenSCAD. I'm posting this more as an
encouragement to people like myself a week ago who are very intimidated by
making smooth objects in OpenSCAD, that it's absolutely possible, but may
require some different thinking, at least compared to how I myself approach
modeling other objects. I actually started out writing a pure Python
program that generated triangles and exported into Wavefront .obj format,
which is a very simple text-based 3d mesh format. (I say 'writing a pure
Python program', but actually Chatgpt wrote most of the hairy stuff). I got
the handle itself to work, then I wanted to add more functionality to
create the rest of the object I want to make, but that turned out to be
such a slog in Python, so I ported my approach from Python 1:1 to OpenSCAD.
That didn't work very well, it was essentially generating all the points
and faces to be passed to polyhedron(); but after a bit of refactoring (but
keeping the original approach) I got the attached more idiomatic OpenSCAD
version.
What it does is basically do the same steps I would do to model this object
manually in Blender. Create a list of points along a bezier curve, then
position a slightly linear_extrude()'ed polygon on each point of that
curve, rotating it to point towards the next point. Then for the 'flare' at
the base it applies a scale() to the relevant (i.e. first x) polygons,
using an exponentially decaying scaling factor. These polygons are combined
into a solid using hull() on each consecutive pair. For generating the
rounded object that forms the base of this handle, I also used hull() on a
bunch of spheres positioned at the extremes of the outline of the object.
All of this may be obvious to others; but although I do by now consider
myself an intermediate level OpenSCAD user, it still took me a radically
different way of thinking to get here. This whole process has been quite a
learning experience really, and I think it will make me consider doing
things in OpenSCAD in the future that just a week ago, I would think of as
too hard/not worth the effort.
A technical note is that I did have to use the preview builds of OpenSCAD,
as otherwise rendering this took minutes; in the preview build, less than
half a second.
And another side remark is that Chatgpt can actually be quite competent at
writing OpenSCAD code, as long as you create a custom GPT and upload the
OpenSCAD and BOSL2 manuals as zipfiles to it, and instruct it on some
stylistic things you want. It exposed me to some techniques I hadn't used
in the past but proved to be quite useful, and took care of all of the
tedious math.
cheers
Roel
[image: image.png]
include <BOSL2-master/std.scad>;
$fn = $preview ? 32 : 128;
module squished_circle(radius, squish_top, squish_bottom, num_points) {
points = [
for (i = [0:num_points - 1])
let (
angle = i * 360 / num_points,
x = radius * cos(angle),
y = radius * sin(angle),
squish = (y > 0) ? (1 - squish_top) : (1 - squish_bottom)
)
[x, y * squish]
];
linear_extrude(height=0.01)
polygon(points);
}
// Function to calculate the Y-axis angle for a point
function calculate_y_angle(index, points) =
index < len(points) - 1 ?
atan2(points[index + 1].z - points[index].z, points[index + 1].x -
points[index].x) :
atan2(points[index].z - points[index - 1].z, points[index].x -
points[index - 1].x);
// Module to render a rotated squished circle at a given point
module render_squished_circle(position, angle_y, scale_) {
translate(position) {
yrot(90 - angle_y) // Rotate around Y-axis to face next segment
zrot(90) // Rotate around Z-axis
scale([scale_, scale_, 1])
squished_circle(10, top_squish, bottom_squish,
circumference_resolution);
}
}
// Function to calculate a smooth transition from max_scale to 1
function calculate_scale(i, num_rings, max_scale, decay) =
(i < num_rings) ?
1 + (max_scale - 1) * (exp(-decay * i / (num_rings - 1)) -
exp(-decay)) / (1 - exp(-decay)) * (1 - 0.5 * (1 - cos(PI * i /
num_rings))) :
1;
module bezier_curve(p0, p1, p2, p3, num_segments) {
bezier_points = [
for (i = [0:num_segments])
let (
t = i / num_segments,
x = (1 - t)^3 * p0.x + 3 * (1 - t)^2 * t * p1.x +
3 * (1 - t) * t^2 * p2.x + t^3 * p3.x,
y = (1 - t)^3 * p0.y + 3 * (1 - t)^2 * t * p1.y +
3 * (1 - t) * t^2 * p2.y + t^3 * p3.y,
z = (1 - t)^3 * p0.z + 3 * (1 - t)^2 * t * p1.z +
3 * (1 - t) * t^2 * p2.z + t^3 * p3.z
)
[x, y, z]
];
for (i = [0 : len(bezier_points) - 2]) {
// Get current point and angle
p1 = bezier_points[i];
angle1_y = (i == 0) ? 90 : calculate_y_angle(i, bezier_points);
// Get next point and angle
p2 = bezier_points[i + 1];
angle2_y = (i == len(bezier_points) - 2) ? 0 : calculate_y_angle(i
1, bezier_points);
scale1 = calculate_scale(i, num_rings, max_scale, decay);
scale2 = calculate_scale(i + 1, num_rings, max_scale, decay);
// Hull between current and next squished circles
hull() {
render_squished_circle(p1, angle1_y, scale1);
render_squished_circle(p2, angle2_y, scale2);
}
}
}
module half_handle(p0, p1, p2, p3, num_segments) {
// Render the Bezier curve
bezier_curve(p0, p1, p2, p3, num_segments);
}
// Parameters
handle_diameter = 20;
top_squish = 0.4;
bottom_squish = 0.1;
circumference_resolution = 64;
handle_width = 120;
handle_height = 40;
max_scale = 3;
num_rings = 30;
decay = 5;
module handle(start_curve_height) {
p0 = [0, 0, 0];
p1 = [0, 0, start_curve_height];
p2 = [handle_width / 2 - 30, 0, handle_height];
p3 = [handle_width / 2, 0, handle_height];
num_segments = 128;
half_handle(p0, p1, p2, p3, num_segments);
right(handle_width)
zrot(180)
half_handle(p0, p1, p2, p3, num_segments);
}
// Configurable parameters
thickness = 20;
length = 200; // Total length of the weigth
point_length = 80;
width = 80; // Total width
sphere_size = 3; // Size of spheres i.e. rounding radius
num_segments = 100; // Number of segments along the curve; smoothness
of the curve
curvature = 0.8;
module body() {
// Taper function with proper curvature control, always reaching 0 at
the end
function taper(x, curvature) = let (
ratio = x / point_length, // Ratio always
between 0 and 1
adjusted_cos = cos(ratio * 90) ^ curvature // Adjust the cosine
curve using curvature
) (width / 2) * adjusted_cos; // Scale by width
for (x = [0 : length : length / 10]) {
echo(x = x, taper = taper(x, 2));
}
// Generate the profile points
profile = [
for (i = [0 : num_segments])
let (x = i * (point_length / num_segments)) // Compute
x-coordinate
[x, taper(x, curvature), 0] // Tapered
width at this point
];
// Render the hull profile using spheres
module front_profile_curve() {
//hull() {
for (p = profile) {
translate(p) sphere(r = sphere_size);
}
sphere(r = sphere_size);
//}
}
// Execute the profile rendering
hull() {
front_profile_curve();
up(thickness)
front_profile_curve();
front_profile_curve();
mirror([0, 1, 0]) {
front_profile_curve();
up(thickness)
front_profile_curve();
}
left(length - point_length) fwd(width / 2)
sphere(r = sphere_size);
up(thickness) left(length - point_length) fwd(width / 2)
sphere(r = sphere_size);
left(length - point_length) back(width / 2)
sphere(r = sphere_size);
up(thickness) left(length - point_length) back(width / 2)
sphere(r = sphere_size);
}
}
up(thickness + sphere_size)
handle(37);
right((length / 2) - 5) // This 5 was calibrated by eye.
body();
On Mon, Jan 20, 2025 at 3:45 PM Roel Vanhout roel.vanhout@gmail.com wrote:
Hello all,
Another day, another filleting question! I know there have been many of
these lately (well, I guess there have always been), but I can't figure out
how to apply any of the solutions in those to my current problem, so I'm
hoping someone can point me in the right direction. I'm open to using
Python as well if that makes it easier.
Essentially I want to create a handle with no sharp corners. I have
attached a crude example that I made in Blender. What I did there was start
out with a 2d version of the cross section of the handle, which is an
ellipse that is more squished (at least I think that's the professional
mathematician's term for it) at the top than it is at bottom. That shape is
then extruded along a Bezier curve. Then the bottom few rings of edges are
scaled in the X and Y axes, each subsequent one a bit less, the amounts of
the scaling factors forming an exponential decay curve or some such.
I don't think this sort of direct edge manipulation is possible in
OpenSCAD, but I also can't think of a CSG equivalent of these operations. I
mentioned Python OpenSCAD above because I know it has an extrude along path
function, which would get me partly there, but can I also then select and
manipulate vertices on the result mesh? Or can I go the other way around -
scale the cross section 2d shape on each segment of the bezier and then do
a hull() of all the result 2d shapes in plain OpenSCAD? Thanks!
[image: image.png]
"Chatgpt can actually be quite competent at writing OpenSCAD code, as
long as you create a custom GPT and upload the OpenSCAD and BOSL2
manuals as zipfiles to it, and instruct it on some stylistic things you
want."
How does one create a "custom GPT"? Would it be useful if someone
created one and uploaded the OpenSCAD information as you suggested and
then made it available to this community?
Jon
On 1/29/2025 8:45 AM, Roel Vanhout via Discuss wrote:
A bit of 'closure' on this question I asked last week. I tried to
understand and use the suggestions that were posted, and although I
did get some ideas from them, I couldn't quite wrap my head around
them enough to make them my own. But, in the end I've managed to
produce pretty much exactly what I wanted in plain OpenSCAD. I'm
posting this more as an encouragement to people like myself a week ago
who are very intimidated by making smooth objects in OpenSCAD, that
it's absolutely possible, but may require some different thinking, at
least compared to how I myself approach modeling other objects. I
actually started out writing a pure Python program that generated
triangles and exported into Wavefront .obj format, which is a very
simple text-based 3d mesh format. (I say 'writing a pure Python
program', but actually Chatgpt wrote most of the hairy stuff). I got
the handle itself to work, then I wanted to add more functionality to
create the rest of the object I want to make, but that turned out to
be such a slog in Python, so I ported my approach from Python 1:1 to
OpenSCAD. That didn't work very well, it was essentially generating
all the points and faces to be passed to polyhedron(); but after a bit
of refactoring (but keeping the original approach) I got the attached
more idiomatic OpenSCAD version.
What it does is basically do the same steps I would do to model this
object manually in Blender. Create a list of points along a bezier
curve, then position a slightly linear_extrude()'ed polygon on each
point of that curve, rotating it to point towards the next point. Then
for the 'flare' at the base it applies a scale() to the relevant (i.e.
first x) polygons, using an exponentially decaying scaling factor.
These polygons are combined into a solid using hull() on each
consecutive pair. For generating the rounded object that forms the
base of this handle, I also used hull() on a bunch of spheres
positioned at the extremes of the outline of the object.
All of this may be obvious to others; but although I do by now
consider myself an intermediate level OpenSCAD user, it still took me
a radically different way of thinking to get here. This whole process
has been quite a learning experience really, and I think it will make
me consider doing things in OpenSCAD in the future that just a week
ago, I would think of as too hard/not worth the effort.
A technical note is that I did have to use the preview builds of
OpenSCAD, as otherwise rendering this took minutes; in the preview
build, less than half a second.
And another side remark is that Chatgpt can actually be quite
competent at writing OpenSCAD code, as long as you create a custom GPT
and upload the OpenSCAD and BOSL2 manuals as zipfiles to it, and
instruct it on some stylistic things you want. It exposed me to some
techniques I hadn't used in the past but proved to be quite useful,
and took care of all of the tedious math.
cheers
Roel
image.png
include <BOSL2-master/std.scad>;
$fn = $preview ? 32 : 128;
module squished_circle(radius, squish_top, squish_bottom, num_points) {
points = [
for (i = [0:num_points - 1])
let (
angle = i * 360 / num_points,
x = radius * cos(angle),
y = radius * sin(angle),
squish = (y > 0) ? (1 - squish_top) : (1 - squish_bottom)
)
[x, y * squish]
];
linear_extrude(height=0.01)
polygon(points);
}
// Function to calculate the Y-axis angle for a point
function calculate_y_angle(index, points) =
index < len(points) - 1 ?
atan2(points[index + 1].z - points[index].z, points[index +
1].x - points[index].x) :
atan2(points[index].z - points[index - 1].z, points[index].x -
points[index - 1].x);
// Module to render a rotated squished circle at a given point
module render_squished_circle(position, angle_y, scale_) {
translate(position) {
yrot(90 - angle_y) // Rotate around Y-axis to face next segment
zrot(90) // Rotate around Z-axis
scale([scale_, scale_, 1])
squished_circle(10, top_squish, bottom_squish,
circumference_resolution);
}
}
// Function to calculate a smooth transition from max_scale to 1
function calculate_scale(i, num_rings, max_scale, decay) =
(i < num_rings) ?
1 + (max_scale - 1) * (exp(-decay * i / (num_rings - 1)) -
exp(-decay)) / (1 - exp(-decay)) * (1 - 0.5 * (1 - cos(PI * i /
num_rings))) :
1;
module bezier_curve(p0, p1, p2, p3, num_segments) {
bezier_points = [
for (i = [0:num_segments])
let (
t = i / num_segments,
x = (1 - t)^3 * p0.x + 3 * (1 - t)^2 * t * p1.x +
3 * (1 - t) * t^2 * p2.x + t^3 * p3.x,
y = (1 - t)^3 * p0.y + 3 * (1 - t)^2 * t * p1.y +
3 * (1 - t) * t^2 * p2.y + t^3 * p3.y,
z = (1 - t)^3 * p0.z + 3 * (1 - t)^2 * t * p1.z +
3 * (1 - t) * t^2 * p2.z + t^3 * p3.z
)
[x, y, z]
];
for (i = [0 : len(bezier_points) - 2]) {
// Get current point and angle
p1 = bezier_points[i];
angle1_y = (i == 0) ? 90 : calculate_y_angle(i, bezier_points);
// Get next point and angle
p2 = bezier_points[i + 1];
angle2_y = (i == len(bezier_points) - 2) ? 0 :
calculate_y_angle(i + 1, bezier_points);
scale1 = calculate_scale(i, num_rings, max_scale, decay);
scale2 = calculate_scale(i + 1, num_rings, max_scale, decay);
// Hull between current and next squished circles
hull() {
render_squished_circle(p1, angle1_y, scale1);
render_squished_circle(p2, angle2_y, scale2);
}
}
}
module half_handle(p0, p1, p2, p3, num_segments) {
// Render the Bezier curve
bezier_curve(p0, p1, p2, p3, num_segments);
}
// Parameters
handle_diameter = 20;
top_squish = 0.4;
bottom_squish = 0.1;
circumference_resolution = 64;
handle_width = 120;
handle_height = 40;
max_scale = 3;
num_rings = 30;
decay = 5;
module handle(start_curve_height) {
p0 = [0, 0, 0];
p1 = [0, 0, start_curve_height];
p2 = [handle_width / 2 - 30, 0, handle_height];
p3 = [handle_width / 2, 0, handle_height];
num_segments = 128;
half_handle(p0, p1, p2, p3, num_segments);
right(handle_width)
zrot(180)
half_handle(p0, p1, p2, p3, num_segments);
}
// Configurable parameters
thickness = 20;
length = 200; // Total length of the weigth
point_length = 80;
width = 80; // Total width
sphere_size = 3; // Size of spheres i.e. rounding radius
num_segments = 100; // Number of segments along the curve;
smoothness of the curve
curvature = 0.8;
module body() {
// Taper function with proper curvature control, always reaching 0
at the end
function taper(x, curvature) = let (
ratio = x / point_length, // Ratio always
between 0 and 1
adjusted_cos = cos(ratio * 90) ^ curvature // Adjust the
cosine curve using curvature
) (width / 2) * adjusted_cos; // Scale by width
for (x = [0 : length : length / 10]) {
echo(x = x, taper = taper(x, 2));
}
// Generate the profile points
profile = [
for (i = [0 : num_segments])
let (x = i * (point_length / num_segments)) // Compute
x-coordinate
[x, taper(x, curvature), 0] // Tapered width at this point
];
// Render the hull profile using spheres
module front_profile_curve() {
//hull() {
for (p = profile) {
translate(p) sphere(r = sphere_size);
}
sphere(r = sphere_size);
//}
}
// Execute the profile rendering
hull() {
front_profile_curve();
up(thickness)
front_profile_curve();
front_profile_curve();
mirror([0, 1, 0]) {
front_profile_curve();
up(thickness)
front_profile_curve();
}
left(length - point_length) fwd(width / 2)
sphere(r = sphere_size);
up(thickness) left(length - point_length) fwd(width / 2)
sphere(r = sphere_size);
left(length - point_length) back(width / 2)
sphere(r = sphere_size);
up(thickness) left(length - point_length) back(width / 2)
sphere(r = sphere_size);
}
}
up(thickness + sphere_size)
handle(37);
right((length / 2) - 5) // This 5 was calibrated by eye.
body();
On Mon, Jan 20, 2025 at 3:45 PM Roel Vanhout roel.vanhout@gmail.com
wrote:
Hello all,
Another day, another filleting question! I know there have been
many of these lately (well, I guess there have always been), but I
can't figure out how to apply any of the solutions in those to my
current problem, so I'm hoping someone can point me in the right
direction. I'm open to using Python as well if that makes it easier.
Essentially I want to create a handle with no sharp corners. I
have attached a crude example that I made in Blender. What I did
there was start out with a 2d version of the cross section of the
handle, which is an ellipse that is more squished (at least I
think that's the professional mathematician's term for it) at the
top than it is at bottom. That shape is then extruded along a
Bezier curve. Then the bottom few rings of edges are scaled in the
X and Y axes, each subsequent one a bit less, the amounts of the
scaling factors forming an exponential decay curve or some such.
I don't think this sort of direct edge manipulation is possible in
OpenSCAD, but I also can't think of a CSG equivalent of these
operations. I mentioned Python OpenSCAD above because I know it
has an extrude along path function, which would get me partly
there, but can I also then select and manipulate vertices on the
result mesh? Or can I go the other way around - scale the cross
section 2d shape on each segment of the bezier and then do a
hull() of all the result 2d shapes in plain OpenSCAD? Thanks!
image.png
OpenSCAD mailing list
To unsubscribe send an email todiscuss-leave@lists.openscad.org
--
This email has been checked for viruses by AVG antivirus software.
www.avg.com
Ah I'm sorry, it seems custom GPT's are available only when you have a Plus
(i.e., paid) account, I hadn't realized that when I wrote the email. I will
look into whether I can expose mine to other users - although mine isn't
really set up for public use, more tuned to my needs and habits. But if
anyone is interested and/or wants to play around with it I'll see what I
can do.
Cheers
On Wed, Jan 29, 2025, 18:15 Jon Bondy jon@jonbondy.com wrote:
"Chatgpt can actually be quite competent at writing OpenSCAD code, as long
as you create a custom GPT and upload the OpenSCAD and BOSL2 manuals as
zipfiles to it, and instruct it on some stylistic things you want."
How does one create a "custom GPT"? Would it be useful if someone created
one and uploaded the OpenSCAD information as you suggested and then made it
available to this community?
Jon
On 1/29/2025 8:45 AM, Roel Vanhout via Discuss wrote:
A bit of 'closure' on this question I asked last week. I tried to
understand and use the suggestions that were posted, and although I did get
some ideas from them, I couldn't quite wrap my head around them enough to
make them my own. But, in the end I've managed to produce pretty much
exactly what I wanted in plain OpenSCAD. I'm posting this more as an
encouragement to people like myself a week ago who are very intimidated by
making smooth objects in OpenSCAD, that it's absolutely possible, but may
require some different thinking, at least compared to how I myself approach
modeling other objects. I actually started out writing a pure Python
program that generated triangles and exported into Wavefront .obj format,
which is a very simple text-based 3d mesh format. (I say 'writing a pure
Python program', but actually Chatgpt wrote most of the hairy stuff). I got
the handle itself to work, then I wanted to add more functionality to
create the rest of the object I want to make, but that turned out to be
such a slog in Python, so I ported my approach from Python 1:1 to OpenSCAD.
That didn't work very well, it was essentially generating all the points
and faces to be passed to polyhedron(); but after a bit of refactoring (but
keeping the original approach) I got the attached more idiomatic OpenSCAD
version.
What it does is basically do the same steps I would do to model this
object manually in Blender. Create a list of points along a bezier curve,
then position a slightly linear_extrude()'ed polygon on each point of that
curve, rotating it to point towards the next point. Then for the 'flare' at
the base it applies a scale() to the relevant (i.e. first x) polygons,
using an exponentially decaying scaling factor. These polygons are combined
into a solid using hull() on each consecutive pair. For generating the
rounded object that forms the base of this handle, I also used hull() on a
bunch of spheres positioned at the extremes of the outline of the object.
All of this may be obvious to others; but although I do by now consider
myself an intermediate level OpenSCAD user, it still took me a radically
different way of thinking to get here. This whole process has been quite a
learning experience really, and I think it will make me consider doing
things in OpenSCAD in the future that just a week ago, I would think of as
too hard/not worth the effort.
A technical note is that I did have to use the preview builds of OpenSCAD,
as otherwise rendering this took minutes; in the preview build, less than
half a second.
And another side remark is that Chatgpt can actually be quite competent at
writing OpenSCAD code, as long as you create a custom GPT and upload the
OpenSCAD and BOSL2 manuals as zipfiles to it, and instruct it on some
stylistic things you want. It exposed me to some techniques I hadn't used
in the past but proved to be quite useful, and took care of all of the
tedious math.
cheers
Roel
[image: image.png]
include <BOSL2-master/std.scad>;
$fn = $preview ? 32 : 128;
module squished_circle(radius, squish_top, squish_bottom, num_points) {
points = [
for (i = [0:num_points - 1])
let (
angle = i * 360 / num_points,
x = radius * cos(angle),
y = radius * sin(angle),
squish = (y > 0) ? (1 - squish_top) : (1 - squish_bottom)
)
[x, y * squish]
];
linear_extrude(height=0.01)
polygon(points);
}
// Function to calculate the Y-axis angle for a point
function calculate_y_angle(index, points) =
index < len(points) - 1 ?
atan2(points[index + 1].z - points[index].z, points[index + 1].x -
points[index].x) :
atan2(points[index].z - points[index - 1].z, points[index].x -
points[index - 1].x);
// Module to render a rotated squished circle at a given point
module render_squished_circle(position, angle_y, scale_) {
translate(position) {
yrot(90 - angle_y) // Rotate around Y-axis to face next segment
zrot(90) // Rotate around Z-axis
scale([scale_, scale_, 1])
squished_circle(10, top_squish, bottom_squish,
circumference_resolution);
}
}
// Function to calculate a smooth transition from max_scale to 1
function calculate_scale(i, num_rings, max_scale, decay) =
(i < num_rings) ?
1 + (max_scale - 1) * (exp(-decay * i / (num_rings - 1)) -
exp(-decay)) / (1 - exp(-decay)) * (1 - 0.5 * (1 - cos(PI * i /
num_rings))) :
1;
module bezier_curve(p0, p1, p2, p3, num_segments) {
bezier_points = [
for (i = [0:num_segments])
let (
t = i / num_segments,
x = (1 - t)^3 * p0.x + 3 * (1 - t)^2 * t * p1.x +
3 * (1 - t) * t^2 * p2.x + t^3 * p3.x,
y = (1 - t)^3 * p0.y + 3 * (1 - t)^2 * t * p1.y +
3 * (1 - t) * t^2 * p2.y + t^3 * p3.y,
z = (1 - t)^3 * p0.z + 3 * (1 - t)^2 * t * p1.z +
3 * (1 - t) * t^2 * p2.z + t^3 * p3.z
)
[x, y, z]
];
for (i = [0 : len(bezier_points) - 2]) {
// Get current point and angle
p1 = bezier_points[i];
angle1_y = (i == 0) ? 90 : calculate_y_angle(i, bezier_points);
// Get next point and angle
p2 = bezier_points[i + 1];
angle2_y = (i == len(bezier_points) - 2) ? 0 : calculate_y_angle(i
1, bezier_points);
scale1 = calculate_scale(i, num_rings, max_scale, decay);
scale2 = calculate_scale(i + 1, num_rings, max_scale, decay);
// Hull between current and next squished circles
hull() {
render_squished_circle(p1, angle1_y, scale1);
render_squished_circle(p2, angle2_y, scale2);
}
}
}
module half_handle(p0, p1, p2, p3, num_segments) {
// Render the Bezier curve
bezier_curve(p0, p1, p2, p3, num_segments);
}
// Parameters
handle_diameter = 20;
top_squish = 0.4;
bottom_squish = 0.1;
circumference_resolution = 64;
handle_width = 120;
handle_height = 40;
max_scale = 3;
num_rings = 30;
decay = 5;
module handle(start_curve_height) {
p0 = [0, 0, 0];
p1 = [0, 0, start_curve_height];
p2 = [handle_width / 2 - 30, 0, handle_height];
p3 = [handle_width / 2, 0, handle_height];
num_segments = 128;
half_handle(p0, p1, p2, p3, num_segments);
right(handle_width)
zrot(180)
half_handle(p0, p1, p2, p3, num_segments);
}
// Configurable parameters
thickness = 20;
length = 200; // Total length of the weigth
point_length = 80;
width = 80; // Total width
sphere_size = 3; // Size of spheres i.e. rounding radius
num_segments = 100; // Number of segments along the curve; smoothness
of the curve
curvature = 0.8;
module body() {
// Taper function with proper curvature control, always reaching 0 at
the end
function taper(x, curvature) = let (
ratio = x / point_length, // Ratio always
between 0 and 1
adjusted_cos = cos(ratio * 90) ^ curvature // Adjust the cosine
curve using curvature
) (width / 2) * adjusted_cos; // Scale by width
for (x = [0 : length : length / 10]) {
echo(x = x, taper = taper(x, 2));
}
// Generate the profile points
profile = [
for (i = [0 : num_segments])
let (x = i * (point_length / num_segments)) // Compute
x-coordinate
[x, taper(x, curvature), 0] // Tapered
width at this point
];
// Render the hull profile using spheres
module front_profile_curve() {
//hull() {
for (p = profile) {
translate(p) sphere(r = sphere_size);
}
sphere(r = sphere_size);
//}
}
// Execute the profile rendering
hull() {
front_profile_curve();
up(thickness)
front_profile_curve();
front_profile_curve();
mirror([0, 1, 0]) {
front_profile_curve();
up(thickness)
front_profile_curve();
}
left(length - point_length) fwd(width / 2)
sphere(r = sphere_size);
up(thickness) left(length - point_length) fwd(width / 2)
sphere(r = sphere_size);
left(length - point_length) back(width / 2)
sphere(r = sphere_size);
up(thickness) left(length - point_length) back(width / 2)
sphere(r = sphere_size);
}
}
up(thickness + sphere_size)
handle(37);
right((length / 2) - 5) // This 5 was calibrated by eye.
body();
On Mon, Jan 20, 2025 at 3:45 PM Roel Vanhout roel.vanhout@gmail.com
wrote:
Hello all,
Another day, another filleting question! I know there have been many of
these lately (well, I guess there have always been), but I can't figure out
how to apply any of the solutions in those to my current problem, so I'm
hoping someone can point me in the right direction. I'm open to using
Python as well if that makes it easier.
Essentially I want to create a handle with no sharp corners. I have
attached a crude example that I made in Blender. What I did there was start
out with a 2d version of the cross section of the handle, which is an
ellipse that is more squished (at least I think that's the professional
mathematician's term for it) at the top than it is at bottom. That shape is
then extruded along a Bezier curve. Then the bottom few rings of edges are
scaled in the X and Y axes, each subsequent one a bit less, the amounts of
the scaling factors forming an exponential decay curve or some such.
I don't think this sort of direct edge manipulation is possible in
OpenSCAD, but I also can't think of a CSG equivalent of these operations. I
mentioned Python OpenSCAD above because I know it has an extrude along path
function, which would get me partly there, but can I also then select and
manipulate vertices on the result mesh? Or can I go the other way around -
scale the cross section 2d shape on each segment of the bezier and then do
a hull() of all the result 2d shapes in plain OpenSCAD? Thanks!
[image: image.png]
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=emailclient
Virus-free.www.avg.com
http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=emailclient
<#m_-3425882695854380890_DAB4FAD8-2DD7-40BB-A1B8-4E2AA1F9FDF2>
This is where deepseek could be a good thing. It's a lot more open than the
rather misleadingly named OpenAI
On Wed, Jan 29, 2025, 12:47 Roel Vanhout via Discuss <
discuss@lists.openscad.org> wrote:
Ah I'm sorry, it seems custom GPT's are available only when you have a
Plus (i.e., paid) account, I hadn't realized that when I wrote the email. I
will look into whether I can expose mine to other users - although mine
isn't really set up for public use, more tuned to my needs and habits. But
if anyone is interested and/or wants to play around with it I'll see what I
can do.
Cheers
On Wed, Jan 29, 2025, 18:15 Jon Bondy jon@jonbondy.com wrote:
"Chatgpt can actually be quite competent at writing OpenSCAD code, as
long as you create a custom GPT and upload the OpenSCAD and BOSL2 manuals
as zipfiles to it, and instruct it on some stylistic things you want."
How does one create a "custom GPT"? Would it be useful if someone
created one and uploaded the OpenSCAD information as you suggested and then
made it available to this community?
Jon
On 1/29/2025 8:45 AM, Roel Vanhout via Discuss wrote:
A bit of 'closure' on this question I asked last week. I tried to
understand and use the suggestions that were posted, and although I did get
some ideas from them, I couldn't quite wrap my head around them enough to
make them my own. But, in the end I've managed to produce pretty much
exactly what I wanted in plain OpenSCAD. I'm posting this more as an
encouragement to people like myself a week ago who are very intimidated by
making smooth objects in OpenSCAD, that it's absolutely possible, but may
require some different thinking, at least compared to how I myself approach
modeling other objects. I actually started out writing a pure Python
program that generated triangles and exported into Wavefront .obj format,
which is a very simple text-based 3d mesh format. (I say 'writing a pure
Python program', but actually Chatgpt wrote most of the hairy stuff). I got
the handle itself to work, then I wanted to add more functionality to
create the rest of the object I want to make, but that turned out to be
such a slog in Python, so I ported my approach from Python 1:1 to OpenSCAD.
That didn't work very well, it was essentially generating all the points
and faces to be passed to polyhedron(); but after a bit of refactoring (but
keeping the original approach) I got the attached more idiomatic OpenSCAD
version.
What it does is basically do the same steps I would do to model this
object manually in Blender. Create a list of points along a bezier curve,
then position a slightly linear_extrude()'ed polygon on each point of that
curve, rotating it to point towards the next point. Then for the 'flare' at
the base it applies a scale() to the relevant (i.e. first x) polygons,
using an exponentially decaying scaling factor. These polygons are combined
into a solid using hull() on each consecutive pair. For generating the
rounded object that forms the base of this handle, I also used hull() on a
bunch of spheres positioned at the extremes of the outline of the object.
All of this may be obvious to others; but although I do by now consider
myself an intermediate level OpenSCAD user, it still took me a radically
different way of thinking to get here. This whole process has been quite a
learning experience really, and I think it will make me consider doing
things in OpenSCAD in the future that just a week ago, I would think of as
too hard/not worth the effort.
A technical note is that I did have to use the preview builds of
OpenSCAD, as otherwise rendering this took minutes; in the preview build,
less than half a second.
And another side remark is that Chatgpt can actually be quite competent
at writing OpenSCAD code, as long as you create a custom GPT and upload the
OpenSCAD and BOSL2 manuals as zipfiles to it, and instruct it on some
stylistic things you want. It exposed me to some techniques I hadn't used
in the past but proved to be quite useful, and took care of all of the
tedious math.
cheers
Roel
[image: image.png]
include <BOSL2-master/std.scad>;
$fn = $preview ? 32 : 128;
module squished_circle(radius, squish_top, squish_bottom, num_points) {
points = [
for (i = [0:num_points - 1])
let (
angle = i * 360 / num_points,
x = radius * cos(angle),
y = radius * sin(angle),
squish = (y > 0) ? (1 - squish_top) : (1 - squish_bottom)
)
[x, y * squish]
];
linear_extrude(height=0.01)
polygon(points);
}
// Function to calculate the Y-axis angle for a point
function calculate_y_angle(index, points) =
index < len(points) - 1 ?
atan2(points[index + 1].z - points[index].z, points[index + 1].x
// Module to render a rotated squished circle at a given point
module render_squished_circle(position, angle_y, scale_) {
translate(position) {
yrot(90 - angle_y) // Rotate around Y-axis to face next segment
zrot(90) // Rotate around Z-axis
scale([scale_, scale_, 1])
squished_circle(10, top_squish, bottom_squish,
circumference_resolution);
}
}
// Function to calculate a smooth transition from max_scale to 1
function calculate_scale(i, num_rings, max_scale, decay) =
(i < num_rings) ?
1 + (max_scale - 1) * (exp(-decay * i / (num_rings - 1)) -
exp(-decay)) / (1 - exp(-decay)) * (1 - 0.5 * (1 - cos(PI * i /
num_rings))) :
1;
module bezier_curve(p0, p1, p2, p3, num_segments) {
bezier_points = [
for (i = [0:num_segments])
let (
t = i / num_segments,
x = (1 - t)^3 * p0.x + 3 * (1 - t)^2 * t * p1.x +
3 * (1 - t) * t^2 * p2.x + t^3 * p3.x,
y = (1 - t)^3 * p0.y + 3 * (1 - t)^2 * t * p1.y +
3 * (1 - t) * t^2 * p2.y + t^3 * p3.y,
z = (1 - t)^3 * p0.z + 3 * (1 - t)^2 * t * p1.z +
3 * (1 - t) * t^2 * p2.z + t^3 * p3.z
)
[x, y, z]
];
for (i = [0 : len(bezier_points) - 2]) {
// Get current point and angle
p1 = bezier_points[i];
angle1_y = (i == 0) ? 90 : calculate_y_angle(i, bezier_points);
// Get next point and angle
p2 = bezier_points[i + 1];
angle2_y = (i == len(bezier_points) - 2) ? 0 :
calculate_y_angle(i + 1, bezier_points);
scale1 = calculate_scale(i, num_rings, max_scale, decay);
scale2 = calculate_scale(i + 1, num_rings, max_scale, decay);
// Hull between current and next squished circles
hull() {
render_squished_circle(p1, angle1_y, scale1);
render_squished_circle(p2, angle2_y, scale2);
}
}
}
module half_handle(p0, p1, p2, p3, num_segments) {
// Render the Bezier curve
bezier_curve(p0, p1, p2, p3, num_segments);
}
// Parameters
handle_diameter = 20;
top_squish = 0.4;
bottom_squish = 0.1;
circumference_resolution = 64;
handle_width = 120;
handle_height = 40;
max_scale = 3;
num_rings = 30;
decay = 5;
module handle(start_curve_height) {
p0 = [0, 0, 0];
p1 = [0, 0, start_curve_height];
p2 = [handle_width / 2 - 30, 0, handle_height];
p3 = [handle_width / 2, 0, handle_height];
num_segments = 128;
half_handle(p0, p1, p2, p3, num_segments);
right(handle_width)
zrot(180)
half_handle(p0, p1, p2, p3, num_segments);
}
// Configurable parameters
thickness = 20;
length = 200; // Total length of the weigth
point_length = 80;
width = 80; // Total width
sphere_size = 3; // Size of spheres i.e. rounding radius
num_segments = 100; // Number of segments along the curve; smoothness
of the curve
curvature = 0.8;
module body() {
// Taper function with proper curvature control, always reaching 0 at
the end
function taper(x, curvature) = let (
ratio = x / point_length, // Ratio always
between 0 and 1
adjusted_cos = cos(ratio * 90) ^ curvature // Adjust the cosine
curve using curvature
) (width / 2) * adjusted_cos; // Scale by width
for (x = [0 : length : length / 10]) {
echo(x = x, taper = taper(x, 2));
}
// Generate the profile points
profile = [
for (i = [0 : num_segments])
let (x = i * (point_length / num_segments)) // Compute
x-coordinate
[x, taper(x, curvature), 0] // Tapered
width at this point
];
// Render the hull profile using spheres
module front_profile_curve() {
//hull() {
for (p = profile) {
translate(p) sphere(r = sphere_size);
}
sphere(r = sphere_size);
//}
}
// Execute the profile rendering
hull() {
front_profile_curve();
up(thickness)
front_profile_curve();
front_profile_curve();
mirror([0, 1, 0]) {
front_profile_curve();
up(thickness)
front_profile_curve();
}
left(length - point_length) fwd(width / 2)
sphere(r = sphere_size);
up(thickness) left(length - point_length) fwd(width / 2)
sphere(r = sphere_size);
left(length - point_length) back(width / 2)
sphere(r = sphere_size);
up(thickness) left(length - point_length) back(width / 2)
sphere(r = sphere_size);
}
}
up(thickness + sphere_size)
handle(37);
right((length / 2) - 5) // This 5 was calibrated by eye.
body();
On Mon, Jan 20, 2025 at 3:45 PM Roel Vanhout roel.vanhout@gmail.com
wrote:
Hello all,
Another day, another filleting question! I know there have been many of
these lately (well, I guess there have always been), but I can't figure out
how to apply any of the solutions in those to my current problem, so I'm
hoping someone can point me in the right direction. I'm open to using
Python as well if that makes it easier.
Essentially I want to create a handle with no sharp corners. I have
attached a crude example that I made in Blender. What I did there was start
out with a 2d version of the cross section of the handle, which is an
ellipse that is more squished (at least I think that's the professional
mathematician's term for it) at the top than it is at bottom. That shape is
then extruded along a Bezier curve. Then the bottom few rings of edges are
scaled in the X and Y axes, each subsequent one a bit less, the amounts of
the scaling factors forming an exponential decay curve or some such.
I don't think this sort of direct edge manipulation is possible in
OpenSCAD, but I also can't think of a CSG equivalent of these operations. I
mentioned Python OpenSCAD above because I know it has an extrude along path
function, which would get me partly there, but can I also then select and
manipulate vertices on the result mesh? Or can I go the other way around -
scale the cross section 2d shape on each segment of the bezier and then do
a hull() of all the result 2d shapes in plain OpenSCAD? Thanks!
[image: image.png]
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=emailclient
Virus-free.www.avg.com
http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=emailclient
<#m_7288014851204764018_m_-3425882695854380890_DAB4FAD8-2DD7-40BB-A1B8-4E2AA1F9FDF2>
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
"Takes care of all the tedious math?" I would say that that horrific code
introduces tons of spurious math that you didn't need or was already
handled by the BOSL2 library. I didn't understand the explanation of the
method, but here's a relatively simple way to generate a shape like this.
The main weakness is that it creates the fillet by scaling, which is
incorrect. It should be an offset, which is a bit more complicated.
include<BOSL2/std.scad>
hrad = 10;
handle_pts=150;
cross_section = xscale(.7,circle(r=hrad));
handle_path = arc(angle=[0,180], r=100, n=handle_pts); // substitute a
different handle if desired
T=path_sweep(cross_section, handle_path, transforms=true);
offset_steps=10;
offset_length = path_length(select(handle_path, 0,offset_steps));
offset_dist = [for(d=lerpn(0,offset_length,offset_steps)) offset_length -
sqrt(offset_length^2-d^2)];
offset_scales = [for(i=idx(offset_dist)) (offset_dist[i]+hrad)/hrad];
scale = concat(reverse(offset_scales),
repeat(1,handle_pts-2*offset_steps,1),
offset_scales);
combine = [for(i=idx(T)) T[i]*scale(scale[i])];
xrot(90)sweep(cross_section, combine);
cuboid([275,300,10],anchor=TOP);
[image: image.png]
On Wed, Jan 29, 2025 at 2:45 PM A. Craig West via Discuss <
discuss@lists.openscad.org> wrote:
This is where deepseek could be a good thing. It's a lot more open than
the rather misleadingly named OpenAI
On Wed, Jan 29, 2025, 12:47 Roel Vanhout via Discuss <
discuss@lists.openscad.org> wrote:
Ah I'm sorry, it seems custom GPT's are available only when you have a
Plus (i.e., paid) account, I hadn't realized that when I wrote the email. I
will look into whether I can expose mine to other users - although mine
isn't really set up for public use, more tuned to my needs and habits. But
if anyone is interested and/or wants to play around with it I'll see what I
can do.
Cheers
On Wed, Jan 29, 2025, 18:15 Jon Bondy jon@jonbondy.com wrote:
"Chatgpt can actually be quite competent at writing OpenSCAD code, as
long as you create a custom GPT and upload the OpenSCAD and BOSL2 manuals
as zipfiles to it, and instruct it on some stylistic things you want."
How does one create a "custom GPT"? Would it be useful if someone
created one and uploaded the OpenSCAD information as you suggested and then
made it available to this community?
Jon
On 1/29/2025 8:45 AM, Roel Vanhout via Discuss wrote:
A bit of 'closure' on this question I asked last week. I tried to
understand and use the suggestions that were posted, and although I did get
some ideas from them, I couldn't quite wrap my head around them enough to
make them my own. But, in the end I've managed to produce pretty much
exactly what I wanted in plain OpenSCAD. I'm posting this more as an
encouragement to people like myself a week ago who are very intimidated by
making smooth objects in OpenSCAD, that it's absolutely possible, but may
require some different thinking, at least compared to how I myself approach
modeling other objects. I actually started out writing a pure Python
program that generated triangles and exported into Wavefront .obj format,
which is a very simple text-based 3d mesh format. (I say 'writing a pure
Python program', but actually Chatgpt wrote most of the hairy stuff). I got
the handle itself to work, then I wanted to add more functionality to
create the rest of the object I want to make, but that turned out to be
such a slog in Python, so I ported my approach from Python 1:1 to OpenSCAD.
That didn't work very well, it was essentially generating all the points
and faces to be passed to polyhedron(); but after a bit of refactoring (but
keeping the original approach) I got the attached more idiomatic OpenSCAD
version.
What it does is basically do the same steps I would do to model this
object manually in Blender. Create a list of points along a bezier curve,
then position a slightly linear_extrude()'ed polygon on each point of that
curve, rotating it to point towards the next point. Then for the 'flare' at
the base it applies a scale() to the relevant (i.e. first x) polygons,
using an exponentially decaying scaling factor. These polygons are combined
into a solid using hull() on each consecutive pair. For generating the
rounded object that forms the base of this handle, I also used hull() on a
bunch of spheres positioned at the extremes of the outline of the object.
All of this may be obvious to others; but although I do by now consider
myself an intermediate level OpenSCAD user, it still took me a radically
different way of thinking to get here. This whole process has been quite a
learning experience really, and I think it will make me consider doing
things in OpenSCAD in the future that just a week ago, I would think of as
too hard/not worth the effort.
A technical note is that I did have to use the preview builds of
OpenSCAD, as otherwise rendering this took minutes; in the preview build,
less than half a second.
And another side remark is that Chatgpt can actually be quite competent
at writing OpenSCAD code, as long as you create a custom GPT and upload the
OpenSCAD and BOSL2 manuals as zipfiles to it, and instruct it on some
stylistic things you want. It exposed me to some techniques I hadn't used
in the past but proved to be quite useful, and took care of all of the
tedious math.
cheers
Roel
[image: image.png]
include <BOSL2-master/std.scad>;
$fn = $preview ? 32 : 128;
module squished_circle(radius, squish_top, squish_bottom, num_points) {
points = [
for (i = [0:num_points - 1])
let (
angle = i * 360 / num_points,
x = radius * cos(angle),
y = radius * sin(angle),
squish = (y > 0) ? (1 - squish_top) : (1 - squish_bottom)
)
[x, y * squish]
];
linear_extrude(height=0.01)
polygon(points);
}
// Function to calculate the Y-axis angle for a point
function calculate_y_angle(index, points) =
index < len(points) - 1 ?
atan2(points[index + 1].z - points[index].z, points[index + 1].x
// Module to render a rotated squished circle at a given point
module render_squished_circle(position, angle_y, scale_) {
translate(position) {
yrot(90 - angle_y) // Rotate around Y-axis to face next segment
zrot(90) // Rotate around Z-axis
scale([scale_, scale_, 1])
squished_circle(10, top_squish, bottom_squish,
circumference_resolution);
}
}
// Function to calculate a smooth transition from max_scale to 1
function calculate_scale(i, num_rings, max_scale, decay) =
(i < num_rings) ?
1 + (max_scale - 1) * (exp(-decay * i / (num_rings - 1)) -
exp(-decay)) / (1 - exp(-decay)) * (1 - 0.5 * (1 - cos(PI * i /
num_rings))) :
1;
module bezier_curve(p0, p1, p2, p3, num_segments) {
bezier_points = [
for (i = [0:num_segments])
let (
t = i / num_segments,
x = (1 - t)^3 * p0.x + 3 * (1 - t)^2 * t * p1.x +
3 * (1 - t) * t^2 * p2.x + t^3 * p3.x,
y = (1 - t)^3 * p0.y + 3 * (1 - t)^2 * t * p1.y +
3 * (1 - t) * t^2 * p2.y + t^3 * p3.y,
z = (1 - t)^3 * p0.z + 3 * (1 - t)^2 * t * p1.z +
3 * (1 - t) * t^2 * p2.z + t^3 * p3.z
)
[x, y, z]
];
for (i = [0 : len(bezier_points) - 2]) {
// Get current point and angle
p1 = bezier_points[i];
angle1_y = (i == 0) ? 90 : calculate_y_angle(i, bezier_points);
// Get next point and angle
p2 = bezier_points[i + 1];
angle2_y = (i == len(bezier_points) - 2) ? 0 :
calculate_y_angle(i + 1, bezier_points);
scale1 = calculate_scale(i, num_rings, max_scale, decay);
scale2 = calculate_scale(i + 1, num_rings, max_scale, decay);
// Hull between current and next squished circles
hull() {
render_squished_circle(p1, angle1_y, scale1);
render_squished_circle(p2, angle2_y, scale2);
}
}
}
module half_handle(p0, p1, p2, p3, num_segments) {
// Render the Bezier curve
bezier_curve(p0, p1, p2, p3, num_segments);
}
// Parameters
handle_diameter = 20;
top_squish = 0.4;
bottom_squish = 0.1;
circumference_resolution = 64;
handle_width = 120;
handle_height = 40;
max_scale = 3;
num_rings = 30;
decay = 5;
module handle(start_curve_height) {
p0 = [0, 0, 0];
p1 = [0, 0, start_curve_height];
p2 = [handle_width / 2 - 30, 0, handle_height];
p3 = [handle_width / 2, 0, handle_height];
num_segments = 128;
half_handle(p0, p1, p2, p3, num_segments);
right(handle_width)
zrot(180)
half_handle(p0, p1, p2, p3, num_segments);
}
// Configurable parameters
thickness = 20;
length = 200; // Total length of the weigth
point_length = 80;
width = 80; // Total width
sphere_size = 3; // Size of spheres i.e. rounding radius
num_segments = 100; // Number of segments along the curve;
smoothness of the curve
curvature = 0.8;
module body() {
// Taper function with proper curvature control, always reaching 0
at the end
function taper(x, curvature) = let (
ratio = x / point_length, // Ratio always
between 0 and 1
adjusted_cos = cos(ratio * 90) ^ curvature // Adjust the cosine
curve using curvature
) (width / 2) * adjusted_cos; // Scale by width
for (x = [0 : length : length / 10]) {
echo(x = x, taper = taper(x, 2));
}
// Generate the profile points
profile = [
for (i = [0 : num_segments])
let (x = i * (point_length / num_segments)) // Compute
x-coordinate
[x, taper(x, curvature), 0] // Tapered
width at this point
];
// Render the hull profile using spheres
module front_profile_curve() {
//hull() {
for (p = profile) {
translate(p) sphere(r = sphere_size);
}
sphere(r = sphere_size);
//}
}
// Execute the profile rendering
hull() {
front_profile_curve();
up(thickness)
front_profile_curve();
front_profile_curve();
mirror([0, 1, 0]) {
front_profile_curve();
up(thickness)
front_profile_curve();
}
left(length - point_length) fwd(width / 2)
sphere(r = sphere_size);
up(thickness) left(length - point_length) fwd(width / 2)
sphere(r = sphere_size);
left(length - point_length) back(width / 2)
sphere(r = sphere_size);
up(thickness) left(length - point_length) back(width / 2)
sphere(r = sphere_size);
}
}
up(thickness + sphere_size)
handle(37);
right((length / 2) - 5) // This 5 was calibrated by eye.
body();
On Mon, Jan 20, 2025 at 3:45 PM Roel Vanhout roel.vanhout@gmail.com
wrote:
Hello all,
Another day, another filleting question! I know there have been many of
these lately (well, I guess there have always been), but I can't figure out
how to apply any of the solutions in those to my current problem, so I'm
hoping someone can point me in the right direction. I'm open to using
Python as well if that makes it easier.
Essentially I want to create a handle with no sharp corners. I have
attached a crude example that I made in Blender. What I did there was start
out with a 2d version of the cross section of the handle, which is an
ellipse that is more squished (at least I think that's the professional
mathematician's term for it) at the top than it is at bottom. That shape is
then extruded along a Bezier curve. Then the bottom few rings of edges are
scaled in the X and Y axes, each subsequent one a bit less, the amounts of
the scaling factors forming an exponential decay curve or some such.
I don't think this sort of direct edge manipulation is possible in
OpenSCAD, but I also can't think of a CSG equivalent of these operations. I
mentioned Python OpenSCAD above because I know it has an extrude along path
function, which would get me partly there, but can I also then select and
manipulate vertices on the result mesh? Or can I go the other way around -
scale the cross section 2d shape on each segment of the bezier and then do
a hull() of all the result 2d shapes in plain OpenSCAD? Thanks!
[image: image.png]
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=emailclient
Virus-free.www.avg.com
http://www.avg.com/email-signature?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=emailclient
<#m_-2767940691129321374_m_7288014851204764018_m_-3425882695854380890_DAB4FAD8-2DD7-40BB-A1B8-4E2AA1F9FDF2>
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
OpenAI was originally supposed to be open source.
I downloaded the source, it's at github.
https://github.com/deepseek-ai
I also ordered Zero Point Energy today, that's exciting.
If you tell me something I'll forget it.
If you show me something I might remember it.If you involve me in it, I will understand it.
Sent with Proton Mail secure email.
On Wednesday, January 29th, 2025 at 2:45 PM, A. Craig West via Discuss discuss@lists.openscad.org wrote:
This is where deepseek could be a good thing. It's a lot more open than the rather misleadingly named OpenAI
On Wed, Jan 29, 2025, 12:47 Roel Vanhout via Discuss discuss@lists.openscad.org wrote:
Ah I'm sorry, it seems custom GPT's are available only when you have a Plus (i.e., paid) account, I hadn't realized that when I wrote the email. I will look into whether I can expose mine to other users - although mine isn't really set up for public use, more tuned to my needs and habits. But if anyone is interested and/or wants to play around with it I'll see what I can do.
Cheers
On Wed, Jan 29, 2025, 18:15 Jon Bondy jon@jonbondy.com wrote:
"Chatgpt can actually be quite competent at writing OpenSCAD code, as long as you create a custom GPT and upload the OpenSCAD and BOSL2 manuals as zipfiles to it, and instruct it on some stylistic things you want."
How does one create a "custom GPT"? Would it be useful if someone created one and uploaded the OpenSCAD information as you suggested and then made it available to this community?
Jon
On 1/29/2025 8:45 AM, Roel Vanhout via Discuss wrote:
A bit of 'closure' on this question I asked last week. I tried to understand and use the suggestions that were posted, and although I did get some ideas from them, I couldn't quite wrap my head around them enough to make them my own. But, in the end I've managed to produce pretty much exactly what I wanted in plain OpenSCAD. I'm posting this more as an encouragement to people like myself a week ago who are very intimidated by making smooth objects in OpenSCAD, that it's absolutely possible, but may require some different thinking, at least compared to how I myself approach modeling other objects. I actually started out writing a pure Python program that generated triangles and exported into Wavefront .obj format, which is a very simple text-based 3d mesh format. (I say 'writing a pure Python program', but actually Chatgpt wrote most of the hairy stuff). I got the handle itself to work, then I wanted to add more functionality to create the rest of the object I want to make, but that turned out to be such a slog in Python, so I ported my approach from Python 1:1 to OpenSCAD. That didn't work very well, it was essentially generating all the points and faces to be passed to polyhedron(); but after a bit of refactoring (but keeping the original approach) I got the attached more idiomatic OpenSCAD version.
What it does is basically do the same steps I would do to model this object manually in Blender. Create a list of points along a bezier curve, then position a slightly linear_extrude()'ed polygon on each point of that curve, rotating it to point towards the next point. Then for the 'flare' at the base it applies a scale() to the relevant (i.e. first x) polygons, using an exponentially decaying scaling factor. These polygons are combined into a solid using hull() on each consecutive pair. For generating the rounded object that forms the base of this handle, I also used hull() on a bunch of spheres positioned at the extremes of the outline of the object.
All of this may be obvious to others; but although I do by now consider myself an intermediate level OpenSCAD user, it still took me a radically different way of thinking to get here. This whole process has been quite a learning experience really, and I think it will make me consider doing things in OpenSCAD in the future that just a week ago, I would think of as too hard/not worth the effort.
A technical note is that I did have to use the preview builds of OpenSCAD, as otherwise rendering this took minutes; in the preview build, less than half a second.
And another side remark is that Chatgpt can actually be quite competent at writing OpenSCAD code, as long as you create a custom GPT and upload the OpenSCAD and BOSL2 manuals as zipfiles to it, and instruct it on some stylistic things you want. It exposed me to some techniques I hadn't used in the past but proved to be quite useful, and took care of all of the tedious math.
cheers
Roel
[image.png]
include <BOSL2-master/std.scad>;
$fn = $preview ? 32 : 128;
module squished_circle(radius, squish_top, squish_bottom, num_points) {
points = [
for (i = [0:num_points - 1])
let (
angle = i * 360 / num_points,
x = radius * cos(angle),
y = radius * sin(angle),
squish = (y > 0) ? (1 - squish_top) : (1 - squish_bottom)
)
[x, y * squish]
];
linear_extrude(height=0.01)
polygon(points);
}
// Function to calculate the Y-axis angle for a point
function calculate_y_angle(index, points) =
index < len(points) - 1 ?
atan2(points[index + 1].z - points[index].z, points[index + 1].x - points[index].x) :
atan2(points[index].z - points[index - 1].z, points[index].x - points[index - 1].x);
// Module to render a rotated squished circle at a given point
module render_squished_circle(position, angle_y, scale_) {
translate(position) {
yrot(90 - angle_y) // Rotate around Y-axis to face next segment
zrot(90) // Rotate around Z-axis
scale([scale_, scale_, 1])
squished_circle(10, top_squish, bottom_squish, circumference_resolution);
}
}
// Function to calculate a smooth transition from max_scale to 1
function calculate_scale(i, num_rings, max_scale, decay) =
(i < num_rings) ?
1 + (max_scale - 1) * (exp(-decay * i / (num_rings - 1)) - exp(-decay)) / (1 - exp(-decay)) * (1 - 0.5 * (1 - cos(PI * i / num_rings))) :
1;
module bezier_curve(p0, p1, p2, p3, num_segments) {
bezier_points = [
for (i = [0:num_segments])
let (
t = i / num_segments,
x = (1 - t)^3 * p0.x + 3 * (1 - t)^2 * t * p1.x +
3 * (1 - t) * t^2 * p2.x + t^3 * p3.x,
y = (1 - t)^3 * p0.y + 3 * (1 - t)^2 * t * p1.y +
3 * (1 - t) * t^2 * p2.y + t^3 * p3.y,
z = (1 - t)^3 * p0.z + 3 * (1 - t)^2 * t * p1.z +
3 * (1 - t) * t^2 * p2.z + t^3 * p3.z
)
[x, y, z]
];
for (i = [0 : len(bezier_points) - 2]) {
// Get current point and angle
p1 = bezier_points[i];
angle1_y = (i == 0) ? 90 : calculate_y_angle(i, bezier_points);
// Get next point and angle
p2 = bezier_points[i + 1];
angle2_y = (i == len(bezier_points) - 2) ? 0 : calculate_y_angle(i + 1, bezier_points);
scale1 = calculate_scale(i, num_rings, max_scale, decay);
scale2 = calculate_scale(i + 1, num_rings, max_scale, decay);
// Hull between current and next squished circles
hull() {
render_squished_circle(p1, angle1_y, scale1);
render_squished_circle(p2, angle2_y, scale2);
}
}
}
module half_handle(p0, p1, p2, p3, num_segments) {
// Render the Bezier curve
bezier_curve(p0, p1, p2, p3, num_segments);
}
// Parameters
handle_diameter = 20;
top_squish = 0.4;
bottom_squish = 0.1;
circumference_resolution = 64;
handle_width = 120;
handle_height = 40;
max_scale = 3;
num_rings = 30;
decay = 5;
module handle(start_curve_height) {
p0 = [0, 0, 0];
p1 = [0, 0, start_curve_height];
p2 = [handle_width / 2 - 30, 0, handle_height];
p3 = [handle_width / 2, 0, handle_height];
num_segments = 128;
half_handle(p0, p1, p2, p3, num_segments);
right(handle_width)
zrot(180)
half_handle(p0, p1, p2, p3, num_segments);
}
// Configurable parameters
thickness = 20;
length = 200; // Total length of the weigth
point_length = 80;
width = 80; // Total width
sphere_size = 3; // Size of spheres i.e. rounding radius
num_segments = 100; // Number of segments along the curve; smoothness of the curve
curvature = 0.8;
module body() {
// Taper function with proper curvature control, always reaching 0 at the end
function taper(x, curvature) = let (
ratio = x / point_length, // Ratio always between 0 and 1
adjusted_cos = cos(ratio * 90) ^ curvature // Adjust the cosine curve using curvature
) (width / 2) * adjusted_cos; // Scale by width
for (x = [0 : length : length / 10]) {
echo(x = x, taper = taper(x, 2));
}
// Generate the profile points
profile = [
for (i = [0 : num_segments])
let (x = i * (point_length / num_segments)) // Compute x-coordinate
[x, taper(x, curvature), 0] // Tapered width at this point
];
// Render the hull profile using spheres
module front_profile_curve() {
//hull() {
for (p = profile) {
translate(p) sphere(r = sphere_size);
}
sphere(r = sphere_size);
//}
}
// Execute the profile rendering
hull() {
front_profile_curve();
up(thickness)
front_profile_curve();
front_profile_curve();
mirror([0, 1, 0]) {
front_profile_curve();
up(thickness)
front_profile_curve();
}
left(length - point_length) fwd(width / 2)
sphere(r = sphere_size);
up(thickness) left(length - point_length) fwd(width / 2)
sphere(r = sphere_size);
left(length - point_length) back(width / 2)
sphere(r = sphere_size);
up(thickness) left(length - point_length) back(width / 2)
sphere(r = sphere_size);
}
}
up(thickness + sphere_size)
handle(37);
right((length / 2) - 5) // This 5 was calibrated by eye.
body();
On Mon, Jan 20, 2025 at 3:45 PM Roel Vanhout roel.vanhout@gmail.com wrote:
Hello all,
Another day, another filleting question! I know there have been many of these lately (well, I guess there have always been), but I can't figure out how to apply any of the solutions in those to my current problem, so I'm hoping someone can point me in the right direction. I'm open to using Python as well if that makes it easier.
Essentially I want to create a handle with no sharp corners. I have attached a crude example that I made in Blender. What I did there was start out with a 2d version of the cross section of the handle, which is an ellipse that is more squished (at least I think that's the professional mathematician's term for it) at the top than it is at bottom. That shape is then extruded along a Bezier curve. Then the bottom few rings of edges are scaled in the X and Y axes, each subsequent one a bit less, the amounts of the scaling factors forming an exponential decay curve or some such.
I don't think this sort of direct edge manipulation is possible in OpenSCAD, but I also can't think of a CSG equivalent of these operations. I mentioned Python OpenSCAD above because I know it has an extrude along path function, which would get me partly there, but can I also then select and manipulate vertices on the result mesh? Or can I go the other way around - scale the cross section 2d shape on each segment of the bezier and then do a hull() of all the result 2d shapes in plain OpenSCAD? Thanks!
[image.png]
OpenSCAD mailing list
To unsubscribe send an email to
discuss-leave@lists.openscad.org
http://www.avg.com/email-signature Virus-free.www.avg.com#m_7288014851204764018_m_-3425882695854380890_DAB4FAD8-2DD7-40BB-A1B8-4E2AA1F9FDF2
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
Hi Roel,
I've been experimenting with ChatGPT and openscad (and python) for a
while - the free version. It is much, much better with python. It is
frustrating with openscad - it starts off with good intentions, then
keeps repeating the same mistakes. I continuously have to remind it
about variables being immutable, and that openscad works in degrees, for
example. After a half day of arguing, I generally give up. Not that I
know any, but I think its behaviour is symptomatic of a petulant child
(and ChatGPT agreed with that description).
My current 'problem', one that you may wish to test, is -
I can generate a shape by using, say, circle( d=50,$fn=f) to give a
pentagon if f=5, square if f=4, etc.. I need the vertices for creating
that type of polygon. Not too difficult. If I want rounded corners, then
I can use offset (r=x). Try to get your ChatGPT to generate the vertices
for a polygon from that, i.e. a polygon with rounded corners, say points
0.1 apart around the circumference of the curves. I would be interested
to see how you and ChatGPT get on, if you want to try. It is easier if
the origin is within the polygon. I do not expect it to use
Bosl2/python/other libraries in its solution, just raw openscad script.
Best wishes,
Ray
On 29/01/2025 17:46, Roel Vanhout via Discuss wrote:
Ah I'm sorry, it seems custom GPT's are available only when you have a
Plus (i.e., paid) account, I hadn't realized that when I wrote the
email. I will look into whether I can expose mine to other users -
although mine isn't really set up for public use, more tuned to my
needs and habits. But if anyone is interested and/or wants to play
around with it I'll see what I can do.
Cheers
o unsubscribe send an email to discuss-leave@lists.openscad.org
(Since it's OT anyway) I just had an interesting discussion with ChatGPT
over what does it mean that a space "follows" or "precedes" a group of
digits. It insists that in "Hello 123" the white space follows the
digits, whereas I would say that it precedes them. We haven't come to a
conclusion yet, but I may try again tomorrow: it's time to sleep now.
On 02/02/25 20:58, Raymond West via Discuss wrote:
Hi Roel,
I've been experimenting with ChatGPT and openscad (and python) for a
while - the free version. It is much, much better with python. It is
frustrating with openscad - it starts off with good intentions, then
keeps repeating the same mistakes. I continuously have to remind it
about variables being immutable, and that openscad works in degrees,
for example. After a half day of arguing, I generally give up. Not
that I know any, but I think its behaviour is symptomatic of a
petulant child (and ChatGPT agreed with that description).
My current 'problem', one that you may wish to test, is -
I can generate a shape by using, say, circle( d=50,$fn=f) to give a
pentagon if f=5, square if f=4, etc.. I need the vertices for creating
that type of polygon. Not too difficult. If I want rounded corners,
then I can use offset (r=x). Try to get your ChatGPT to generate the
vertices for a polygon from that, i.e. a polygon with rounded corners,
say points 0.1 apart around the circumference of the curves. I would
be interested to see how you and ChatGPT get on, if you want to try.
It is easier if the origin is within the polygon. I do not expect it
to use Bosl2/python/other libraries in its solution, just raw openscad
script.
Best wishes,
Ray
On 29/01/2025 17:46, Roel Vanhout via Discuss wrote:
Ah I'm sorry, it seems custom GPT's are available only when you have
a Plus (i.e., paid) account, I hadn't realized that when I wrote the
email. I will look into whether I can expose mine to other users -
although mine isn't really set up for public use, more tuned to my
needs and habits. But if anyone is interested and/or wants to play
around with it I'll see what I can do.
Cheers
o unsubscribe send an email to discuss-leave@lists.openscad.org
OpenSCAD mailing list
To unsubscribe send an email todiscuss-leave@lists.openscad.org
I for one welcome our new AI overlords.
On Sun, Feb 2, 2025 at 5:10 PM Andreas Croci via Discuss <
discuss@lists.openscad.org> wrote:
(Since it's OT anyway) I just had an interesting discussion with ChatGPT
over what does it mean that a space "follows" or "precedes" a group of
digits. It insists that in "Hello 123" the white space follows the digits,
whereas I would say that it precedes them. We haven't come to a conclusion
yet, but I may try again tomorrow: it's time to sleep now.
On 02/02/25 20:58, Raymond West via Discuss wrote:
Hi Roel,
I've been experimenting with ChatGPT and openscad (and python) for a while
My current 'problem', one that you may wish to test, is -
I can generate a shape by using, say, circle( d=50,$fn=f) to give a
pentagon if f=5, square if f=4, etc.. I need the vertices for creating that
type of polygon. Not too difficult. If I want rounded corners, then I can
use offset (r=x). Try to get your ChatGPT to generate the vertices for a
polygon from that, i.e. a polygon with rounded corners, say points 0.1
apart around the circumference of the curves. I would be interested to see
how you and ChatGPT get on, if you want to try. It is easier if the origin
is within the polygon. I do not expect it to use Bosl2/python/other
libraries in its solution, just raw openscad script.
Best wishes,
Ray
On 29/01/2025 17:46, Roel Vanhout via Discuss wrote:
Ah I'm sorry, it seems custom GPT's are available only when you have a
Plus (i.e., paid) account, I hadn't realized that when I wrote the email. I
will look into whether I can expose mine to other users - although mine
isn't really set up for public use, more tuned to my needs and habits. But
if anyone is interested and/or wants to play around with it I'll see what I
can do.
Cheers
o 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