discuss@lists.openscad.org

OpenSCAD general discussion Mailing-list

View all threads

Rounded Polygon

NH
nop head
Fri, Mar 15, 2019 8:00 PM

Interesting stuff. I wonder if we should use Euler spirals instead of
Bezier splines to round polygons.

On Fri, 15 Mar 2019 at 19:45, Gadgetmind lists@foxhill.co.uk wrote:

On 15/03/2019 14:07, Ronaldo Persiano wrote:

Besides, curvature continuity is a requeriment on the design of a road
track. Any discontinuity on the track is prone to an accident because a
sudden wheel turn is needed to keep the vehicle on track when you cross the
discontinuity.

Railways used to be designed with straight and curves, and it made them
uncomfortable and restricted speeds, and ditto "loop the loop" on roller
coasters as the sudden changes in acceleration (high jerk) caused neck
injuries.

Then along came what I still call clothoid curves, but wikipedia prefers
Euler Spirals.

https://en.wikipedia.org/wiki/Euler_spiral

They are used to link straights to circles on railways, rollercoasters,
and much more.

https://en.wikipedia.org/wiki/Track_transition_curve


OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

Interesting stuff. I wonder if we should use Euler spirals instead of Bezier splines to round polygons. On Fri, 15 Mar 2019 at 19:45, Gadgetmind <lists@foxhill.co.uk> wrote: > On 15/03/2019 14:07, Ronaldo Persiano wrote: > > Besides, curvature continuity is a requeriment on the design of a road > track. Any discontinuity on the track is prone to an accident because a > sudden wheel turn is needed to keep the vehicle on track when you cross the > discontinuity. > > Railways used to be designed with straight and curves, and it made them > uncomfortable and restricted speeds, and ditto "loop the loop" on roller > coasters as the sudden changes in acceleration (high jerk) caused neck > injuries. > > Then along came what I still call clothoid curves, but wikipedia prefers > Euler Spirals. > > https://en.wikipedia.org/wiki/Euler_spiral > > They are used to link straights to circles on railways, rollercoasters, > and much more. > > https://en.wikipedia.org/wiki/Track_transition_curve > > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >
CA
Carsten Arnholm
Fri, Mar 15, 2019 8:59 PM

On 15.03.2019 17:39, Gadgetmind wrote:

Railways used to be designed with straight and curves, and it made them
uncomfortable and restricted speeds, and ditto "loop the loop" on roller
coasters as the sudden changes in acceleration (high jerk) caused neck
injuries.

Then along came what I still call clothoid curves, but wikipedia prefers
Euler Spirals.

Ditto, I learned about clothoid curves 35 years ago. A railway track
with immediate transition from a straight segment with zero curvature to
1/r in a circular segment will introduce a sudden sideways acceleration.
Not good. Railway tracks and motorways therefore use clothoid transition
curves.

I agree with those who say this does not matter for 3d printing though.

Carsten Arnholm

On 15.03.2019 17:39, Gadgetmind wrote: > Railways used to be designed with straight and curves, and it made them > uncomfortable and restricted speeds, and ditto "loop the loop" on roller > coasters as the sudden changes in acceleration (high jerk) caused neck > injuries. > > Then along came what I still call clothoid curves, but wikipedia prefers > Euler Spirals. Ditto, I learned about clothoid curves 35 years ago. A railway track with immediate transition from a straight segment with zero curvature to 1/r in a circular segment will introduce a sudden sideways acceleration. Not good. Railway tracks and motorways therefore use clothoid transition curves. I agree with those who say this does not matter for 3d printing though. Carsten Arnholm
A
adrianv
Fri, Mar 15, 2019 9:41 PM

nophead wrote

Interesting stuff. I wonder if we should use Euler spirals instead of
Bezier splines to round polygons.

It looks to me like the Bezier solution is probably easier than trying to
fit a fragment of an Euler spiral to transition between a flat section and a
circular arc.

I compared a 4th order bezier smoothed square to a circle rounded square and
they didn't look very different.  I asked myself why not?  And after some
investigation, reached a conclusion that I think is interesting.  I also
wonder if, perhaps, I was too quick to deny the utility of 5th order bezier
for this application.  Here are three examples.  The left uses circular
arcs.  The center uses 4th order bezier with the control points chosen for
the flattest arc, which is closest to circular.  It sure looks a lot like
the left hand image.  It looks like there are little corners where the
roundover meets the side.  The right hand example is a 4th order bezier with
different parameters and it looks smooth. I would say that the difference is
apparent, and I think it would be apparent if I printed the three squares.
(Maybe I should do a test print.)

http://forum.openscad.org/file/t2477/three_squares_crop.png

So what's going on.  Do I have continuous curvature or not?  Using a
curvature parameter that goes from [0,1] where 1 places p1=p0 and p3=4, and
0 places p1=p2=p3, I calculated the endpoint curvature and it is zero on
[0,1).  At 1 I have a problem because the derivative is zero, so it's a bad
parametrization.  But then I graphed the curvature for different parameter
values:

http://forum.openscad.org/file/t2477/bezier4curvature.png

The graphs show the curvature across half the bezier curve.  Of course the
other half is a mirror image.  So what I find is that when the parameter is
close to 1 the curvature starts at 0 but there is a big spike.  So it's
continuous technically, but not really practically.  It seems like a
parameter value in the range of [.5,.8] or so should give a moderate
derivative of the curvature.  If you go smaller the curvature rises a lot
in the middle of the curve, so the curve becomes pointed.  Note also that
if you want the curve to approximate a circle it's clear that this is
accomplished best when the parameter is close to 1, because then the
curvature is constant across most of the range.

So why am I having second thoughts about wanting order 5?  Well, it seems
that with order 4, once you scale the curves to be the same size (to cut off
the same amount of the corner) there is very little variation in that middle
range.  I felt like the full range of curves coming out of the 5th order
bezier was producing some weird looking flat stuff, but maybe some more
limited parameter set would be interesting.    I may plot more graphs later.

Also from this graph I can justify why we shouldn't bother with the Euler
spiral.  The Euler spiral's nice property is that the curvature starts at
zero and increases linearly.  The 0.7 curve and 0.5 curves look like
reasonable approximations to linear.  So the results wouldn't be much
different.  And this bezier approach is very easy to work with.  I have
done an implementation that does both bezier 4th order and circular arcs,
where I allow the user to specify the size of each corner's curve
independently, and I check for collisions (i.e. you pick too large of a
curve to fit).  My intention was that it could do closed paths (polygons)
but also open paths, and paths in 3d.  And the circular arc code was more
difficult to write than the bezier code, where once you've picked the
control points, you're basically done.  Once I've done a bit more testing
I'll post it here for comment.

Is there any mechanism other than assert() to generate warning or error
messages?  Assert seems kind of clumsy, since it prints the test, and it is
always a fatal error instead of a warning.

--
Sent from: http://forum.openscad.org/

nophead wrote > Interesting stuff. I wonder if we should use Euler spirals instead of > Bezier splines to round polygons. It looks to me like the Bezier solution is probably easier than trying to fit a fragment of an Euler spiral to transition between a flat section and a circular arc. I compared a 4th order bezier smoothed square to a circle rounded square and they didn't look very different. I asked myself why not? And after some investigation, reached a conclusion that I think is interesting. I also wonder if, perhaps, I was too quick to deny the utility of 5th order bezier for this application. Here are three examples. The left uses circular arcs. The center uses 4th order bezier with the control points chosen for the flattest arc, which is closest to circular. It sure looks a lot like the left hand image. It looks like there are little corners where the roundover meets the side. The right hand example is a 4th order bezier with different parameters and it looks smooth. I would say that the difference is apparent, and I think it would be apparent if I printed the three squares. (Maybe I should do a test print.) <http://forum.openscad.org/file/t2477/three_squares_crop.png> So what's going on. Do I have continuous curvature or not? Using a curvature parameter that goes from [0,1] where 1 places p1=p0 and p3=4, and 0 places p1=p2=p3, I calculated the endpoint curvature and it is zero on [0,1). At 1 I have a problem because the derivative is zero, so it's a bad parametrization. But then I graphed the curvature for different parameter values: <http://forum.openscad.org/file/t2477/bezier4curvature.png> The graphs show the curvature across half the bezier curve. Of course the other half is a mirror image. So what I find is that when the parameter is close to 1 the curvature starts at 0 but there is a big spike. So it's continuous technically, but not really practically. It seems like a parameter value in the range of [.5,.8] or so should give a moderate derivative of the curvature. If you go smaller the curvature rises a lot in the middle of the curve, so the curve becomes pointed. Note also that if you want the curve to approximate a circle it's clear that this is accomplished best when the parameter is close to 1, because then the curvature is constant across most of the range. So why am I having second thoughts about wanting order 5? Well, it seems that with order 4, once you scale the curves to be the same size (to cut off the same amount of the corner) there is very little variation in that middle range. I felt like the full range of curves coming out of the 5th order bezier was producing some weird looking flat stuff, but maybe some more limited parameter set would be interesting. I may plot more graphs later. Also from this graph I can justify why we shouldn't bother with the Euler spiral. The Euler spiral's nice property is that the curvature starts at zero and increases linearly. The 0.7 curve and 0.5 curves look like reasonable approximations to linear. So the results wouldn't be much different. And this bezier approach is very easy to work with. I have done an implementation that does both bezier 4th order and circular arcs, where I allow the user to specify the size of each corner's curve independently, and I check for collisions (i.e. you pick too large of a curve to fit). My intention was that it could do closed paths (polygons) but also open paths, and paths in 3d. And the circular arc code was more difficult to write than the bezier code, where once you've picked the control points, you're basically done. Once I've done a bit more testing I'll post it here for comment. Is there any mechanism other than assert() to generate warning or error messages? Assert seems kind of clumsy, since it prints the test, and it is always a fatal error instead of a warning. -- Sent from: http://forum.openscad.org/
RP
Ronaldo Persiano
Sat, Mar 16, 2019 12:26 AM

Very nice research! I am already waiting for the episode 2 :)

Is there any mechanism other than assert() to generate warning or error

messages?  Assert seems kind of clumsy, since it prints the test, and it is
always a fatal error instead of a warning.

Yes, you may insert an echo. I usually do something like this:

let( x = test? echo(a,b,c) 0 : 0 )

As echo() accepts HTML codes you are able to use a background color similar
to the OpenSCAD warnings.

Very nice research! I am already waiting for the episode 2 :) Is there any mechanism other than assert() to generate warning or error > messages? Assert seems kind of clumsy, since it prints the test, and it is > always a fatal error instead of a warning. > Yes, you may insert an echo. I usually do something like this: let( x = test? echo(a,b,c) 0 : 0 ) As echo() accepts HTML codes you are able to use a background color similar to the OpenSCAD warnings.
A
adrianv
Sat, Mar 16, 2019 5:03 AM

Ronaldo wrote

Very nice research! I am already waiting for the episode 2 :)

Maybe not as exciting as the first plot, but I did plot the shape of the
curve as I varied the curvature parameter.  It changes so slightly that it's
hard to see if I put too many curves on the graph, so I'm showing curvature
parameters of just 0, 0.5, and 1.  What changes a lot is the location of p0
and p4.  For this case, I have set the tip of the rounded corner to be 2
units back from the corner.  The bezier curve intersects the edge of the
right angle corner 4.5 units away from the corner when the curve parameter
is 1 (red line), 7.5 units when the parameter is 0.5 (green line), and a
whopping 22.6 units if you set the parameter to zero (blue line).  So
choosing a smaller curvature parameter causes it to really vary the
curvature slowly.  This I think makes those small values not very useful,
since you are very likely to run out of room on your object for the curve.

http://forum.openscad.org/file/t2477/corner2.png

Is there any mechanism other than assert() to generate warning or error

messages?  Assert seems kind of clumsy, since it prints the test, and it
is
always a fatal error instead of a warning.

Yes, you may insert an echo. I usually do something like this:

So with tagging I can get the color, but it's not going to be included in
the warning count.  I normally find that all the warning message scroll off
the message area due to the statistics report at the end.  Has anybody ever
talked about adding a warning command to the language, or extending echo to
have a warning flag that makes it count on the warning list?

--
Sent from: http://forum.openscad.org/

Ronaldo wrote > Very nice research! I am already waiting for the episode 2 :) Maybe not as exciting as the first plot, but I did plot the shape of the curve as I varied the curvature parameter. It changes so slightly that it's hard to see if I put too many curves on the graph, so I'm showing curvature parameters of just 0, 0.5, and 1. What changes a lot is the location of p0 and p4. For this case, I have set the tip of the rounded corner to be 2 units back from the corner. The bezier curve intersects the edge of the right angle corner 4.5 units away from the corner when the curve parameter is 1 (red line), 7.5 units when the parameter is 0.5 (green line), and a whopping 22.6 units if you set the parameter to zero (blue line). So choosing a smaller curvature parameter causes it to really vary the curvature slowly. This I think makes those small values not very useful, since you are very likely to run out of room on your object for the curve. <http://forum.openscad.org/file/t2477/corner2.png> > Is there any mechanism other than assert() to generate warning or error >> messages? Assert seems kind of clumsy, since it prints the test, and it >> is >> always a fatal error instead of a warning. >> > > Yes, you may insert an echo. I usually do something like this: So with tagging I can get the color, but it's not going to be included in the warning count. I normally find that all the warning message scroll off the message area due to the statistics report at the end. Has anybody ever talked about adding a warning command to the language, or extending echo to have a warning flag that makes it count on the warning list? -- Sent from: http://forum.openscad.org/
A
adrianv
Sat, Mar 16, 2019 8:25 PM

Here's the current version of my code, which appears to be working.  It can
round over each corner with an independently set rounding parameter
(including no rounding), and it can handle open and closed paths in 2d or
3d.

use<lib/BOSL/math.scad>
use<lib/BOSL/beziers.scad>

// TODO:
//  remove colinear points?
//
// roundcorners(path, curve, type, all, closed)
//
// path: a list of 2d or 3d points, possibly with an extra coordinate giving
smoothing parameters, e.g.
//      ex:  [[0,0],[0,1],[1,1],[0,1]]    2d point list
//          [[0,0,0], [0,1,1], [1,1,2], [0,1,3]]    3d point list
//          [[0,0,.2],[0,1,.1],[1,1,0],[0,1,.3]]    2d point list with
smoothing parameters
//          [[0,0,0,.2], [0,1,1,.1], [1,1,2,0], [0,1,3,.3]]    3d point
list with smooth parameters
//          [[0,0,[.3,.5], [4,0,[.2,.6]], [4,4,0], [0,4,[
// curve: set to "smooth" to get continuous curvature 4th order bezier
curves
//        set to "circle" to get circular arcs
// type: set to "cut" with either curve type to specify how much of the
corner to "cut" off.  The
//                    smoothing parameter will be the distance from the
corner to the tip of the rounded curve
//      set to "radius" to use with curve=="circle" to specify the curve
radius
//      set to "joint" to use with curve=="smooth" to specify the distance
from the corner at which
//                    the curve joints the shape
// all: set this to a curvature parameter to apply to all points on the
list.  If this is set then all
//      of the values given in the path are assumed to be geometrical
coordinates.  If you don't set it
//      then the last value of each entry in path is assumed to be the
smoothing parameters
// closed: set to true (the default) if the curve is closed and false if the
curve is open at the ends
//
// If you select curve=="smooth" then there are two smoothing parameters.
The first one
// is the cut or joint distance as given type "type".  The second one is a
curvature
// parameter which is a number in [0,1], where larger numbers have a more
abrupt
// transition and smaller ones a more gradual transition.  If the curvature
parameter is
// close to zero the transition is so gradual that it may take a very large
distance.
//
// If you select curves that are too large to fit the code will fail with an
error.  It displays a set
// of scale factors that you can apply to the (first) smoothing parameter
which will reduce the size of the
// curves so that they will fit on the shape.  If the scale factors are
larger than one then they
// indicate how much you can increase the curve size before collisions will
occur.
//
function roundcorners(path, curve, type, all=undef,  closed=true) =
let(
default_curvature = 0.7,  // default curvature for "smooth" curves
typeok = type == "cut" || (curve=="circle" && type=="radius") ||
(curve=="smooth" && type=="joint")
)
assert(curve=="smooth" || curve=="circle", "Unknown 'curve' setting in
roundcorners")
assert(typeok, curve=="circle" ? "In roundcorners curve=="circle"
requires 'type' of 'radius' or 'cut'":
"In roundcorners curve=="smooth"
requires 'type' of 'joint' or 'cut'")
let(
pathfixed= all == undef ? path : array_zip([path,
replist([all],len(path))]),
dim = len(pathfixed[0])-1,
points = array_subindex(pathfixed, [0:dim-1]),
parm = array_subindex(pathfixed, dim),
// dk will be a list of parameters, for the "smooth" type the distance
and curvature parameter pair,
// and for the circle type, distance and radius.
dk = [for(i=[0:len(points)-1]) let(
angle = pathangle(wrap_range(points,i-1,i+1))/2,
parm0 = is_list(parm[i]) ? parm[i][0] : parm[i],
k = curve=="circle" && type=="radius" ? parm0 :
curve=="circle" && type=="cut" ? parm0 / (1/sin(angle) - 1) :
is_list(parm[i]) && len(parm[i])==2 ? parm[i][1] :
default_curvature
) !closed && (i==0 || i==len(points)-1) ? [0,0] :
curve=="circle" ? [k/tan(angle), k] :
curve=="smooth" && type=="joint" ? [parm0,k] :
[8parm0/cos(angle)/(1+4k),k]
],
lengths = [for(i=[0:len(points)]) norm(flatten(diff(wrap_range(points,
i-1,i))))],
scalefactors = [for(i=[0:len(points)-1])
min(lengths[i]/sum(array_subindex(wrap_range(dk,i-1,i),0)),
lengths[i+1]/sum(array_subindex(wrap_range(dk,i,i+1),0)))]
)
echo("Roundover scale factors:",scalefactors)
assert(min(scalefactors)>=1,"Curves are too big for the path")
[ for(i=[0:len(points)-1])
each  dk[i][0] == 0 ? [points[i]] :
curve=="smooth" ? bezcorner(wrap_range(points,i-1,i+1), dk[i]) :
circlecorner(wrap_range(points,i-1,i+1),
dk[i])
];

function bezcorner(points, parm) =
let(
d = parm[0],
k = parm[1],
prev = normalize(points[0]-points[1]),
next = normalize(points[2]-points[1]),
P = [points[1]+dprev,
points[1]+k
dprev,
points[1],
points[1]+k
dnext,
points[1]+d
next])
bezier_curve(P,20);

function circlecorner(points, parm) =
let(
angle = pathangle(points)/2,
d = parm[0],
r = parm[1],
prev = normalize(points[0]-points[1]),
next = normalize(points[2]-points[1]),
center = r/sin(angle) * normalize(prev+next)+points[1]
)
circular_arc(center, points[1]+prevd, points[1]+nextd, 20);

function circular_arc(center, p1, p2, N) = let(
angle = pathangle([p1,center,p2]),
v1 = p1-center,
v2 = p2-center)
len(center)==2 ?
let ( start = atan2(v1[1],v1[0]),
end = atan2(v2[1],v2[0]),
r=norm(v1))
[for(i=[0:N-1]) let(theta=(end-start)i/(N-1)+start)
r
[cos(theta),sin(theta)]+center] :
let(axis = cross(v1,v2))
[for(i=[0:N-1]) matrix3_rot_by_axis(axis, i*angle/(N-1)) * v1 +
center];

function bezier_curve(P,N) =
[for(i=[0:N-1]) bez_point(P, i/(N-1))];

function pathangle(pts) =
let( d = [for(i=[0:2]) norm(flatten(diff(wrap_range(pts,i,i+1))))] )
acos(constrain(
(d[0]*d[0] + d[1]*d[1] - d[2]*d[2]) / 2 / d[0] / d[1], -1,1));

function array_subindex(vect, index) =
[for(entry=vect)
let(value=[for(i=index) entry[i]])
len(value)==1 ? value[0] : value];

function array_zip(vecs,v2,v3) =
v3!=undef ? array_zip([vecs,v2,v3]) :
v2!=undef ? array_zip([vecs,v2]) :
let(
length = len(vecs[0]),
samesize = [for (v=vecs) len(v)==length?0:1],
dummy=assert(sum(samesize)==0,"Input vectors must have the same length")
)
[for(i=[0:length-1])
[for(v=vecs) each v[i]]
];

function replist(list, N) = [for(i=[0:N-1]) list];

function diff(v) =
[for(i=[0:len(v)-2]) v[i+1]-v[i]];

sq = [[0,0],[2,0],[2,2],[0,2]];

polygon(roundcorners(sq, curve="circle", type="cut", all=.2));
translate([2.5,0,0])polygon(roundcorners(sq, all=[.2,.5], curve="smooth",
type="cut"));

--
Sent from: http://forum.openscad.org/

Here's the current version of my code, which appears to be working. It can round over each corner with an independently set rounding parameter (including no rounding), and it can handle open and closed paths in 2d or 3d. use<lib/BOSL/math.scad> use<lib/BOSL/beziers.scad> // TODO: // remove colinear points? // // roundcorners(path, curve, type, all, closed) // // path: a list of 2d or 3d points, possibly with an extra coordinate giving smoothing parameters, e.g. // ex: [[0,0],[0,1],[1,1],[0,1]] 2d point list // [[0,0,0], [0,1,1], [1,1,2], [0,1,3]] 3d point list // [[0,0,.2],[0,1,.1],[1,1,0],[0,1,.3]] 2d point list with smoothing parameters // [[0,0,0,.2], [0,1,1,.1], [1,1,2,0], [0,1,3,.3]] 3d point list with smooth parameters // [[0,0,[.3,.5], [4,0,[.2,.6]], [4,4,0], [0,4,[ // curve: set to "smooth" to get continuous curvature 4th order bezier curves // set to "circle" to get circular arcs // type: set to "cut" with either curve type to specify how much of the corner to "cut" off. The // smoothing parameter will be the distance from the corner to the tip of the rounded curve // set to "radius" to use with curve=="circle" to specify the curve radius // set to "joint" to use with curve=="smooth" to specify the distance from the corner at which // the curve joints the shape // all: set this to a curvature parameter to apply to all points on the list. If this is set then all // of the values given in the path are assumed to be geometrical coordinates. If you don't set it // then the last value of each entry in path is assumed to be the smoothing parameters // closed: set to true (the default) if the curve is closed and false if the curve is open at the ends // // If you select curve=="smooth" then there are two smoothing parameters. The first one // is the cut or joint distance as given type "type". The second one is a curvature // parameter which is a number in [0,1], where larger numbers have a more abrupt // transition and smaller ones a more gradual transition. If the curvature parameter is // close to zero the transition is so gradual that it may take a very large distance. // // If you select curves that are too large to fit the code will fail with an error. It displays a set // of scale factors that you can apply to the (first) smoothing parameter which will reduce the size of the // curves so that they will fit on the shape. If the scale factors are larger than one then they // indicate how much you can increase the curve size before collisions will occur. // function roundcorners(path, curve, type, all=undef, closed=true) = let( default_curvature = 0.7, // default curvature for "smooth" curves typeok = type == "cut" || (curve=="circle" && type=="radius") || (curve=="smooth" && type=="joint") ) assert(curve=="smooth" || curve=="circle", "Unknown 'curve' setting in roundcorners") assert(typeok, curve=="circle" ? "In roundcorners curve==\"circle\" requires 'type' of 'radius' or 'cut'": "In roundcorners curve==\"smooth\" requires 'type' of 'joint' or 'cut'") let( pathfixed= all == undef ? path : array_zip([path, replist([all],len(path))]), dim = len(pathfixed[0])-1, points = array_subindex(pathfixed, [0:dim-1]), parm = array_subindex(pathfixed, dim), // dk will be a list of parameters, for the "smooth" type the distance and curvature parameter pair, // and for the circle type, distance and radius. dk = [for(i=[0:len(points)-1]) let( angle = pathangle(wrap_range(points,i-1,i+1))/2, parm0 = is_list(parm[i]) ? parm[i][0] : parm[i], k = curve=="circle" && type=="radius" ? parm0 : curve=="circle" && type=="cut" ? parm0 / (1/sin(angle) - 1) : is_list(parm[i]) && len(parm[i])==2 ? parm[i][1] : default_curvature ) !closed && (i==0 || i==len(points)-1) ? [0,0] : curve=="circle" ? [k/tan(angle), k] : curve=="smooth" && type=="joint" ? [parm0,k] : [8*parm0/cos(angle)/(1+4*k),k] ], lengths = [for(i=[0:len(points)]) norm(flatten(diff(wrap_range(points, i-1,i))))], scalefactors = [for(i=[0:len(points)-1]) min(lengths[i]/sum(array_subindex(wrap_range(dk,i-1,i),0)), lengths[i+1]/sum(array_subindex(wrap_range(dk,i,i+1),0)))] ) echo("Roundover scale factors:",scalefactors) assert(min(scalefactors)>=1,"Curves are too big for the path") [ for(i=[0:len(points)-1]) each dk[i][0] == 0 ? [points[i]] : curve=="smooth" ? bezcorner(wrap_range(points,i-1,i+1), dk[i]) : circlecorner(wrap_range(points,i-1,i+1), dk[i]) ]; function bezcorner(points, parm) = let( d = parm[0], k = parm[1], prev = normalize(points[0]-points[1]), next = normalize(points[2]-points[1]), P = [points[1]+d*prev, points[1]+k*d*prev, points[1], points[1]+k*d*next, points[1]+d*next]) bezier_curve(P,20); function circlecorner(points, parm) = let( angle = pathangle(points)/2, d = parm[0], r = parm[1], prev = normalize(points[0]-points[1]), next = normalize(points[2]-points[1]), center = r/sin(angle) * normalize(prev+next)+points[1] ) circular_arc(center, points[1]+prev*d, points[1]+next*d, 20); function circular_arc(center, p1, p2, N) = let( angle = pathangle([p1,center,p2]), v1 = p1-center, v2 = p2-center) len(center)==2 ? let ( start = atan2(v1[1],v1[0]), end = atan2(v2[1],v2[0]), r=norm(v1)) [for(i=[0:N-1]) let(theta=(end-start)*i/(N-1)+start) r*[cos(theta),sin(theta)]+center] : let(axis = cross(v1,v2)) [for(i=[0:N-1]) matrix3_rot_by_axis(axis, i*angle/(N-1)) * v1 + center]; function bezier_curve(P,N) = [for(i=[0:N-1]) bez_point(P, i/(N-1))]; function pathangle(pts) = let( d = [for(i=[0:2]) norm(flatten(diff(wrap_range(pts,i,i+1))))] ) acos(constrain( (d[0]*d[0] + d[1]*d[1] - d[2]*d[2]) / 2 / d[0] / d[1], -1,1)); function array_subindex(vect, index) = [for(entry=vect) let(value=[for(i=index) entry[i]]) len(value)==1 ? value[0] : value]; function array_zip(vecs,v2,v3) = v3!=undef ? array_zip([vecs,v2,v3]) : v2!=undef ? array_zip([vecs,v2]) : let( length = len(vecs[0]), samesize = [for (v=vecs) len(v)==length?0:1], dummy=assert(sum(samesize)==0,"Input vectors must have the same length") ) [for(i=[0:length-1]) [for(v=vecs) each v[i]] ]; function replist(list, N) = [for(i=[0:N-1]) list]; function diff(v) = [for(i=[0:len(v)-2]) v[i+1]-v[i]]; sq = [[0,0],[2,0],[2,2],[0,2]]; polygon(roundcorners(sq, curve="circle", type="cut", all=.2)); translate([2.5,0,0])polygon(roundcorners(sq, all=[.2,.5], curve="smooth", type="cut")); -- Sent from: http://forum.openscad.org/
A
adrianv
Sun, Mar 17, 2019 3:43 AM

This may be more graphs than anyone wants to look at, but I did an analysis
of order 5 smoothing to see if it presented any obvious benefits.  Since
there are now two parameters, it's more to look at.  I'm defining has h1 the
location of P1 and P4 as the fraction of the distance away from the apex
towards P0 and P5, and I define h2 as the fractional distance from the apex
to P1 or P4.

http://forum.openscad.org/file/t2477/case1.png
http://forum.openscad.org/file/t2477/case2.png
http://forum.openscad.org/file/t2477/case3.png
http://forum.openscad.org/file/t2477/case4.png
http://forum.openscad.org/file/t2477/case5.png

In this case, unlike the previous plot the curvatures are calculated for the
scaled roundovers that are shown on the left side.  It looks to me like
the cases h2=0.5 and maybe h2=0.7 are the most promising, so focusing on
those and comparing to the order 4 case I have the following:

http://forum.openscad.org/file/t2477/order4.png
http://forum.openscad.org/file/t2477/order5_case1.png
http://forum.openscad.org/file/t2477/order5_case2.png

After examining these various plots I am hard pressed to see an obvious
benefit to using order 5.  There is only one matter left to consider.  It
turns out that if you like h2=0.7 you may be able to achieve a roundover in
a shorter space by using order 5.  But note that this is only true for h1
values above about 0.4.  If h1 gets small then order 4 is much more
efficient.

http://forum.openscad.org/file/t2477/size.png

Here is a comparison of a few selected "nice" looking parameter sets, where
d gives the location of p0 relative to the apex (so smaller is better).

http://forum.openscad.org/file/t2477/compare.png

So maybe the argument could be made for the blue curve, which gives d 5%
smaller than the next best option.  But really it's not much difference.
Again, it seems hard to justify using 5th order, and especially with the
worsening behavior as the h1 parameter shrinks.

So have I beat this to death yet?

--
Sent from: http://forum.openscad.org/

This may be more graphs than anyone wants to look at, but I did an analysis of order 5 smoothing to see if it presented any obvious benefits. Since there are now two parameters, it's more to look at. I'm defining has h1 the location of P1 and P4 as the fraction of the distance away from the apex towards P0 and P5, and I define h2 as the fractional distance from the apex to P1 or P4. <http://forum.openscad.org/file/t2477/case1.png> <http://forum.openscad.org/file/t2477/case2.png> <http://forum.openscad.org/file/t2477/case3.png> <http://forum.openscad.org/file/t2477/case4.png> <http://forum.openscad.org/file/t2477/case5.png> In this case, unlike the previous plot the curvatures are calculated for the *scaled* roundovers that are shown on the left side. It looks to me like the cases h2=0.5 and maybe h2=0.7 are the most promising, so focusing on those and comparing to the order 4 case I have the following: <http://forum.openscad.org/file/t2477/order4.png> <http://forum.openscad.org/file/t2477/order5_case1.png> <http://forum.openscad.org/file/t2477/order5_case2.png> After examining these various plots I am hard pressed to see an obvious benefit to using order 5. There is only one matter left to consider. It turns out that if you like h2=0.7 you may be able to achieve a roundover in a shorter space by using order 5. But note that this is only true for h1 values above about 0.4. If h1 gets small then order 4 is much more efficient. <http://forum.openscad.org/file/t2477/size.png> Here is a comparison of a few selected "nice" looking parameter sets, where d gives the location of p0 relative to the apex (so smaller is better). <http://forum.openscad.org/file/t2477/compare.png> So maybe the argument could be made for the blue curve, which gives d 5% smaller than the next best option. But really it's not much difference. Again, it seems hard to justify using 5th order, and especially with the worsening behavior as the h1 parameter shrinks. So have I beat this to death yet? -- Sent from: http://forum.openscad.org/
A
adrianv
Mon, Mar 18, 2019 4:25 PM

adrianv wrote

So have I beat this to death yet?

I realized that the curvature plots should really be done as arc-length vs
curvature instead of Bezier parameter vs curvature.  The curves with larger
parameter value have parameterizations that move very slowly near the end
points, so my previous plots underestimate the slope of the curvature there.
Also plotting based on arc-length makes it easier to understand the trade
off of really long curves to shorter ones.  I can post updated plots if
anybody actually wants to see them.

--
Sent from: http://forum.openscad.org/

adrianv wrote > So have I beat this to death yet? I realized that the curvature plots should really be done as arc-length vs curvature instead of Bezier parameter vs curvature. The curves with larger parameter value have parameterizations that move very slowly near the end points, so my previous plots underestimate the slope of the curvature there. Also plotting based on arc-length makes it easier to understand the trade off of really long curves to shorter ones. I can post updated plots if anybody actually wants to see them. -- Sent from: http://forum.openscad.org/
RP
Ronaldo Persiano
Mon, Mar 18, 2019 8:15 PM

I would like to see them. I would expect a parametric slow down where the
curvature is greater due to smaller norms of the parametric derivatives
there.

adrianv avm4@cornell.edu wrote:

The curves with larger
parameter value have parameterizations that move very slowly near the end
points, so my previous plots underestimate the slope of the curvature
there.
Also plotting based on arc-length makes it easier to understand the trade
off of really long curves to shorter ones.  I can post updated plots if
anybody actually wants to see them.

I would like to see them. I would expect a parametric slow down where the curvature is greater due to smaller norms of the parametric derivatives there. adrianv <avm4@cornell.edu> wrote: > > The curves with larger > parameter value have parameterizations that move very slowly near the end > points, so my previous plots underestimate the slope of the curvature > there. > Also plotting based on arc-length makes it easier to understand the trade > off of really long curves to shorter ones. I can post updated plots if > anybody actually wants to see them. >
A
adrianv
Mon, Mar 18, 2019 10:21 PM

Ronaldo wrote

I would like to see them.

Ok.  Here they are.  These are the same plots posted before, but the
curvature graph (right side) is now plotted as arc length of the bezier
curve against the curvature.  I placed the center of the bezier curve at 0
and only show half the curve, so the curves start at some negative number
equal to half their length.  Some of the curves with small h parameters are
very long indeed (up to about length 40) so I plotted everything on the same
scale and cut off some of them so it's easier to compare between graphs.  I
don't feel like the new graphs lead to any change in the conclusions.
There's not a big difference between the order 4 and order 5 curves, but the
order 5 do manage with slightly shorter lengths.  The graphs do highlight
the poor properties of the curves with h1 close to 1---worse than using a
circle in terms of smoothness due to the overshoot at the ends.  I also do
wonder how much the derivative of the curvature matters.  Will I be able to
feel the difference between cases where the curvature plot has a steeper
slope?  Or does matching curvature really suffice and seeking higher levels
of continuity is just unnecessary.  I was thinking I need to print out some
tests.  The final graph has a different scale for the curvatures to make it
easier to compare between the rather similar lines that appear on the plot.
http://forum.openscad.org/file/t2477/ncase1.png
http://forum.openscad.org/file/t2477/ncase2.png
http://forum.openscad.org/file/t2477/ncase3.png
http://forum.openscad.org/file/t2477/ncase4.png
http://forum.openscad.org/file/t2477/ncase5.png
http://forum.openscad.org/file/t2477/norder4.png
http://forum.openscad.org/file/t2477/norder5_1.png
http://forum.openscad.org/file/t2477/norder5_2.png
http://forum.openscad.org/file/t2477/ncompare.png

--
Sent from: http://forum.openscad.org/

Ronaldo wrote > I would like to see them. Ok. Here they are. These are the same plots posted before, but the curvature graph (right side) is now plotted as arc length of the bezier curve against the curvature. I placed the center of the bezier curve at 0 and only show half the curve, so the curves start at some negative number equal to half their length. Some of the curves with small h parameters are very long indeed (up to about length 40) so I plotted everything on the same scale and cut off some of them so it's easier to compare between graphs. I don't feel like the new graphs lead to any change in the conclusions. There's not a big difference between the order 4 and order 5 curves, but the order 5 do manage with slightly shorter lengths. The graphs do highlight the poor properties of the curves with h1 close to 1---worse than using a circle in terms of smoothness due to the overshoot at the ends. I also do wonder how much the derivative of the curvature matters. Will I be able to feel the difference between cases where the curvature plot has a steeper slope? Or does matching curvature really suffice and seeking higher levels of continuity is just unnecessary. I was thinking I need to print out some tests. The final graph has a different scale for the curvatures to make it easier to compare between the rather similar lines that appear on the plot. <http://forum.openscad.org/file/t2477/ncase1.png> <http://forum.openscad.org/file/t2477/ncase2.png> <http://forum.openscad.org/file/t2477/ncase3.png> <http://forum.openscad.org/file/t2477/ncase4.png> <http://forum.openscad.org/file/t2477/ncase5.png> <http://forum.openscad.org/file/t2477/norder4.png> <http://forum.openscad.org/file/t2477/norder5_1.png> <http://forum.openscad.org/file/t2477/norder5_2.png> <http://forum.openscad.org/file/t2477/ncompare.png> -- Sent from: http://forum.openscad.org/