I need to make what I can best describe as a curved slope. I can’t describe it well, but if you would care to run the following you would see.
// r1 = inner radius, r2 = outer radius, h1 = start height, h2 = end height, a = sweep angle
module curve_slope(r1, r2, h1, h2, a)
{
h_increment = (h2-h1)/a;
step=1;
union()
{
for (i = [0:step:a])
{
rotate([0,0,i])
rotate_extrude(angle=step)
translate([r1,0,0])
square([r2-r1,h1 + h_increment * i]);
}
}
}
curve_slope(45,60,0,20,90);
This does approximate exactly what I want, but it ends up being very inefficient in terms of polygon count, and is essentially a staircase rather than a smooth surface. If you choose a step value to create a smooth slope then the polygon count shoots up and rendering is really slow.
Is there a better way?
Thanks in advance
Jon
Build a polyhedron.
Others may have cleverer ways built on top of sweep functions - I don't
know, I've never used them - but here's an example from first
principles. It's set up for the Customizer, so that's an easy way to
play with the parameters.
// Curved Ramp
// Angular distance of ramp
a = 90;
// Inside radius
r1 = 45;
// Outside radius
r2 = 60;
// Height at start
h1 = 0;
// Height at end
h2 = 20;
// Number of steps
n = 100; // [2:10000]
curved_slope(r1, r2, h1, h2, a, n);
module curved_slope(r1, r2, h1, h2, a, n) {
assert(r1 > 0);
assert(r2 > r1);
assert(h1 >= 0);
assert(h2 >= 0);
assert(h1 > 0 || h2 > 0);
assert(a > 0);
assert(a < 360); // Likely badness if start touches end
assert(n > 1);
// All of the indexes of the steps
indexes = [0:n-1];
// The fraction represented by each step
ticks = [ for (i=indexes) i/(n-1) ];
// The angle for each step
angles = [ for (i=ticks) i*a ];
// The height at each step
heights = [ for (i=ticks) h1 + (h2-h1)*i ];
// The inner and outter 2D points at each step
inner = [ for (i = indexes) torect2([r1, angles[i]]) ];
outer = [ for (i = indexes) torect2([r2, angles[i]]) ];
// The outlines of the final shape
inner_bottom = [ for (i = indexes) [ inner[i].x, inner[i].y, 0 ] ];
inner_top = [ for (i = indexes) [ inner[i].x, inner[i].y, heights[i] ] ];
outer_bottom = [ for (i = indexes) [ outer[i].x, outer[i].y, 0 ] ];
outer_top = [ for (i = indexes) [ outer[i].x, outer[i].y, heights[i] ] ];
// Now we build the actual polyhedron data
// All of the points
points = concat(inner_bottom, inner_top, outer_bottom, outer_top);
// The base point indexes of each segment
ib = n*0; // inside bottom
it = n*1; // inside top
ob = n*2; // outside bottom
ot = n*3; // outside top
// Connect those points all up into triangles, except the ends are quads.
faces = concat(
// bottom
[ for (i = indexes) if (i != 0) [ ib + i, ob + i-1, ob + i ] ],
[ for (i = indexes) if (i != 0) [ ib + i, ib + i-1, ob + i-1 ] ],
// inside
[ for (i = indexes) if (i != 0) [ ib + i, it + i, it + i-1 ] ],
[ for (i = indexes) if (i != 0) [ ib + i, it + i-1, ib + i-1 ] ],
// outside
[ for (i = indexes) if (i != 0) [ ob + i, ot + i-1, ot + i ] ],
[ for (i = indexes) if (i != 0) [ ob + i, ob + i-1, ot + i-1 ] ],
// top
[ for (i = indexes) if (i != 0) [ it + i, ot + i, ot + i-1 ] ],
[ for (i = indexes) if (i != 0) [ it + i, ot + i-1, it + i-1 ] ],
// h1 end
[ if (h1 > 0) [ ib+0, it+0, ot+0, ob+0 ] ],
// h2 end
[ if (h2 > 0) [ ib+n-1, ob+n-1, ot+n-1, it+n-1 ] ]
);
// And build the final shape.
polyhedron(points=points, faces=faces);
}
// Given a [rho, theta], transform to an [x,y].
function torect2(p) = [
p[0] * cos(p[1]),
p[0] * sin(p[1])
];
Thank you. That solution looks absolutely perfect, it’s orders of magnitude more efficient than mine.
I think I must have somewhat ignored polyhedron() when I first learned openscad so despite it being right there, never really contemplated it’s utility until now.
I say it's silly to go to that much work every time you want to use
polyhedron. The problem with polyhedron is that you have got to do all this
book keeping. And it's easy to botch it, sometimes in subtle ways which
make your result invalid. To me it makes much more sense to use general
purpose polyhedron making routines like skin() and sweep() functions.
Here's the simplest change on the original code to make the shape using
skin() from BOSL2 which just links together a series of polygons and does
all the polyhedron book keeping for you.
https://github.com/revarbat/BOSL2/wiki
include <BOSL2/std.scad>
include <BOSL2/skin.scad>
// r1 = inner radius, r2 = outer radius, h1 = start height, h2 = end height,
a = sweep angle
module curve_slope(r1, r2, h1, h2, a)
{
h_increment = (h2-h1)/a;
step=1;
profiles = [for (i = [0:step:a])
rot(i,p=[[r1,0,0],
[r2,0,0],
[r2,0,h_incrementi],
[r1,0,h_incrementi]])
];
skin(profiles, slices=0); // slices=0 means insert no extra slices
between given polygons
}
curve_slope(45,60,0,20,90);
http://forum.openscad.org/file/t2477/slope1.png
Maybe it's a quirk of mine, but I dislike long skinny triangles in my
models. They give a kind of corrugated look to models and I think you end
up needing more of them to get a good looking model than with proper
equlateralish triangles. So here's an adjustment the subdivides the top:
// r1 = inner radius, r2 = outer radius, h1 = start height, h2 = end height,
a = sweep angle
module curve_slope(r1, r2, h1, h2, a)
{
h_increment = (h2-h1)/a;
step=1;
profiles = [for (i = [0:step:a])
rot(i,p=[[r1,0,0],
[r2,0,0],
each
lerp([r2,0,h_incrementi],[r1,0,h_incrementi],
[for(j=[0:1:5]) j/5])
])
];
skin(profiles, slices=0);
}
http://forum.openscad.org/file/t2477/slope2.png
JordanBrown wrote
Build a polyhedron.
Others may have cleverer ways built on top of sweep functions - I don't
know, I've never used them - but here's an example from first
principles. It's set up for the Customizer, so that's an easy way to
play with the parameters.
--
Sent from: http://forum.openscad.org/
On 2/26/2021 1:55 PM, adrianv wrote:
I say it's silly to go to that much work every time you want to use
polyhedron. The problem with polyhedron is that you have got to do
all this book keeping. And it's easy to botch it, sometimes in subtle
ways which make your result invalid. To me it makes much more sense
to use general purpose polyhedron making routines like skin() and
sweep() functions.
No argument. I've done so very little with such shapes that it's
easier, or at least not much harder, for me to do it from first
principles than to learn how to use a library that will do it easier.
This one really is a pretty simple shape.
And because I've done it so infrequently - I might have designed fewer
than ten polyhedra, ever - it was kind of fun. (My major project has
11K lines of OpenSCAD, and zero polyhedra. It originally had one, but
I found a simpler way and got rid of it.)
Fun tidbit: If you disable some of the asserts in my module, you can do
things like have negative heights, negative radii, and so on. If you
turn on View/Thrown Together, you can see that these tend to result in
some or all of the figure being inside out.
https://www.imdb.com/title/tt0177789/quotes?item=qt0424466
https://www.youtube.com/watch?v=_wMD0ZCh2Sc
With all that advanced stuff, we shouldn't forget that there is a simple
solution with native means for this specific problem:
--
Sent from: http://forum.openscad.org/
Sometimes, i look at what is possible using openscad, in just a few
lines I can produce something that using some other cad software, would
be tedious, to say the least. And then it can be 3D printed, giving a
'needed' functional item that would be tricky to make in some other way.
This is a feather board, if you are familiar with a table saw or router,
you will know what it is. It is clamped by an 8mm coach bolt, but it is
trivial to resize it to whatever size is required. It prints OK in Petg
(pla may be too brittle), with 4 walls or so, maybe 10% infill. It will
work with far fewer fingers, of course, but it will let you keep all
your fingers!
module arm(){
difference(){
union(){
difference(){
cylinder(15,50,50);
translate([5,0,0])cylinder(15,40,40);
translate([-80,0,0])cube(100);
}
translate([-43,0,0]) cylinder (15,12,12); //round end
}
translate([-43,0,0]) cube([9,9,115],true);// 9mm squarehole
}
}
//arm();
module finger(){
rotate([0,0,-130]){
translate([-1,0,0])cube([2,30 ,15]); //2mm thick fingers
}
}
//finger();
module fingers(){
for (i=[-90:4:70]){
rotate([0,0,i])translate([0,-48,0])finger();
}
}
$fn=100;
difference(){
union(){
arm();
fingers();
}
translate([35,-21,0])rotate([0,0,30])cube(100); // chop off end
difference(){ //'flatten' ends
cylinder (15,200,200);
cylinder(15,70,70);
}
}
That's a clever approach that I completely overlooked. I suppose I tend to
forget about the twist parameter for linear_extrude, perhaps in part because
it usually produces a bad result with how the shape is triangulated. But in
this case it's OK.
Parkinbot wrote
With all that advanced stuff, we shouldn't forget that there is a simple
solution with native means for this specific problem:
--
Sent from: http://forum.openscad.org/
OpenSCAD mailing list
Discuss@.openscad
--
Sent from: http://forum.openscad.org/
That's an interesting construct. I've not seen a radial fingerboard before.How do you feel about converting it to a parametric version?
On Saturday, February 27, 2021, 10:46:07 AM EST, Ray West <raywest@raywest.com> wrote:
Sometimes, i look at what is possible using openscad, in just a few
lines I can produce something that using some other cad software, would
be tedious, to say the least. And then it can be 3D printed, giving a
'needed' functional item that would be tricky to make in some other way.
This is a feather board, if you are familiar with a table saw or router,
you will know what it is. It is clamped by an 8mm coach bolt, but it is
trivial to resize it to whatever size is required. It prints OK in Petg
(pla may be too brittle), with 4 walls or so, maybe 10% infill. It will
work with far fewer fingers, of course, but it will let you keep all
your fingers!
module arm(){
difference(){
union(){
difference(){
cylinder(15,50,50);
translate([5,0,0])cylinder(15,40,40);
translate([-80,0,0])cube(100);
}
translate([-43,0,0]) cylinder (15,12,12); //round end
}
translate([-43,0,0]) cube([9,9,115],true);// 9mm squarehole
}
}
//arm();
module finger(){
rotate([0,0,-130]){
translate([-1,0,0])cube([2,30 ,15]); //2mm thick fingers
}
}
//finger();
module fingers(){
for (i=[-90:4:70]){
rotate([0,0,i])translate([0,-48,0])finger();
}
}
$fn=100;
difference(){
union(){
arm();
fingers();
}
translate([35,-21,0])rotate([0,0,30])cube(100); // chop off end
difference(){ //'flatten' ends
cylinder (15,200,200);
cylinder(15,70,70);
}
}
OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org