discuss@lists.openscad.org

OpenSCAD general discussion Mailing-list

View all threads

Rounded Polygon

I
irevdev
Sat, Jul 22, 2017 12:35 PM

Hi all,

Just sharing a tool that I think is pretty useful for rounding the points on
a polygon. The idea is that along with the list of coordinates that you
would normally pass to polygon(), a list of radii is also given and they are
used to round the corners at each of the coordinates.

http://forum.openscad.org/file/n21897/PolyRoundexample1.png

code here
https://github.com/Irev-Dev/Round-Anything/blob/master/polyround.scad

I normally design SCAD things mostly with primitives, but I always get
frustrated when it comes to adding fillets later (internal radii in
particular), I'm going to try and design things from now on by extruding
these rounded polygons (where practical).

--
View this message in context: http://forum.openscad.org/Rounded-Polygon-tp21897.html
Sent from the OpenSCAD mailing list archive at Nabble.com.

Hi all, Just sharing a tool that I think is pretty useful for rounding the points on a polygon. The idea is that along with the list of coordinates that you would normally pass to polygon(), a list of radii is also given and they are used to round the corners at each of the coordinates. <http://forum.openscad.org/file/n21897/PolyRoundexample1.png> code here <https://github.com/Irev-Dev/Round-Anything/blob/master/polyround.scad> I normally design SCAD things mostly with primitives, but I always get frustrated when it comes to adding fillets later (internal radii in particular), I'm going to try and design things from now on by extruding these rounded polygons (where practical). -- View this message in context: http://forum.openscad.org/Rounded-Polygon-tp21897.html Sent from the OpenSCAD mailing list archive at Nabble.com.
T
TLC123
Sat, Jul 22, 2017 2:20 PM

Oh Yes this will be used extensively , i assure you.

--
View this message in context: http://forum.openscad.org/Rounded-Polygon-tp21897p21903.html
Sent from the OpenSCAD mailing list archive at Nabble.com.

Oh Yes this will be used extensively , i assure you. -- View this message in context: http://forum.openscad.org/Rounded-Polygon-tp21897p21903.html Sent from the OpenSCAD mailing list archive at Nabble.com.
I
irevdev
Sat, Jul 22, 2017 9:36 PM

Good to hear :)

I forgot to add, one current issue is that if three consecutive points are
col-linear it breaks :/
It's probably easy to fix, I've just hit a wall in motivation.

--
View this message in context: http://forum.openscad.org/Rounded-Polygon-tp21897p21904.html
Sent from the OpenSCAD mailing list archive at Nabble.com.

Good to hear :) I forgot to add, one current issue is that if three consecutive points are col-linear it breaks :/ It's probably easy to fix, I've just hit a wall in motivation. -- View this message in context: http://forum.openscad.org/Rounded-Polygon-tp21897p21904.html Sent from the OpenSCAD mailing list archive at Nabble.com.
T
TLC123
Sun, Jul 23, 2017 8:21 AM

Yeah i get some runaway error too. Not sure if its the same issue though.
Co-linearity is easily fixed in function round3points.
if more tha 98% collinear just return input back as is.
swap the end of round3points to:

swapout:for:
I think my issue occur when radius for p2 dont fit between p1 -p3.
Maybe that should be left to be expected
or limited so the arc never can go outside the three points?
Also i probably will use [x,y,r], format points in my trials.
Easy enough to separate them before calling polyRound.
Any reason you selected against that?
Thanks again for a great module that will com to much use. Not least with
sweeps.
http://forum.openscad.org/file/n21908/100.jpg

--
View this message in context: http://forum.openscad.org/Rounded-Polygon-tp21897p21908.html
Sent from the OpenSCAD mailing list archive at Nabble.com.

Yeah i get some runaway error too. Not sure if its the same issue though. Co-linearity is easily fixed in function round3points. if more tha 98% collinear just return input back as is. swap the end of round3points to: swapout:for: I think my issue occur when radius for p2 dont fit between p1 -p3. Maybe that should be left to be expected or limited so the arc never can go outside the three points? Also i probably will use [x,y,r], format points in my trials. Easy enough to separate them before calling polyRound. Any reason you selected against that? Thanks again for a great module that will com to much use. Not least with sweeps. <http://forum.openscad.org/file/n21908/100.jpg> -- View this message in context: http://forum.openscad.org/Rounded-Polygon-tp21897p21908.html Sent from the OpenSCAD mailing list archive at Nabble.com.
I
irevdev
Sun, Jul 23, 2017 12:00 PM

TLC123 wrote

Co-linearity is easily fixed in function round3points.
if more tha 98% collinear just return input back as is.
swap the end of round3points to:

swapout:

for:

Thanks for having a look at the co-linearity problem. I've only had a quick
look at your code now before bed so I mightn't understand it properly but I
would think that if you test for co-linearity and the result is true, then
you should return nothing and move onto the next set. My thought experiment
is that if there are 5 points where points 2 , 3 and 4 are co-linear,
processing points 1,2&3 together is fine likewise so is 3,4&5. If we just
skip processing points 2,3&4 it should be fine. Returning the original three
points might cause problems, I'll have a look at it though later.

TLC123 wrote

I think my issue occur when radius for p2 dont fit between p1 -p3.
Maybe that should be left to be expected
or limited so the arc never can go outside the three points?

Your suggestion to limit the arc to stay within the three points, I'm
thinking out loud now, at first I thought I wouldn't work, but now I think
it could potentially work if instead of just processing the list of points
three at a time like it is currently p[i],p[i+1],p[i+2] instead it grabs the
last point from the previous arc so  arcpoints[last point of last
arc],p[i+1],p[i+2]. it would have to do something different on the first and
last iteration of the for loop, but that's seem like a nice simple solution.

TLC123 wrote

Also i probably will use [x,y,r], format points in my trials.

Easy enough to separate them before calling polyRound.
Any reason you selected against that?
Thanks again for a great module that will com to much use. Not least with
sweeps.

In terms of the format [[x,y,r],[x,y,r],etc], I think you're right, I think
it's better. I posted this code as soon at it was mostly working so I
haven't actually used it for anything other than the examples, but trying to
implement it today on an actual project of mine I found it confusing as to
which radius lined up with which point on the polygon. So I think I'll make
this change, but with any of those three things, feel free to make a pull
request.

I'll have a closer look at your code soon, though probably not until
Tuesday, I'm busy tomorrow.

--
View this message in context: http://forum.openscad.org/Rounded-Polygon-tp21897p21909.html
Sent from the OpenSCAD mailing list archive at Nabble.com.

TLC123 wrote > Co-linearity is easily fixed in function round3points. > if more tha 98% collinear just return input back as is. > swap the end of round3points to: > > swapout: > for: Thanks for having a look at the co-linearity problem. I've only had a quick look at your code now before bed so I mightn't understand it properly but I would think that if you test for co-linearity and the result is true, then you should return nothing and move onto the next set. My thought experiment is that if there are 5 points where points 2 , 3 and 4 are co-linear, processing points 1,2&3 together is fine likewise so is 3,4&5. If we just skip processing points 2,3&4 it should be fine. Returning the original three points might cause problems, I'll have a look at it though later. TLC123 wrote > I think my issue occur when radius for p2 dont fit between p1 -p3. > Maybe that should be left to be expected > or limited so the arc never can go outside the three points? Your suggestion to limit the arc to stay within the three points, I'm thinking out loud now, at first I thought I wouldn't work, but now I think it could potentially work if instead of just processing the list of points three at a time like it is currently p[i],p[i+1],p[i+2] instead it grabs the last point from the previous arc so arcpoints[last point of last arc],p[i+1],p[i+2]. it would have to do something different on the first and last iteration of the for loop, but that's seem like a nice simple solution. TLC123 wrote > Also i probably will use [x,y,r], format points in my trials. > > Easy enough to separate them before calling polyRound. > Any reason you selected against that? > Thanks again for a great module that will com to much use. Not least with > sweeps. In terms of the format [[x,y,r],[x,y,r],etc], I think you're right, I think it's better. I posted this code as soon at it was mostly working so I haven't actually used it for anything other than the examples, but trying to implement it today on an actual project of mine I found it confusing as to which radius lined up with which point on the polygon. So I think I'll make this change, but with any of those three things, feel free to make a pull request. I'll have a closer look at your code soon, though probably not until Tuesday, I'm busy tomorrow. -- View this message in context: http://forum.openscad.org/Rounded-Polygon-tp21897p21909.html Sent from the OpenSCAD mailing list archive at Nabble.com.
D
droftarts
Sun, Jul 23, 2017 2:51 PM

TLC123 wrote

Also i probably will use [x,y,r], format points in my trials.
<br>
Easy enough to separate them before calling polyRound.
<br>
Any reason you selected against that?
<br>

Probably so he could draw the original polygon easily, independently of the
script, for testing.

The main reason I started the other script was to enable CSG export to
FreeCAD and then into Fusion 360, as this couldn't be done using hull (read
the thread  here
http://forum.openscad.org/Script-to-replicate-hull-and-minkoswki-for-CSG-export-import-into-FreeCAD-td16537.html
). This meant that circles and arcs keep their definition, rather than being
broken up into a mesh. Your script does seem to create a mesh, ie arcs are
broken up into straight segments, so it doesn't maintain the geometry of
circles when you import it into FreeCAD.

Unlike the other script, the points don't have to go around in a clockwise
order with yours, which is nice.

Ian

--
View this message in context: http://forum.openscad.org/Rounded-Polygon-tp21897p21910.html
Sent from the OpenSCAD mailing list archive at Nabble.com.

TLC123 wrote > Also i probably will use [x,y,r], format points in my trials. > <br> > Easy enough to separate them before calling polyRound. > <br> > Any reason you selected against that? > <br> Probably so he could draw the original polygon easily, independently of the script, for testing. The main reason I started the other script was to enable CSG export to FreeCAD and then into Fusion 360, as this couldn't be done using hull (read the thread here <http://forum.openscad.org/Script-to-replicate-hull-and-minkoswki-for-CSG-export-import-into-FreeCAD-td16537.html> ). This meant that circles and arcs keep their definition, rather than being broken up into a mesh. Your script does seem to create a mesh, ie arcs are broken up into straight segments, so it doesn't maintain the geometry of circles when you import it into FreeCAD. Unlike the other script, the points don't have to go around in a clockwise order with yours, which is nice. Ian -- View this message in context: http://forum.openscad.org/Rounded-Polygon-tp21897p21910.html Sent from the OpenSCAD mailing list archive at Nabble.com.
D
droftarts
Sun, Jul 23, 2017 3:21 PM

Thinking about it, an approach that is somewhere between the two scripts
might be the best of both. Take the initial polygon, calculate the tangent
points between each three points and the radius, redraw the polygon without
the middle point but with the tangent points, then union or difference the
circle from it. This would give you the same shape as your version, but
constructed from a polygon with unioned or differenced circles, like my
version. This would mean on CSG export that it would maintain it's geometry,
rather than being converted to a mesh, so can be opened in other CAD
software as a solid body, rather than a mesh.

Ian

--
View this message in context: http://forum.openscad.org/Rounded-Polygon-tp21897p21911.html
Sent from the OpenSCAD mailing list archive at Nabble.com.

Thinking about it, an approach that is somewhere between the two scripts might be the best of both. Take the initial polygon, calculate the tangent points between each three points and the radius, redraw the polygon without the middle point but with the tangent points, then union or difference the circle from it. This would give you the same shape as your version, but constructed from a polygon with unioned or differenced circles, like my version. This would mean on CSG export that it would maintain it's geometry, rather than being converted to a mesh, so can be opened in other CAD software as a solid body, rather than a mesh. Ian -- View this message in context: http://forum.openscad.org/Rounded-Polygon-tp21897p21911.html Sent from the OpenSCAD mailing list archive at Nabble.com.
K
KeithSloan52
Sun, Jul 23, 2017 4:35 PM

There seem's to be some miss understandings about FreeCAD's import of SCAD
and CSG files.

  1. FreeCAD does try and support hull and minkowski requests. For it to work
    FreeCAD must be able to find the OpenSCAD executable. The path to the
    OpenSCAD executable is an option of the OpenSCAD work bench. ( It can be
    very slow.)

  2. For hull & minkowski to work with 2D objects the option to allow FreeCAD
    to download and update DXF libraries must be enabled see general
    import/export preference, The downloadable library is in general no longer
    used by FreeCAD but IS used by importCSG for hull & Minkowski requests
    involving 2D objects. There was a bug with LWPOLYINE in the DXF library that
    has not long been fixed.

  3. polyhedron should also be supported, but again there was a bug until
    recently.

So if you have problems then please try the latest 0.17 version and if
still, problems please report in the FreeCAD forum.

--
View this message in context: http://forum.openscad.org/Rounded-Polygon-tp21897p21912.html
Sent from the OpenSCAD mailing list archive at Nabble.com.

There seem's to be some miss understandings about FreeCAD's import of SCAD and CSG files. 1) FreeCAD does try and support hull and minkowski requests. For it to work FreeCAD must be able to find the OpenSCAD executable. The path to the OpenSCAD executable is an option of the OpenSCAD work bench. ( It can be very slow.) 2) For hull & minkowski to work with 2D objects the option to allow FreeCAD to download and update DXF libraries must be enabled see general import/export preference, The downloadable library is in general no longer used by FreeCAD but IS used by importCSG for hull & Minkowski requests involving 2D objects. There was a bug with LWPOLYINE in the DXF library that has not long been fixed. 3) polyhedron should also be supported, but again there was a bug until recently. So if you have problems then please try the latest 0.17 version and if still, problems please report in the FreeCAD forum. -- View this message in context: http://forum.openscad.org/Rounded-Polygon-tp21897p21912.html Sent from the OpenSCAD mailing list archive at Nabble.com.
I
irevdev
Sun, Jul 23, 2017 7:26 PM

droftarts wrote

Thinking about it, an approach that is somewhere between the two scripts
might be the best of both. Take the initial polygon, calculate the tangent
points between each three points and the radius, redraw the polygon
without the middle point but with the tangent points, then union or
difference the circle from it. This would give you the same shape as your
version, but constructed from a polygon with unioned or differenced
circles, like my version. This would mean on CSG export that it would
maintain it's geometry, rather than being converted to a mesh, so can be
opened in other CAD software as a solid body, rather than a mesh.

Ian

Hi Ian,

short answer is if you use fn of 1 with my code it will draw the polygon
along all the tangent points only.

This was my initial approach, but I dumped it when I realised if you wanted
to have a relatively large radius compare to the overall size of the shape
than unioning it with a circle would mean the circle would take over. ie the
radius of 10 in the example, a circle that big would be bigger than most of
the shape. I thought it could be fixed by cutting the circle down before it
got unioned but at that point it seemed drawing points of the circle would
be easier.

If you wanted go back to this like I said you can use fn of 1 or you could
modify the round3points() function so that instead of passing the tangent
points and circle center to CentreN2PointsArc() it just returns these values
instead, that way you would also have the coordinates of the circle center
for the circle unioning.

--
View this message in context: http://forum.openscad.org/Rounded-Polygon-tp21897p21913.html
Sent from the OpenSCAD mailing list archive at Nabble.com.

droftarts wrote > Thinking about it, an approach that is somewhere between the two scripts > might be the best of both. Take the initial polygon, calculate the tangent > points between each three points and the radius, redraw the polygon > without the middle point but with the tangent points, then union or > difference the circle from it. This would give you the same shape as your > version, but constructed from a polygon with unioned or differenced > circles, like my version. This would mean on CSG export that it would > maintain it's geometry, rather than being converted to a mesh, so can be > opened in other CAD software as a solid body, rather than a mesh. > > Ian Hi Ian, short answer is if you use fn of 1 with my code it will draw the polygon along all the tangent points only. This was my initial approach, but I dumped it when I realised if you wanted to have a relatively large radius compare to the overall size of the shape than unioning it with a circle would mean the circle would take over. ie the radius of 10 in the example, a circle that big would be bigger than most of the shape. I thought it could be fixed by cutting the circle down before it got unioned but at that point it seemed drawing points of the circle would be easier. If you wanted go back to this like I said you can use fn of 1 or you could modify the round3points() function so that instead of passing the tangent points and circle center to CentreN2PointsArc() it just returns these values instead, that way you would also have the coordinates of the circle center for the circle unioning. -- View this message in context: http://forum.openscad.org/Rounded-Polygon-tp21897p21913.html Sent from the OpenSCAD mailing list archive at Nabble.com.
D
droftarts
Sun, Jul 23, 2017 9:37 PM

Ah yes, I see the problem, and now I try it, the other script has this
problem too. Though it probably shows how often it's a problem, as neither I
nor anyone else has noticed it before! Thanks for the extra info, I'll take
a look.

Keith: I'd like to see some examples of what FreeCad can import correctly
from OpenSCAD, but I think that belongs in another thread, rather than
hijack this one!

Ian

--
View this message in context: http://forum.openscad.org/Rounded-Polygon-tp21897p21914.html
Sent from the OpenSCAD mailing list archive at Nabble.com.

Ah yes, I see the problem, and now I try it, the other script has this problem too. Though it probably shows how often it's a problem, as neither I nor anyone else has noticed it before! Thanks for the extra info, I'll take a look. Keith: I'd like to see some examples of what FreeCad can import correctly from OpenSCAD, but I think that belongs in another thread, rather than hijack this one! Ian -- View this message in context: http://forum.openscad.org/Rounded-Polygon-tp21897p21914.html Sent from the OpenSCAD mailing list archive at Nabble.com.
RP
Ronaldo Persiano
Sun, Jul 23, 2017 11:02 PM

2017-07-23 5:21 GMT-03:00 TLC123 torleif.ceder@gmail.com:

I think my issue occur when radius for p2 dont fit between p1 -p3.
Maybe that should be left to be expected
or limited so the arc never can go outside the three points?

The issue is not restricted to that extreme cases. It is enough to have
tangent points in an edge in reversed order.

module test2(size,r) {
p = [ [0,0], [size,0],[size,size],[0,size] ];
polygon( polyRound(p,r,10));
translate([0,0,-1])%polygon(p);
}

test2(100,[80,20,30,50]);

If polyRound is recoded to identify those cases, either ​it should do
nothing or reduce some radiuses. Unhapilly, the radius reduction problem
has usually many solutions.

2017-07-23 5:21 GMT-03:00 TLC123 <torleif.ceder@gmail.com>: > I think my issue occur when radius for p2 dont fit between p1 -p3. > Maybe that should be left to be expected > or limited so the arc never can go outside the three points? > > The issue is not restricted to that extreme cases. It is enough to have tangent points in an edge in reversed order. module test2(size,r) { p = [ [0,0], [size,0],[size,size],[0,size] ]; polygon( polyRound(p,r,10)); translate([0,0,-1])%polygon(p); } test2(100,[80,20,30,50]); If polyRound is recoded to identify those cases, either ​it should do nothing or reduce some radiuses. Unhapilly, the radius reduction problem has usually many solutions.
P
Parkinbot
Mon, Jul 24, 2017 8:52 AM

As Ronaldo mentioned it is not straight forward to deal with conflicting
radii. But, even a robust implemention will be quite difficult, this
function is a nice-to-have if handled with care.

Here is my implementation of it. It uses $fs to control arc graining and
seems to be semantically equivalents for the rest:

$fs=.2;  // graining

b=[[-5,0],[5,3],[0,7],[8,7],[20,20],[10,0]]; //points
br=[1,    1.5,  1,  10,    1.5,    5]; //radiuses
polygon(polyRound(b,br));
%translate([0,0,0.2])polygon(b);

p=[[0,0],[0,20],[15,15],[3,10],[15,0],[6,2]];//points
pr=[2,    4,      3,    3,      1,  8];//radiuses
translate([25,0,0])polygon(polyRound(p,pr,$fs=.4));
%translate([25,0,0.2])polygon(p);

function polyRound(b, r) = [for(i = [0:len(b)-1]) each tri(b, i,
r[(i+1)%len(b)])];

function tri(L,i, r) = let(N=len(L)) // uses $fs
let(A = L[i]) let(B=L[(i+1)%N], C=L[(i+2)%N])                  //
points
let(a = (A-B)/norm((A-B)), b = (C-B)/norm((C-B)))              //
vectors
let(a_= [-a[1], a[0]], b_=[b[1],-b[0]])                        //
normals
let(m = r*(b_-a_),k=(a[0]m[1]-a[1]m[0])/(b[0]a[1]-b[1]a[0])) //
equation stuff
let(s = sign(k), w = 2
atn([r,s
k]), w0 = atn(-s
a_))          //
angles
let(n = round(abs(r
w/180PI)/$fs), M = B+ska+sra_)        //
middle point
[for(z = [w0:-s
w/(n+1):w0-sw-s.0001]) M+r*[cos(z), sin(z)]]; // arc

// full circle atan
function atn(X) = let(w = X[0]==0?X[1]<0?270:90:atan(X[1]/X[0]))
X[0]<0?180+w:(w+360)%360;

--
View this message in context: http://forum.openscad.org/Rounded-Polygon-tp21897p21928.html
Sent from the OpenSCAD mailing list archive at Nabble.com.

As Ronaldo mentioned it is not straight forward to deal with conflicting radii. But, even a robust implemention will be quite difficult, this function is a nice-to-have if handled with care. Here is my implementation of it. It uses $fs to control arc graining and seems to be semantically equivalents for the rest: > $fs=.2; // graining > > b=[[-5,0],[5,3],[0,7],[8,7],[20,20],[10,0]]; //points > br=[1, 1.5, 1, 10, 1.5, 5]; //radiuses > polygon(polyRound(b,br)); > %translate([0,0,0.2])polygon(b); > > p=[[0,0],[0,20],[15,15],[3,10],[15,0],[6,2]];//points > pr=[2, 4, 3, 3, 1, 8];//radiuses > translate([25,0,0])polygon(polyRound(p,pr,$fs=.4)); > %translate([25,0,0.2])polygon(p); > > function polyRound(b, r) = [for(i = [0:len(b)-1]) each tri(b, i, > r[(i+1)%len(b)])]; > > function tri(L,i, r) = let(N=len(L)) // uses $fs > let(A = L[i]) let(B=L[(i+1)%N], C=L[(i+2)%N]) // > points > let(a = (A-B)/norm((A-B)), b = (C-B)/norm((C-B))) // > vectors > let(a_= [-a[1], a[0]], b_=[b[1],-b[0]]) // > normals > let(m = r*(b_-a_),k=(a[0]*m[1]-a[1]*m[0])/(b[0]*a[1]-b[1]*a[0])) // > equation stuff > let(s = sign(k), w = 2*atn([r,s*k]), w0 = atn(-s*a_)) // > angles > let(n = round(abs(r*w/180*PI)/$fs), M = B+s*k*a+s*r*a_) // > middle point > [for(z = [w0:-s*w/(n+1):w0-s*w-s*.0001]) M+r*[cos(z), sin(z)]]; // arc > > // full circle atan > function atn(X) = let(w = X[0]==0?X[1]<0?270:90:atan(X[1]/X[0])) > X[0]<0?180+w:(w+360)%360; -- View this message in context: http://forum.openscad.org/Rounded-Polygon-tp21897p21928.html Sent from the OpenSCAD mailing list archive at Nabble.com.
T
TLC123
Thu, Jul 27, 2017 4:15 AM

I made some experiments in a fork on github. Don't know if I posted it
correctly, very unused to github.
First version dealt with the collinear case and radius zero case.
Next i clamped tangD value to be inside either leg of the triangle.

Now I'm working on reducing radius
if tangD +tangD of previous point is larger than the length of the leg or
tangD +tangD of following points is larger than the length of the following
leg.

Then
Mutiply radius by the proportional amount of that  oversize.
And repeat for all points.
If no changes occured done else retry recursive with new set of radii.
Currently working but a bit to eagerly with reducing radius. I think I know
what part of logic that needs change and I will deal with it as soon as
possible

--
View this message in context: http://forum.openscad.org/Rounded-Polygon-tp21897p21945.html
Sent from the OpenSCAD mailing list archive at Nabble.com.

I made some experiments in a fork on github. Don't know if I posted it correctly, very unused to github. First version dealt with the collinear case and radius zero case. Next i clamped tangD value to be inside either leg of the triangle. Now I'm working on reducing radius if tangD +tangD of previous point is larger than the length of the leg or tangD +tangD of following points is larger than the length of the following leg. Then Mutiply radius by the proportional amount of that oversize. And repeat for all points. If no changes occured done else retry recursive with new set of radii. Currently working but a bit to eagerly with reducing radius. I think I know what part of logic that needs change and I will deal with it as soon as possible -- View this message in context: http://forum.openscad.org/Rounded-Polygon-tp21897p21945.html Sent from the OpenSCAD mailing list archive at Nabble.com.
P
Parkinbot
Fri, Jul 28, 2017 11:15 AM

TLC123 wrote

Mutiply radius by the proportional amount of that  oversize.
And repeat for all points.

Are you sure, it isn't better to report an error, instead of doing a silent
repair?

--
View this message in context: http://forum.openscad.org/Rounded-Polygon-tp21897p21948.html
Sent from the OpenSCAD mailing list archive at Nabble.com.

TLC123 wrote > Mutiply radius by the proportional amount of that oversize. > And repeat for all points. Are you sure, it isn't better to report an error, instead of doing a silent repair? -- View this message in context: http://forum.openscad.org/Rounded-Polygon-tp21897p21948.html Sent from the OpenSCAD mailing list archive at Nabble.com.
T
TLC123
Tue, Aug 1, 2017 10:10 AM

Report what radius have been corrected by how much and have a
option to autofix or not?

--
View this message in context: http://forum.openscad.org/Rounded-Polygon-tp21897p21982.html
Sent from the OpenSCAD mailing list archive at Nabble.com.

Report what radius have been corrected by how much and have a option to autofix or not? -- View this message in context: http://forum.openscad.org/Rounded-Polygon-tp21897p21982.html Sent from the OpenSCAD mailing list archive at Nabble.com.
I
irevdev
Tue, Aug 1, 2017 12:41 PM

I've got a pretty big update to the polyRound() code, some general tidying,
improvements and new features, mostly notably radii conflict handling.  link
here again, if you don't want to scroll up
https://github.com/Irev-Dev/Round-Anything
First a big thank you to TLC123 who's made a substantial contribution.

So the interface of the function has changed, instead of taking two separate
lists for points and radii, it takes one list where each point takes the
format [x,y,r]. TLC suggested it and it seems more intuitive to me.
http://forum.openscad.org/file/n21983/example1.png
The radii conflict handling works by reducing two conflicting radii by a
factor, this means that the two will keep there ratios, for example if two
conflicting radii of 30 and 30 would be reduced to 10 and 10, but
conflicting radii of 10 and 40 might be reduced to 4 and 16, ie 30/30=10/10
and 10/40=4/16. There is no way to explain how it does this with out drawing
something, so here are some pictures.
http://forum.openscad.org/file/n21983/formulas.png
Not sure how well that image will turn out, here is a link for it
https://github.com/Irev-Dev/Round-Anything/blob/master/images/formulas.png
It's not the perfect solution but I'm happy with it for now as it seems
pretty robust and isn't too complicated.

For those who don't want radii conflict handling polycarious() has no
protection built in. So as it stands the radii conflict handling is not an
option within the same function? should I make it enable/disable-able within
one function?

One problem with the radii conflict handling is if you were to have 3
consecutive radii, where the 1st and 2nd radii conflict a lot and the 2nd
and 3rd conflict but less so, what will happen is that the 2nd radii will
reduce enough for the worst case which is the 1st and 2nd radii conflict.
The problem here is that with the second radius reducing, once it has been
reduced it may no longer conflict with the 3rd radius, and therefore the 3rd
radius it may not need to be reduced, but the code doesn't check for this
and so the 3rd radius will be reduced as if the original conflicting 2nd
radius were still there.
Trying to fix this would be difficult because how would it be handled? would
you go through the array in order giving the first point priority? or do you
write logic so that it reduces the radii at the worst conflict and then the
2nd worst, 3rd etc?
I think it's fine as it is because I think the radii reduction should not be
relied on in the first place, I did included a debugging option that will
tell you if any of the radii have been reduced because of a conflict. see
some of the examples.

--
View this message in context: http://forum.openscad.org/Rounded-Polygon-tp21897p21983.html
Sent from the OpenSCAD mailing list archive at Nabble.com.

I've got a pretty big update to the polyRound() code, some general tidying, improvements and new features, mostly notably radii conflict handling. link here again, if you don't want to scroll up <https://github.com/Irev-Dev/Round-Anything> First a big thank you to TLC123 who's made a substantial contribution. So the interface of the function has changed, instead of taking two separate lists for points and radii, it takes one list where each point takes the format [x,y,r]. TLC suggested it and it seems more intuitive to me. <http://forum.openscad.org/file/n21983/example1.png> The radii conflict handling works by reducing two conflicting radii by a factor, this means that the two will keep there ratios, for example if two conflicting radii of 30 and 30 would be reduced to 10 and 10, but conflicting radii of 10 and 40 might be reduced to 4 and 16, ie 30/30=10/10 and 10/40=4/16. There is no way to explain how it does this with out drawing something, so here are some pictures. <http://forum.openscad.org/file/n21983/formulas.png> Not sure how well that image will turn out, here is a link for it <https://github.com/Irev-Dev/Round-Anything/blob/master/images/formulas.png> It's not the perfect solution but I'm happy with it for now as it seems pretty robust and isn't too complicated. For those who don't want radii conflict handling polycarious() has no protection built in. So as it stands the radii conflict handling is not an option within the same function? should I make it enable/disable-able within one function? One problem with the radii conflict handling is if you were to have 3 consecutive radii, where the 1st and 2nd radii conflict a lot and the 2nd and 3rd conflict but less so, what will happen is that the 2nd radii will reduce enough for the worst case which is the 1st and 2nd radii conflict. The problem here is that with the second radius reducing, once it has been reduced it may no longer conflict with the 3rd radius, and therefore the 3rd radius it may not need to be reduced, but the code doesn't check for this and so the 3rd radius will be reduced as if the original conflicting 2nd radius were still there. Trying to fix this would be difficult because how would it be handled? would you go through the array in order giving the first point priority? or do you write logic so that it reduces the radii at the worst conflict and then the 2nd worst, 3rd etc? I think it's fine as it is because I think the radii reduction should not be relied on in the first place, I did included a debugging option that will tell you if any of the radii have been reduced because of a conflict. see some of the examples. -- View this message in context: http://forum.openscad.org/Rounded-Polygon-tp21897p21983.html Sent from the OpenSCAD mailing list archive at Nabble.com.
A
adrianv
Mon, Mar 11, 2019 5:12 PM

I really like this capability and have been examining the code, thinking it
would be desirable to have a cleaned up version (which I'm willing to work
to produce).  It seems like it would be nice to change the interface a bit,
to eliminate the cryptic numeric "mode" and replace it either with booleans,
(return_adjustments=true/false, allow_conflicts=true/false) or with text
(mode="handle_conflicts", mode="return_adjustments",
mode="allow_conflicts").  What is better?  (The word "debug" is a little
vague, but my ideas are a little long.)  Another thing that seems desirable
is making the naming systematic.  Why do I use polyround.scad to get the
polyRound module?  And is the library round-anything or Round-Anything?
(Under Linux case matters.)

The polyround.scad file contains a bunch of extra stuff, much of which is
undocumented.  I've tried to use RailCustomiser and have not really figured
it out.  Sometimes it returns nan.  I don't know why.

Also it appears that the colinearity handling in polyRound has a bug, namely
that it doesn't do anything at all.  The code is:

p=getpoints(radiipoints), //make list of coordinates without radii
Lp=len(p),
//remove the middle point of any three colinear points
newrp=[
  for(i=[0:len(p)-1])

if(isColinear(p[wrap(i-1,Lp)],p[wrap(i+0,Lp)],p[wrap(i+1,Lp)])==0*||p[wrap(i+0,Lp)].z!=0*)radiipoints[wrap(i+0,Lp)]
],

and the second part of the test is always true because p[i].z==undef, so you
never delete any points.  I tried deleting that second part of the test and
that appears to fix it.  Have I missed something here?  Is there some
reason to retain colinear points if they have a nonzero radius, which
appears to be the intention of that extra test.

I did notice that I get different results when colinear points are retained:
because there are more points, it appears that the conflict resolution
applies in my example and I get a smaller roundover than requested.  This
behavior seems undesirable.

What does processRadiiPoints do?  In the cases I've tried it on, I just get
back an output equal to the input.  Is there some other way to specify the
radius of rounding than a direct value?

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

I really like this capability and have been examining the code, thinking it would be desirable to have a cleaned up version (which I'm willing to work to produce). It seems like it would be nice to change the interface a bit, to eliminate the cryptic numeric "mode" and replace it either with booleans, (return_adjustments=true/false, allow_conflicts=true/false) or with text (mode="handle_conflicts", mode="return_adjustments", mode="allow_conflicts"). What is better? (The word "debug" is a little vague, but my ideas are a little long.) Another thing that seems desirable is making the naming systematic. Why do I use polyround.scad to get the polyRound module? And is the library round-anything or Round-Anything? (Under Linux case matters.) The polyround.scad file contains a bunch of extra stuff, much of which is undocumented. I've tried to use RailCustomiser and have not really figured it out. Sometimes it returns nan. I don't know why. Also it appears that the colinearity handling in polyRound has a bug, namely that it doesn't do anything at all. The code is: p=getpoints(radiipoints), //make list of coordinates without radii Lp=len(p), //remove the middle point of any three colinear points newrp=[ for(i=[0:len(p)-1]) if(isColinear(p[wrap(i-1,Lp)],p[wrap(i+0,Lp)],p[wrap(i+1,Lp)])==0*||p[wrap(i+0,Lp)].z!=0*)radiipoints[wrap(i+0,Lp)] ], and the second part of the test is always true because p[i].z==undef, so you never delete any points. I tried deleting that second part of the test and that appears to fix it. Have I missed something here? Is there some reason to retain colinear points if they have a nonzero radius, which appears to be the intention of that extra test. I did notice that I get different results when colinear points are retained: because there are more points, it appears that the conflict resolution applies in my example and I get a smaller roundover than requested. This behavior seems undesirable. What does processRadiiPoints do? In the cases I've tried it on, I just get back an output equal to the input. Is there some other way to specify the radius of rounding than a direct value? -- Sent from: http://forum.openscad.org/
T
Troberg
Tue, Mar 12, 2019 6:37 AM

Here's my take on a similar subject, incidentally also named polyround. It's
not as powerful (all corners have the same radius), but it works on any 2D
object. You can select if it will affect inside corners, outside corners or
both. If you just want, say, to round the corners of a square (or some other
shape), it's simpler to use.

Known bugs is that if the radius is big enough, it might snip off narrow
parts of the object. Don't make the radius more than 2 times the narrowest
part and you'll be fine.

When I get some spare time, I'll refactor it a bit to make it cleaner (two
internal modules for inside() and outside(), so I don't need to duplicate
code).

module polyround(radius,inside=true,outside=true){
if(inside==true){
if(outside==true){
//Inside corners
offset(r=-radius)
offset(delta=radius)
//Outside corners
offset(r=radius)
offset(delta=-radius)
children();
}else{
//Inside corners
offset(r=-radius)
offset(delta=radius)
children();
}
}else{
if(outside==true){
//Outside corners
offset(r=radius)
offset(delta=-radius)
children();
}else{
children();
}
}
}

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

Here's my take on a similar subject, incidentally also named polyround. It's not as powerful (all corners have the same radius), but it works on any 2D object. You can select if it will affect inside corners, outside corners or both. If you just want, say, to round the corners of a square (or some other shape), it's simpler to use. Known bugs is that if the radius is big enough, it might snip off narrow parts of the object. Don't make the radius more than 2 times the narrowest part and you'll be fine. When I get some spare time, I'll refactor it a bit to make it cleaner (two internal modules for inside() and outside(), so I don't need to duplicate code). module polyround(radius,inside=true,outside=true){ if(inside==true){ if(outside==true){ //Inside corners offset(r=-radius) offset(delta=radius) //Outside corners offset(r=radius) offset(delta=-radius) children(); }else{ //Inside corners offset(r=-radius) offset(delta=radius) children(); } }else{ if(outside==true){ //Outside corners offset(r=radius) offset(delta=-radius) children(); }else{ children(); } } } -- Sent from: http://forum.openscad.org/
NH
nop head
Tue, Mar 12, 2019 8:37 AM

Yes I always round 2D shapes with a single radius using two or three
offsets but I haven't grouped it into a module. I don't use delta though. I
just use offset(-rad) offset(2 * rad) offset(-rad). Not sure what
difference it makes.

On Tue, 12 Mar 2019 at 06:44, Troberg troberg.anders@gmail.com wrote:

Here's my take on a similar subject, incidentally also named polyround.
It's
not as powerful (all corners have the same radius), but it works on any 2D
object. You can select if it will affect inside corners, outside corners or
both. If you just want, say, to round the corners of a square (or some
other
shape), it's simpler to use.

Known bugs is that if the radius is big enough, it might snip off narrow
parts of the object. Don't make the radius more than 2 times the narrowest
part and you'll be fine.

When I get some spare time, I'll refactor it a bit to make it cleaner (two
internal modules for inside() and outside(), so I don't need to duplicate
code).

module polyround(radius,inside=true,outside=true){
if(inside==true){
if(outside==true){
//Inside corners
offset(r=-radius)
offset(delta=radius)
//Outside corners
offset(r=radius)
offset(delta=-radius)
children();
}else{
//Inside corners
offset(r=-radius)
offset(delta=radius)
children();
}
}else{
if(outside==true){
//Outside corners
offset(r=radius)
offset(delta=-radius)
children();
}else{
children();
}
}
}

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


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

Yes I always round 2D shapes with a single radius using two or three offsets but I haven't grouped it into a module. I don't use delta though. I just use offset(-rad) offset(2 * rad) offset(-rad). Not sure what difference it makes. On Tue, 12 Mar 2019 at 06:44, Troberg <troberg.anders@gmail.com> wrote: > Here's my take on a similar subject, incidentally also named polyround. > It's > not as powerful (all corners have the same radius), but it works on any 2D > object. You can select if it will affect inside corners, outside corners or > both. If you just want, say, to round the corners of a square (or some > other > shape), it's simpler to use. > > Known bugs is that if the radius is big enough, it might snip off narrow > parts of the object. Don't make the radius more than 2 times the narrowest > part and you'll be fine. > > When I get some spare time, I'll refactor it a bit to make it cleaner (two > internal modules for inside() and outside(), so I don't need to duplicate > code). > > module polyround(radius,inside=true,outside=true){ > if(inside==true){ > if(outside==true){ > //Inside corners > offset(r=-radius) > offset(delta=radius) > //Outside corners > offset(r=radius) > offset(delta=-radius) > children(); > }else{ > //Inside corners > offset(r=-radius) > offset(delta=radius) > children(); > } > }else{ > if(outside==true){ > //Outside corners > offset(r=radius) > offset(delta=-radius) > children(); > }else{ > children(); > } > } > } > > > > -- > Sent from: http://forum.openscad.org/ > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >
T
Troberg
Tue, Mar 12, 2019 12:23 PM

Your variant does both inside and outside corners. Mine has them separated.
Apart from that, they are the same.

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

Your variant does both inside and outside corners. Mine has them separated. Apart from that, they are the same. -- Sent from: http://forum.openscad.org/
A
adrianv
Tue, Mar 12, 2019 1:33 PM

The round-anything library includes this, which rounds inside and outside
corners independently with separate rounding radii.  You can set IR or OR to
zero as desired if you want only internal or external rounding.  Looks short
and elegant to me.  Does this have some shortcomings I'm overlooking
compared to the other versions?

module round2d(OR=3,IR=1){
offset(OR){
offset(-IR-OR){
offset(IR){
children();
}
}
}
}

So this is nice for the cases that it addresses, but it doesn't address the
problem that the more general polyround does, with the possibility of
rounding only some corners, and rounding different corners by different
amounts, and doing the rounding to a point list that can be input to sweep
type operations.

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

The round-anything library includes this, which rounds inside and outside corners independently with separate rounding radii. You can set IR or OR to zero as desired if you want only internal or external rounding. Looks short and elegant to me. Does this have some shortcomings I'm overlooking compared to the other versions? module round2d(OR=3,IR=1){ offset(OR){ offset(-IR-OR){ offset(IR){ children(); } } } } So this is nice for the cases that it addresses, but it doesn't address the problem that the more general polyround does, with the possibility of rounding only some corners, and rounding different corners by different amounts, and doing the rounding to a point list that can be input to sweep type operations. -- Sent from: http://forum.openscad.org/
WA
William Adams
Tue, Mar 12, 2019 2:26 PM

Would it be possible to use this tool to get rounding as is done in some
industrial designs?

https://hackernoon.com/apples-icons-have-that-shape-for-a-very-good-reason-720d4e7c8a14

If not, could someone suggest a suitable technique to achieve this?

William

On Tue, Mar 12, 2019 at 9:40 AM adrianv avm4@cornell.edu wrote:

The round-anything library includes this, which rounds inside and outside
corners independently with separate rounding radii.  You can set IR or OR
to
zero as desired if you want only internal or external rounding.  Looks
short
and elegant to me.  Does this have some shortcomings I'm overlooking
compared to the other versions?

module round2d(OR=3,IR=1){
offset(OR){
offset(-IR-OR){
offset(IR){
children();
}
}
}
}

So this is nice for the cases that it addresses, but it doesn't address the
problem that the more general polyround does, with the possibility of
rounding only some corners, and rounding different corners by different
amounts, and doing the rounding to a point list that can be input to sweep
type operations.

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


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

Would it be possible to use this tool to get rounding as is done in some industrial designs? https://hackernoon.com/apples-icons-have-that-shape-for-a-very-good-reason-720d4e7c8a14 If not, could someone suggest a suitable technique to achieve this? William On Tue, Mar 12, 2019 at 9:40 AM adrianv <avm4@cornell.edu> wrote: > The round-anything library includes this, which rounds inside and outside > corners independently with separate rounding radii. You can set IR or OR > to > zero as desired if you want only internal or external rounding. Looks > short > and elegant to me. Does this have some shortcomings I'm overlooking > compared to the other versions? > > module round2d(OR=3,IR=1){ > offset(OR){ > offset(-IR-OR){ > offset(IR){ > children(); > } > } > } > } > > So this is nice for the cases that it addresses, but it doesn't address the > problem that the more general polyround does, with the possibility of > rounding only some corners, and rounding different corners by different > amounts, and doing the rounding to a point list that can be input to sweep > type operations. > > > > -- > Sent from: http://forum.openscad.org/ > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >
NH
nop head
Tue, Mar 12, 2019 3:06 PM

I don't thinks so because all the rounding discussed so far uses circular
arcs that meet straight lines tangentially. That is continuous in gradient
but has a discontinuity of curvature. Possibly Bezier splines would do the
job?

On Tue, 12 Mar 2019 at 14:27, William Adams will.adams@frycomm.com wrote:

Would it be possible to use this tool to get rounding as is done in some
industrial designs?

https://hackernoon.com/apples-icons-have-that-shape-for-a-very-good-reason-720d4e7c8a14

If not, could someone suggest a suitable technique to achieve this?

William

On Tue, Mar 12, 2019 at 9:40 AM adrianv avm4@cornell.edu wrote:

The round-anything library includes this, which rounds inside and outside
corners independently with separate rounding radii.  You can set IR or OR
to
zero as desired if you want only internal or external rounding.  Looks
short
and elegant to me.  Does this have some shortcomings I'm overlooking
compared to the other versions?

module round2d(OR=3,IR=1){
offset(OR){
offset(-IR-OR){
offset(IR){
children();
}
}
}
}

So this is nice for the cases that it addresses, but it doesn't address
the
problem that the more general polyround does, with the possibility of
rounding only some corners, and rounding different corners by different
amounts, and doing the rounding to a point list that can be input to sweep
type operations.

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


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

I don't thinks so because all the rounding discussed so far uses circular arcs that meet straight lines tangentially. That is continuous in gradient but has a discontinuity of curvature. Possibly Bezier splines would do the job? On Tue, 12 Mar 2019 at 14:27, William Adams <will.adams@frycomm.com> wrote: > Would it be possible to use this tool to get rounding as is done in some > industrial designs? > > > https://hackernoon.com/apples-icons-have-that-shape-for-a-very-good-reason-720d4e7c8a14 > > If not, could someone suggest a suitable technique to achieve this? > > William > > > On Tue, Mar 12, 2019 at 9:40 AM adrianv <avm4@cornell.edu> wrote: > >> The round-anything library includes this, which rounds inside and outside >> corners independently with separate rounding radii. You can set IR or OR >> to >> zero as desired if you want only internal or external rounding. Looks >> short >> and elegant to me. Does this have some shortcomings I'm overlooking >> compared to the other versions? >> >> module round2d(OR=3,IR=1){ >> offset(OR){ >> offset(-IR-OR){ >> offset(IR){ >> children(); >> } >> } >> } >> } >> >> So this is nice for the cases that it addresses, but it doesn't address >> the >> problem that the more general polyround does, with the possibility of >> rounding only some corners, and rounding different corners by different >> amounts, and doing the rounding to a point list that can be input to sweep >> type operations. >> >> >> >> -- >> Sent from: http://forum.openscad.org/ >> >> _______________________________________________ >> OpenSCAD mailing list >> Discuss@lists.openscad.org >> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >> > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >
RW
Rogier Wolff
Tue, Mar 12, 2019 5:55 PM

On Tue, Mar 12, 2019 at 03:06:43PM +0000, nop head wrote:

I don't thinks so because all the rounding discussed so far uses circular
arcs that meet straight lines tangentially. That is continuous in gradient
but has a discontinuity of curvature. Possibly Bezier splines would do the
job?

I would REALLY like to have bezier curves in openscad. The $fn parameter
would determine how many interpolation points would be used to convert the
spline to triangles.

The problem is a bit how to integrate the splines with the rest of
openscad: all primitives are 3D OBJECTS and splines usually define a
surface (in 3D if required).

We already can create an object from arbitrary 3D points, right?
(or is this only possible for 2D objects? Ah! I should know this: I
designed pyramids from 5 vertices with my niece this weekend, Duh!).

So it would suffice if a function could return a list of points (*)
corresponding to a definition of an object defined by bezier surfaces.

On the other hand, the "define bezier primitive" could internally
build on the polyhedron function: building the list-of-vertices and
faces as it processes its own input...

I think the "create bezier object" primitve would have very similar
arguments as the polyhedron primitve: A list of vertices and a list of
faces. To define a bezier patch you need precisely 16 vertices for
each patch.

Roger.

(*) Not sure if such a function can return a complex object in the
current implementation: both the list-of-points and the
list-of-vertices that define the triangles. That's be nice.

On Tue, 12 Mar 2019 at 14:27, William Adams will.adams@frycomm.com wrote:

Would it be possible to use this tool to get rounding as is done in some
industrial designs?

https://hackernoon.com/apples-icons-have-that-shape-for-a-very-good-reason-720d4e7c8a14

If not, could someone suggest a suitable technique to achieve this?

William

On Tue, Mar 12, 2019 at 9:40 AM adrianv avm4@cornell.edu wrote:

The round-anything library includes this, which rounds inside and outside
corners independently with separate rounding radii.  You can set IR or OR
to
zero as desired if you want only internal or external rounding.  Looks
short
and elegant to me.  Does this have some shortcomings I'm overlooking
compared to the other versions?

module round2d(OR=3,IR=1){
offset(OR){
offset(-IR-OR){
offset(IR){
children();
}
}
}
}

So this is nice for the cases that it addresses, but it doesn't address
the
problem that the more general polyround does, with the possibility of
rounding only some corners, and rounding different corners by different
amounts, and doing the rounding to a point list that can be input to sweep
type operations.

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


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

--
** R.E.Wolff@BitWizard.nl ** https://www.BitWizard.nl/ ** +31-15-2049110 **
**    Delftechpark 11 2628 XJ  Delft, The Netherlands.  KVK: 27239233    **
The plan was simple, like my brother-in-law Phil. But unlike
Phil, this plan just might work.

On Tue, Mar 12, 2019 at 03:06:43PM +0000, nop head wrote: > I don't thinks so because all the rounding discussed so far uses circular > arcs that meet straight lines tangentially. That is continuous in gradient > but has a discontinuity of curvature. Possibly Bezier splines would do the > job? I would REALLY like to have bezier curves in openscad. The $fn parameter would determine how many interpolation points would be used to convert the spline to triangles. The problem is a bit how to integrate the splines with the rest of openscad: all primitives are 3D OBJECTS and splines usually define a surface (in 3D if required). We already can create an object from arbitrary 3D points, right? (or is this only possible for 2D objects? Ah! I should know this: I designed pyramids from 5 vertices with my niece this weekend, Duh!). So it would suffice if a function could return a list of points (*) corresponding to a definition of an object defined by bezier surfaces. On the other hand, the "define bezier primitive" could internally build on the polyhedron function: building the list-of-vertices and faces as it processes its own input... I think the "create bezier object" primitve would have very similar arguments as the polyhedron primitve: A list of vertices and a list of faces. To define a bezier patch you need precisely 16 vertices for each patch. Roger. (*) Not sure if such a function can return a complex object in the current implementation: both the list-of-points and the list-of-vertices that define the triangles. That's be nice. > > On Tue, 12 Mar 2019 at 14:27, William Adams <will.adams@frycomm.com> wrote: > > > Would it be possible to use this tool to get rounding as is done in some > > industrial designs? > > > > > > https://hackernoon.com/apples-icons-have-that-shape-for-a-very-good-reason-720d4e7c8a14 > > > > If not, could someone suggest a suitable technique to achieve this? > > > > William > > > > > > On Tue, Mar 12, 2019 at 9:40 AM adrianv <avm4@cornell.edu> wrote: > > > >> The round-anything library includes this, which rounds inside and outside > >> corners independently with separate rounding radii. You can set IR or OR > >> to > >> zero as desired if you want only internal or external rounding. Looks > >> short > >> and elegant to me. Does this have some shortcomings I'm overlooking > >> compared to the other versions? > >> > >> module round2d(OR=3,IR=1){ > >> offset(OR){ > >> offset(-IR-OR){ > >> offset(IR){ > >> children(); > >> } > >> } > >> } > >> } > >> > >> So this is nice for the cases that it addresses, but it doesn't address > >> the > >> problem that the more general polyround does, with the possibility of > >> rounding only some corners, and rounding different corners by different > >> amounts, and doing the rounding to a point list that can be input to sweep > >> type operations. > >> > >> > >> > >> -- > >> Sent from: http://forum.openscad.org/ > >> > >> _______________________________________________ > >> OpenSCAD mailing list > >> Discuss@lists.openscad.org > >> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org > >> > > _______________________________________________ > > OpenSCAD mailing list > > Discuss@lists.openscad.org > > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org > > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org -- ** R.E.Wolff@BitWizard.nl ** https://www.BitWizard.nl/ ** +31-15-2049110 ** ** Delftechpark 11 2628 XJ Delft, The Netherlands. KVK: 27239233 ** The plan was simple, like my brother-in-law Phil. But unlike Phil, this plan just might work.
JB
Jordan Brown
Tue, Mar 12, 2019 9:30 PM

On 3/12/2019 10:55 AM, Rogier Wolff wrote:

(*) Not sure if such a function can return a complex object in the
current implementation: both the list-of-points and the
list-of-vertices that define the triangles. That's be nice.

Sure.  Just return a vector, the first element of which is a vector of
points and the second element of which is a vector of vertices.

On 3/12/2019 10:55 AM, Rogier Wolff wrote: > (*) Not sure if such a function can return a complex object in the > current implementation: both the list-of-points and the > list-of-vertices that define the triangles. That's be nice. Sure.  Just return a vector, the first element of which is a vector of points and the second element of which is a vector of vertices.
A
adrianv
Tue, Mar 12, 2019 11:07 PM

Definitely none of the rounding code I've seen does this directly.  Thanks
for bringing this to my attention.  I'm actually interested in mplementing
this myself.  Does it make sense to use tangent circles to define the
location of the curved section and then fit a bezier instead of a circular
arc into the space?  Or is there some better way to define the space where
the curve should go at a given corner?  Like perhaps a setback distance
along the edge from the corner?

nophead wrote

I don't thinks so because all the rounding discussed so far uses circular
arcs that meet straight lines tangentially. That is continuous in gradient
but has a discontinuity of curvature. Possibly Bezier splines would do the
job?

On Tue, 12 Mar 2019 at 14:27, William Adams <

will.adams@

> wrote:

Would it be possible to use this tool to get rounding as is done in some
industrial designs?

https://hackernoon.com/apples-icons-have-that-shape-for-a-very-good-reason-720d4e7c8a14

If not, could someone suggest a suitable technique to achieve this?

William

Definitely none of the rounding code I've seen does this directly. Thanks for bringing this to my attention. I'm actually interested in mplementing this myself. Does it make sense to use tangent circles to define the location of the curved section and then fit a bezier instead of a circular arc into the space? Or is there some better way to define the space where the curve should go at a given corner? Like perhaps a setback distance along the edge from the corner? nophead wrote > I don't thinks so because all the rounding discussed so far uses circular > arcs that meet straight lines tangentially. That is continuous in gradient > but has a discontinuity of curvature. Possibly Bezier splines would do the > job? > > On Tue, 12 Mar 2019 at 14:27, William Adams &lt; > will.adams@ > &gt; wrote: > >> Would it be possible to use this tool to get rounding as is done in some >> industrial designs? >> >> >> https://hackernoon.com/apples-icons-have-that-shape-for-a-very-good-reason-720d4e7c8a14 >> >> If not, could someone suggest a suitable technique to achieve this? >> >> William >> -- Sent from: http://forum.openscad.org/
A
adrianv
Tue, Mar 12, 2019 11:19 PM

rew wrote

On Tue, Mar 12, 2019 at 03:06:43PM +0000, nop head wrote:

I don't thinks so because all the rounding discussed so far uses circular
arcs that meet straight lines tangentially. That is continuous in
gradient
but has a discontinuity of curvature. Possibly Bezier splines would do
the
job?

I would REALLY like to have bezier curves in openscad. The $fn parameter
would determine how many interpolation points would be used to convert the
spline to triangles.

Does it need to be in the base language for some reason?  Bezier curves have
been implemented several times.  Here are three examples:

https://github.com/revarbat/BOSL/wiki/beziers.scad
https://www.thingiverse.com/thing:8483/attribution_is_important
https://github.com/JustinSDK/dotSCAD

And actually that third one has a bezier_smooth function that maybe does the
smooth curvature smoothing that was requested.

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

rew wrote > On Tue, Mar 12, 2019 at 03:06:43PM +0000, nop head wrote: >> I don't thinks so because all the rounding discussed so far uses circular >> arcs that meet straight lines tangentially. That is continuous in >> gradient >> but has a discontinuity of curvature. Possibly Bezier splines would do >> the >> job? > > I would REALLY like to have bezier curves in openscad. The $fn parameter > would determine how many interpolation points would be used to convert the > spline to triangles. Does it need to be in the base language for some reason? Bezier curves have been implemented several times. Here are three examples: https://github.com/revarbat/BOSL/wiki/beziers.scad https://www.thingiverse.com/thing:8483/attribution_is_important https://github.com/JustinSDK/dotSCAD And actually that third one has a bezier_smooth function that maybe does the smooth curvature smoothing that was requested. -- Sent from: http://forum.openscad.org/
NH
nop head
Tue, Mar 12, 2019 11:28 PM

I don't have an artistic bone in my body, so to me circles meeting tangents
are fine. I don't have any Apple products and probably never will as they
are just a waste of money. They look nice but are very unreliable and
locked in.

If I could see a need for avoiding discontinuities in curvature I am sure I
could work something out with Bezier splines but life is too short. I use
Bezier splines to approximate minimum energy curves to model bent strips.
2D Bezier curves are easy in OpenSCAD, and 3D Bezier curves are certainly
possible with polyhedron. I don't think new primitives are needed.

On Tue, 12 Mar 2019 at 23:15, adrianv avm4@cornell.edu wrote:

Definitely none of the rounding code I've seen does this directly.  Thanks
for bringing this to my attention.  I'm actually interested in mplementing
this myself.  Does it make sense to use tangent circles to define the
location of the curved section and then fit a bezier instead of a circular
arc into the space?  Or is there some better way to define the space where
the curve should go at a given corner?  Like perhaps a setback distance
along the edge from the corner?

nophead wrote

I don't thinks so because all the rounding discussed so far uses circular
arcs that meet straight lines tangentially. That is continuous in

gradient

but has a discontinuity of curvature. Possibly Bezier splines would do

the

job?

On Tue, 12 Mar 2019 at 14:27, William Adams <

will.adams@

> wrote:

Would it be possible to use this tool to get rounding as is done in some
industrial designs?

If not, could someone suggest a suitable technique to achieve this?

William

I don't have an artistic bone in my body, so to me circles meeting tangents are fine. I don't have any Apple products and probably never will as they are just a waste of money. They look nice but are very unreliable and locked in. If I could see a need for avoiding discontinuities in curvature I am sure I could work something out with Bezier splines but life is too short. I use Bezier splines to approximate minimum energy curves to model bent strips. 2D Bezier curves are easy in OpenSCAD, and 3D Bezier curves are certainly possible with polyhedron. I don't think new primitives are needed. On Tue, 12 Mar 2019 at 23:15, adrianv <avm4@cornell.edu> wrote: > Definitely none of the rounding code I've seen does this directly. Thanks > for bringing this to my attention. I'm actually interested in mplementing > this myself. Does it make sense to use tangent circles to define the > location of the curved section and then fit a bezier instead of a circular > arc into the space? Or is there some better way to define the space where > the curve should go at a given corner? Like perhaps a setback distance > along the edge from the corner? > > > nophead wrote > > I don't thinks so because all the rounding discussed so far uses circular > > arcs that meet straight lines tangentially. That is continuous in > gradient > > but has a discontinuity of curvature. Possibly Bezier splines would do > the > > job? > > > > On Tue, 12 Mar 2019 at 14:27, William Adams &lt; > > > will.adams@ > > > &gt; wrote: > > > >> Would it be possible to use this tool to get rounding as is done in some > >> industrial designs? > >> > >> > >> > https://hackernoon.com/apples-icons-have-that-shape-for-a-very-good-reason-720d4e7c8a14 > >> > >> If not, could someone suggest a suitable technique to achieve this? > >> > >> William > >> > > > > > > -- > Sent from: http://forum.openscad.org/ > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >
RW
Rogier Wolff
Wed, Mar 13, 2019 10:59 AM

On Tue, Mar 12, 2019 at 11:28:24PM +0000, nop head wrote:

I don't have an artistic bone in my body, so to me circles meeting tangents
are fine. I don't have any Apple products and probably never will as they
are just a waste of money. They look nice but are very unreliable and
locked in.

If I could see a need for avoiding discontinuities in curvature I am sure I
could work something out with Bezier splines but life is too short. I use
Bezier splines to approximate minimum energy curves to model bent strips.
2D Bezier curves are easy in OpenSCAD, and 3D Bezier curves are certainly
possible with polyhedron. I don't think new primitives are needed.

At first I didn't think so, then I did, now I do....

It would be VERY nice if a recursive bezier module could be built. But
that requires returning "patches" that will build up to the sides of a
polyhedron. Writing out the recursion by hand and implementing the
stack on an array is very tedious. It's like on the first day of work
you new boss points at an actual Turing machine, and says: "that's
just as turing-complete as that windows machine over there, you can
use the turing machine."

It's theoretically possible, but WAY more convenient if there is some
language support.

Roger. 

--
** R.E.Wolff@BitWizard.nl ** https://www.BitWizard.nl/ ** +31-15-2049110 **
**    Delftechpark 11 2628 XJ  Delft, The Netherlands.  KVK: 27239233    **
The plan was simple, like my brother-in-law Phil. But unlike
Phil, this plan just might work.

On Tue, Mar 12, 2019 at 11:28:24PM +0000, nop head wrote: > I don't have an artistic bone in my body, so to me circles meeting tangents > are fine. I don't have any Apple products and probably never will as they > are just a waste of money. They look nice but are very unreliable and > locked in. > > If I could see a need for avoiding discontinuities in curvature I am sure I > could work something out with Bezier splines but life is too short. I use > Bezier splines to approximate minimum energy curves to model bent strips. > 2D Bezier curves are easy in OpenSCAD, and 3D Bezier curves are certainly > possible with polyhedron. I don't think new primitives are needed. At first I didn't think so, then I did, now I do.... It would be VERY nice if a recursive bezier module could be built. But that requires returning "patches" that will build up to the sides of a polyhedron. Writing out the recursion by hand and implementing the stack on an array is very tedious. It's like on the first day of work you new boss points at an actual Turing machine, and says: "that's just as turing-complete as that windows machine over there, you can use the turing machine." It's theoretically possible, but WAY more convenient if there is some language support. Roger. -- ** R.E.Wolff@BitWizard.nl ** https://www.BitWizard.nl/ ** +31-15-2049110 ** ** Delftechpark 11 2628 XJ Delft, The Netherlands. KVK: 27239233 ** The plan was simple, like my brother-in-law Phil. But unlike Phil, this plan just might work.
NH
nop head
Wed, Mar 13, 2019 11:41 AM

Isn't it just some for loops and list comprehension? I don't think it is
much harder than sweep if you want a regular array of surface points.

On Wed, 13 Mar 2019, 11:00 Rogier Wolff <R.E.Wolff@bitwizard.nl wrote:

On Tue, Mar 12, 2019 at 11:28:24PM +0000, nop head wrote:

I don't have an artistic bone in my body, so to me circles meeting

tangents

are fine. I don't have any Apple products and probably never will as they
are just a waste of money. They look nice but are very unreliable and
locked in.

If I could see a need for avoiding discontinuities in curvature I am

sure I

could work something out with Bezier splines but life is too short. I use
Bezier splines to approximate minimum energy curves to model bent strips.
2D Bezier curves are easy in OpenSCAD, and 3D Bezier curves are certainly
possible with polyhedron. I don't think new primitives are needed.

At first I didn't think so, then I did, now I do....

It would be VERY nice if a recursive bezier module could be built. But
that requires returning "patches" that will build up to the sides of a
polyhedron. Writing out the recursion by hand and implementing the
stack on an array is very tedious. It's like on the first day of work
you new boss points at an actual Turing machine, and says: "that's
just as turing-complete as that windows machine over there, you can
use the turing machine."

It's theoretically possible, but WAY more convenient if there is some
language support.

     Roger.

--
** R.E.Wolff@BitWizard.nl ** https://www.BitWizard.nl/ ** +31-15-2049110
**
**    Delftechpark 11 2628 XJ  Delft, The Netherlands.  KVK: 27239233    **
The plan was simple, like my brother-in-law Phil. But unlike
Phil, this plan just might work.


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

Isn't it just some for loops and list comprehension? I don't think it is much harder than sweep if you want a regular array of surface points. On Wed, 13 Mar 2019, 11:00 Rogier Wolff <R.E.Wolff@bitwizard.nl wrote: > On Tue, Mar 12, 2019 at 11:28:24PM +0000, nop head wrote: > > I don't have an artistic bone in my body, so to me circles meeting > tangents > > are fine. I don't have any Apple products and probably never will as they > > are just a waste of money. They look nice but are very unreliable and > > locked in. > > > > If I could see a need for avoiding discontinuities in curvature I am > sure I > > could work something out with Bezier splines but life is too short. I use > > Bezier splines to approximate minimum energy curves to model bent strips. > > 2D Bezier curves are easy in OpenSCAD, and 3D Bezier curves are certainly > > possible with polyhedron. I don't think new primitives are needed. > > At first I didn't think so, then I did, now I do.... > > It would be VERY nice if a recursive bezier module could be built. But > that requires returning "patches" that will build up to the sides of a > polyhedron. Writing out the recursion by hand and implementing the > stack on an array is very tedious. It's like on the first day of work > you new boss points at an actual Turing machine, and says: "that's > just as turing-complete as that windows machine over there, you can > use the turing machine." > > It's theoretically possible, but WAY more convenient if there is some > language support. > > Roger. > > > -- > ** R.E.Wolff@BitWizard.nl ** https://www.BitWizard.nl/ ** +31-15-2049110 > ** > ** Delftechpark 11 2628 XJ Delft, The Netherlands. KVK: 27239233 ** > The plan was simple, like my brother-in-law Phil. But unlike > Phil, this plan just might work. > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >
A
adrianv
Wed, Mar 13, 2019 11:46 AM

rew wrote

If I could see a need for avoiding discontinuities in curvature I am sure
I
could work something out with Bezier splines but life is too short. I use
Bezier splines to approximate minimum energy curves to model bent strips.
2D Bezier curves are easy in OpenSCAD, and 3D Bezier curves are certainly
possible with polyhedron. I don't think new primitives are needed.

At first I didn't think so, then I did, now I do....

It would be VERY nice if a recursive bezier module could be built. But
that requires returning "patches" that will build up to the sides of a
polyhedron. Writing out the recursion by hand and implementing the
stack on an array is very tedious. It's like on the first day of work
you new boss points at an actual Turing machine, and says: "that's
just as turing-complete as that windows machine over there, you can
use the turing machine."

It's theoretically possible, but WAY more convenient if there is some
language support.

If it's "theoretically possible" then after someone does it you can use the
code and you don't really care how hard it was to write.  (How hard is it to
write into OpenSCAD as a primitive?)  OpenSCAD can do recursion, so why
would you want to maintain your own stack?  What is it that you think can't
be done?  Or maybe more to the point, what exactly would your desired module
do?  Maybe we can write it.

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

rew wrote >> If I could see a need for avoiding discontinuities in curvature I am sure >> I >> could work something out with Bezier splines but life is too short. I use >> Bezier splines to approximate minimum energy curves to model bent strips. >> 2D Bezier curves are easy in OpenSCAD, and 3D Bezier curves are certainly >> possible with polyhedron. I don't think new primitives are needed. > > At first I didn't think so, then I did, now I do.... > > It would be VERY nice if a recursive bezier module could be built. But > that requires returning "patches" that will build up to the sides of a > polyhedron. Writing out the recursion by hand and implementing the > stack on an array is very tedious. It's like on the first day of work > you new boss points at an actual Turing machine, and says: "that's > just as turing-complete as that windows machine over there, you can > use the turing machine." > > It's theoretically possible, but WAY more convenient if there is some > language support. If it's "theoretically possible" then after someone does it you can use the code and you don't really care how hard it was to write. (How hard is it to write into OpenSCAD as a primitive?) OpenSCAD can do recursion, so why would you want to maintain your own stack? What is it that you think can't be done? Or maybe more to the point, what exactly would your desired module do? Maybe we can write it. -- Sent from: http://forum.openscad.org/
RW
Rogier Wolff
Wed, Mar 13, 2019 11:52 AM

On Wed, Mar 13, 2019 at 11:41:30AM +0000, nop head wrote:

Isn't it just some for loops and list comprehension? I don't think it is
much harder than sweep if you want a regular array of surface points.

Hmm.. Ok. Maybe it's doable... I'll give it a go later on. Maybe this
weekend. Feel free to remind me. I might forget.

(I already wrote the first test-control-points and the call of the
module, and the level zero approximation.... )

Roger. 

On Wed, 13 Mar 2019, 11:00 Rogier Wolff <R.E.Wolff@bitwizard.nl wrote:

On Tue, Mar 12, 2019 at 11:28:24PM +0000, nop head wrote:

I don't have an artistic bone in my body, so to me circles meeting

tangents

are fine. I don't have any Apple products and probably never will as they
are just a waste of money. They look nice but are very unreliable and
locked in.

If I could see a need for avoiding discontinuities in curvature I am

sure I

could work something out with Bezier splines but life is too short. I use
Bezier splines to approximate minimum energy curves to model bent strips.
2D Bezier curves are easy in OpenSCAD, and 3D Bezier curves are certainly
possible with polyhedron. I don't think new primitives are needed.

At first I didn't think so, then I did, now I do....

It would be VERY nice if a recursive bezier module could be built. But
that requires returning "patches" that will build up to the sides of a
polyhedron. Writing out the recursion by hand and implementing the
stack on an array is very tedious. It's like on the first day of work
you new boss points at an actual Turing machine, and says: "that's
just as turing-complete as that windows machine over there, you can
use the turing machine."

It's theoretically possible, but WAY more convenient if there is some
language support.

     Roger.

--
** R.E.Wolff@BitWizard.nl ** https://www.BitWizard.nl/ ** +31-15-2049110
**
**    Delftechpark 11 2628 XJ  Delft, The Netherlands.  KVK: 27239233    **
The plan was simple, like my brother-in-law Phil. But unlike
Phil, this plan just might work.


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

--
** R.E.Wolff@BitWizard.nl ** https://www.BitWizard.nl/ ** +31-15-2049110 **
**    Delftechpark 11 2628 XJ  Delft, The Netherlands.  KVK: 27239233    **
The plan was simple, like my brother-in-law Phil. But unlike
Phil, this plan just might work.

On Wed, Mar 13, 2019 at 11:41:30AM +0000, nop head wrote: > Isn't it just some for loops and list comprehension? I don't think it is > much harder than sweep if you want a regular array of surface points. Hmm.. Ok. Maybe it's doable... I'll give it a go later on. Maybe this weekend. Feel free to remind me. I might forget. (I already wrote the first test-control-points and the call of the module, and the level zero approximation.... ) Roger. > > On Wed, 13 Mar 2019, 11:00 Rogier Wolff <R.E.Wolff@bitwizard.nl wrote: > > > On Tue, Mar 12, 2019 at 11:28:24PM +0000, nop head wrote: > > > I don't have an artistic bone in my body, so to me circles meeting > > tangents > > > are fine. I don't have any Apple products and probably never will as they > > > are just a waste of money. They look nice but are very unreliable and > > > locked in. > > > > > > If I could see a need for avoiding discontinuities in curvature I am > > sure I > > > could work something out with Bezier splines but life is too short. I use > > > Bezier splines to approximate minimum energy curves to model bent strips. > > > 2D Bezier curves are easy in OpenSCAD, and 3D Bezier curves are certainly > > > possible with polyhedron. I don't think new primitives are needed. > > > > At first I didn't think so, then I did, now I do.... > > > > It would be VERY nice if a recursive bezier module could be built. But > > that requires returning "patches" that will build up to the sides of a > > polyhedron. Writing out the recursion by hand and implementing the > > stack on an array is very tedious. It's like on the first day of work > > you new boss points at an actual Turing machine, and says: "that's > > just as turing-complete as that windows machine over there, you can > > use the turing machine." > > > > It's theoretically possible, but WAY more convenient if there is some > > language support. > > > > Roger. > > > > > > -- > > ** R.E.Wolff@BitWizard.nl ** https://www.BitWizard.nl/ ** +31-15-2049110 > > ** > > ** Delftechpark 11 2628 XJ Delft, The Netherlands. KVK: 27239233 ** > > The plan was simple, like my brother-in-law Phil. But unlike > > Phil, this plan just might work. > > > > _______________________________________________ > > OpenSCAD mailing list > > Discuss@lists.openscad.org > > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org > > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org -- ** R.E.Wolff@BitWizard.nl ** https://www.BitWizard.nl/ ** +31-15-2049110 ** ** Delftechpark 11 2628 XJ Delft, The Netherlands. KVK: 27239233 ** The plan was simple, like my brother-in-law Phil. But unlike Phil, this plan just might work.
A
adrianv
Wed, Mar 13, 2019 2:09 PM

William Adams-2 wrote

Would it be possible to use this tool to get rounding as is done in some
industrial designs?

https://hackernoon.com/apples-icons-have-that-shape-for-a-very-good-reason-720d4e7c8a14

If not, could someone suggest a suitable technique to achieve this?

William

I studied Bezier curves last night (about which I knew nothing) and figured
out how cubic bezier curves can be used to achieve continuous curvature
rounding.  One parameter needs to be specified at each corner.  I'm
wondering what the best way to specify this parameter is.  It could be
specified as the distance to the intersection point of the bezier with the
edge.  Or it could be specified as the distance from the corner tip to the
maximum projection of the curve (e.g. how much is cut off).  Or perhaps
some other way relating to rounding with circular arcs?

I also wonder if it might be desirable to round in a continuous curvature
fashion but more aggressively using a higher order Bezier.  These roundovers
with the cubic bezier are rather gentle.  Anybody know how to calculate the
curvature at the endpoints of an order 4 (or general order) bezier?

Here are two examples.  The green line shows the bezier curve fit to the
corner shown in red.  Note how far back it extends before finally
terminating on the linear portion?  It means you need a long flat edge to
have room for a fairly modest roundover.

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

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

William Adams-2 wrote > Would it be possible to use this tool to get rounding as is done in some > industrial designs? > > https://hackernoon.com/apples-icons-have-that-shape-for-a-very-good-reason-720d4e7c8a14 > > If not, could someone suggest a suitable technique to achieve this? > > William I studied Bezier curves last night (about which I knew nothing) and figured out how cubic bezier curves can be used to achieve continuous curvature rounding. One parameter needs to be specified at each corner. I'm wondering what the best way to specify this parameter is. It could be specified as the distance to the intersection point of the bezier with the edge. Or it could be specified as the distance from the corner tip to the maximum projection of the curve (e.g. how much is cut off). Or perhaps some other way relating to rounding with circular arcs? I also wonder if it might be desirable to round in a continuous curvature fashion but more aggressively using a higher order Bezier. These roundovers with the cubic bezier are rather gentle. Anybody know how to calculate the curvature at the endpoints of an order 4 (or general order) bezier? Here are two examples. The green line shows the bezier curve fit to the corner shown in red. Note how far back it extends before finally terminating on the linear portion? It means you need a *long* flat edge to have room for a fairly modest roundover. <http://forum.openscad.org/file/t2477/bez.png> -- Sent from: http://forum.openscad.org/
TP
Torsten Paul
Wed, Mar 13, 2019 10:12 PM

I have not looked at the detailed properties, but Catmull–Rom
spline have the nice benefit that they don't need additional
control points. So for "just rounding stuff" that seems to be
quite interesting.

ciao,
Torsten.

I have not looked at the detailed properties, but Catmull–Rom spline have the nice benefit that they don't need additional control points. So for "just rounding stuff" that seems to be quite interesting. ciao, Torsten.
A
adrianv
Wed, Mar 13, 2019 10:19 PM

tp3 wrote

I have not looked at the detailed properties, but Catmull–Rom
spline have the nice benefit that they don't need additional
control points. So for "just rounding stuff" that seems to be
quite interesting.

I also didn't look in detail, but it's not apparent that these splines have
any nice derivative properties, like even first derivative control.  Having
no control parameters isn't necessary a good thing, as indicated by the
cubic bezier, which I think doesn't produce a curved enough roundover.

I did a little more analysis and I think a good way to do continuous
curvature roundovers is to use order 4 beziers.  This ends up providing two
parameters.  I'm still not sure of the optimal way to expose these
parameters to the user.  Basically with these beziers you set p0 to one end
point, p4 to the other endpoint, p2 to the point of the corner, and the
remaining p1 and p3 are symmetrically placed on the intervals [p0,p2] and
[p2,p4].  The parameters that need to be chosen are the distance, d,  of p0
and p4 from the corner and the distance a, of p1 and p2 from the corner.
Choosing a=d gives the maximum roundover, which I think is probably what is
generally desired.  If we consider doing a chamfer by simply connecting p0
and p4 then the roundover that results from a=d will put the tip of the
roundover at 5/8 of the way from the corner point to the chamfer.  Setting
a=0 puts the roundover 1/8 of the way from the corner to the chamfer.

So I could have the user specify d (the distance along the line segment to
the start of the roundover curve) or I could have the user specify the
distance to the line between p0 and p4.  And for a I can have the user
specify a value on [0,1] to control the range from 0 to d, or I could have
the user specify something from [1/8 to 5/8]*d---specifying the actual
location of the roundover tip.

Maybe I'll post some pictures later since I think the above may not be
clear.

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

tp3 wrote > I have not looked at the detailed properties, but Catmull–Rom > spline have the nice benefit that they don't need additional > control points. So for "just rounding stuff" that seems to be > quite interesting. I also didn't look in detail, but it's not apparent that these splines have any nice derivative properties, like even first derivative control. Having no control parameters isn't necessary a good thing, as indicated by the cubic bezier, which I think doesn't produce a curved enough roundover. I did a little more analysis and I think a good way to do continuous curvature roundovers is to use order 4 beziers. This ends up providing two parameters. I'm still not sure of the optimal way to expose these parameters to the user. Basically with these beziers you set p0 to one end point, p4 to the other endpoint, p2 to the point of the corner, and the remaining p1 and p3 are symmetrically placed on the intervals [p0,p2] and [p2,p4]. The parameters that need to be chosen are the distance, d, of p0 and p4 from the corner and the distance a, of p1 and p2 from the corner. Choosing a=d gives the maximum roundover, which I think is probably what is generally desired. If we consider doing a chamfer by simply connecting p0 and p4 then the roundover that results from a=d will put the tip of the roundover at 5/8 of the way from the corner point to the chamfer. Setting a=0 puts the roundover 1/8 of the way from the corner to the chamfer. So I could have the user specify d (the distance along the line segment to the start of the roundover curve) or I could have the user specify the distance to the line between p0 and p4. And for a I can have the user specify a value on [0,1] to control the range from 0 to d, or I could have the user specify something from [1/8 to 5/8]*d---specifying the actual location of the roundover tip. Maybe I'll post some pictures later since I think the above may not be clear. -- Sent from: http://forum.openscad.org/
A
adrianv
Thu, Mar 14, 2019 2:13 AM

http://forum.openscad.org/file/t2477/diagram.jpg So there's an image
showing a corner to be smoothed.  The control points p0, ..., p4 are located
as shown, with p0 and p4 at the base of the bezier curve, p2 at the tip of
the corner, and p1 and p3 on the line segment in between somewhere.  It
takes two parameters to specify the 4th order curve: d, the distance from
the corner (p2) to the base control points (p0 and p4) and a, the distance
to the secondary control points p1 and p3.  The most rounding occurs when
a=d, at which point c = (5/8)*h.  The least rounding occurs when a=0, at
which point c=(1/8)*h.  So the user could specify d or h.  Which is more
natural?  For the amount of curvature the user could specify    a (which
seems not very meaningful) or    a/d which is a sort of smoothing factor
that ranges on [0,1]  c, how much of the corner to "cut off" (but must be
in the range [1/8,5/8]*h  the amount to cut off as a fraction of h, so a
value in the range [1/8, 5/8]

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

<http://forum.openscad.org/file/t2477/diagram.jpg> So there's an image showing a corner to be smoothed. The control points p0, ..., p4 are located as shown, with p0 and p4 at the base of the bezier curve, p2 at the tip of the corner, and p1 and p3 on the line segment in between somewhere. It takes two parameters to specify the 4th order curve: d, the distance from the corner (p2) to the base control points (p0 and p4) and a, the distance to the secondary control points p1 and p3. The most rounding occurs when a=d, at which point c = (5/8)*h. The least rounding occurs when a=0, at which point c=(1/8)*h. So the user could specify d or h. Which is more natural? For the amount of curvature the user could specify a (which seems not very meaningful) or a/d which is a sort of smoothing factor that ranges on [0,1] c, how much of the corner to "cut off" (but must be in the range [1/8,5/8]*h the amount to cut off as a fraction of h, so a value in the range [1/8, 5/8] -- Sent from: http://forum.openscad.org/
RP
Ronaldo Persiano
Thu, Mar 14, 2019 2:14 AM

You are right, a degree 3 Bezier arc would at most be zero curvature at one
extreme and tangent continuous at the other. The minimal degree for a zero
curvature at each extremes is really 5. However, I would use a degree 6
Bezier arc because you get too restricted setting p2 to the vertex of the
polygon. I did a experiment with degree 6 with the following strategy.

[image: pc.PNG]
The collinearity of P0, P1 and P2 implies zero curvature of the arc at P0
besides the tangent to segment [C.P0]  (similarly for P5) .
The position of P2 (respect. P3) follows a ratio r0 in the interval (0,1)
in the segment [C,P0] (respect. [C,P5]).
The position of P1 (respect. P4) follows a ratio r1 in the interval (0,1)
in the segment [P2,P0] (respect. [P3,P5]).
This two ratios give some flexibility to the shape of the curve.

Here is a code that follows that strategy to round a polygon. I haven't
tried with non-convex polygons but it should work fine.

// polygon to be rounded

q = [ [0,0], [30,0], [15,20] ];

color("blue")  roundedPoly(q, 20, 1/5);
color("yellow") roundedPoly(q, 20, 1/3);
color("red")    roundedPoly(q, 20, 1/2);

translate([30,0,0]) {
color("blue")  roundedPoly(q, 20, 1/5, 1/3);
color("yellow") roundedPoly(q, 20, 1/3, 1/3);
color("red")    roundedPoly(q, 20, 1/2, 1/3);
}

module roundedPoly(p, n=20, r=1/4, r0=2/3, r1=1/2) {
assert(len(p)>2, "polygonal has less than 3 points");

assert(r>0 && r<1, "improper value of argument r");

l = len(p);
q = [for(i=[0:l-1])
let( p0 = (1-r)p[i] + rp[(i+l-1)%l] ,
p1 = p[i],
p2 = (1-r)p[i] + rp[(i+1)%l] )
each BZeroCurvature(p0,p1,p2,n,r0,r1) ];
line(q, closed=true);
}

// a Bezier arc of degree 5 from p0 to p2, tangent to
// [p0,p1] at p0, tangent to [p1,p2) at p2 and
// with zero curvature at p0 and p2
// n = # of points in the arc
// r0, r1 - form factors in the open interval (0,1)
function BZeroCurvature(p0,p1,p2,n=20,r0=2/3,r1=1/2) =
assert(r0>0 && r0<1 && r1>0 && r1<1, "improper value of r0 or r1")
let( p = [ p0,
p0 + r0*(p1-p0)r1,
p0 + r0
(p1-p0),
p2 + r0*(p1-p2),
p2 + r0*(p1-p2)*r1,
p2 ] )
BezierCurve(p,n);

// p are the curve control points, the curve degree is len(p)-1
function BezierCurve(p, n=10) =
[for(i=[0:n-1]) BezierPoint(p, i/(n-1)) ];

function BezierPoint(p, u) =
(len(p) == 2)?
u*p[1] + (1-u)p[0] :
u
BezierPoint([for(i=[1:len(p)-1]) p[i] ], u)
+ (1-u)*BezierPoint([for(i=[0:len(p)-2]) p[i] ], u);

module line(p,closed=false,w=0.1)
for(i=[0:len(p)-(closed? 1:2)]){
hull(){ translate(to3d(p[i]))  sphere(w);
translate(to3d(p[(i+1)%len(p)])) sphere(w); }
}
function to3d(p) = len(p)==3 ? p : [p.x,p.y,0];

[image: roundedPoly.PNG]

I would not expect any good interface for Bezier stuffs could be designed
to solve a large set of problems to justify its implementation in the core
of OpenSCAD. Each modeling problem requires specific codes to be written
and that is easily done in users space if you have the needed mathematical
background. Anyway, to work with Bezier curves and surfaces, even using
other people good libraries, a minimal mathematical background is necessary.

You are right, a degree 3 Bezier arc would at most be zero curvature at one extreme and tangent continuous at the other. The minimal degree for a zero curvature at each extremes is really 5. However, I would use a degree 6 Bezier arc because you get too restricted setting p2 to the vertex of the polygon. I did a experiment with degree 6 with the following strategy. [image: pc.PNG] The collinearity of P0, P1 and P2 implies zero curvature of the arc at P0 besides the tangent to segment [C.P0] (similarly for P5) . The position of P2 (respect. P3) follows a ratio r0 in the interval (0,1) in the segment [C,P0] (respect. [C,P5]). The position of P1 (respect. P4) follows a ratio r1 in the interval (0,1) in the segment [P2,P0] (respect. [P3,P5]). This two ratios give some flexibility to the shape of the curve. Here is a code that follows that strategy to round a polygon. I haven't tried with non-convex polygons but it should work fine. // polygon to be rounded q = [ [0,0], [30,0], [15,20] ]; color("blue") roundedPoly(q, 20, 1/5); color("yellow") roundedPoly(q, 20, 1/3); color("red") roundedPoly(q, 20, 1/2); translate([30,0,0]) { color("blue") roundedPoly(q, 20, 1/5, 1/3); color("yellow") roundedPoly(q, 20, 1/3, 1/3); color("red") roundedPoly(q, 20, 1/2, 1/3); } module roundedPoly(p, n=20, r=1/4, r0=2/3, r1=1/2) { assert(len(p)>2, "polygonal has less than 3 points"); assert(r>0 && r<1, "improper value of argument r"); l = len(p); q = [for(i=[0:l-1]) let( p0 = (1-r)*p[i] + r*p[(i+l-1)%l] , p1 = p[i], p2 = (1-r)*p[i] + r*p[(i+1)%l] ) each BZeroCurvature(p0,p1,p2,n,r0,r1) ]; line(q, closed=true); } // a Bezier arc of degree 5 from p0 to p2, tangent to // [p0,p1] at p0, tangent to [p1,p2) at p2 and // with zero curvature at p0 and p2 // n = # of points in the arc // r0, r1 - form factors in the open interval (0,1) function BZeroCurvature(p0,p1,p2,n=20,r0=2/3,r1=1/2) = assert(r0>0 && r0<1 && r1>0 && r1<1, "improper value of r0 or r1") let( p = [ p0, p0 + r0*(p1-p0)*r1, p0 + r0*(p1-p0), p2 + r0*(p1-p2), p2 + r0*(p1-p2)*r1, p2 ] ) BezierCurve(p,n); // p are the curve control points, the curve degree is len(p)-1 function BezierCurve(p, n=10) = [for(i=[0:n-1]) BezierPoint(p, i/(n-1)) ]; function BezierPoint(p, u) = (len(p) == 2)? u*p[1] + (1-u)*p[0] : u*BezierPoint([for(i=[1:len(p)-1]) p[i] ], u) + (1-u)*BezierPoint([for(i=[0:len(p)-2]) p[i] ], u); module line(p,closed=false,w=0.1) for(i=[0:len(p)-(closed? 1:2)]){ hull(){ translate(to3d(p[i])) sphere(w); translate(to3d(p[(i+1)%len(p)])) sphere(w); } } function to3d(p) = len(p)==3 ? p : [p.x,p.y,0]; [image: roundedPoly.PNG] I would not expect any good interface for Bezier stuffs could be designed to solve a large set of problems to justify its implementation in the core of OpenSCAD. Each modeling problem requires specific codes to be written and that is easily done in users space if you have the needed mathematical background. Anyway, to work with Bezier curves and surfaces, even using other people good libraries, a minimal mathematical background is necessary.
RP
Ronaldo Persiano
Thu, Mar 14, 2019 2:21 AM

I missed to mention that the argument r of roundedPoly() controls how much
of the corners are rounded. It has an effect similar to radius when
circular arcs are used.

I missed to mention that the argument r of roundedPoly() controls how much of the corners are rounded. It has an effect similar to radius when circular arcs are used.
A
adrianv
Thu, Mar 14, 2019 2:52 AM

Ronaldo wrote

You are right, a degree 3 Bezier arc would at most be zero curvature at
one
extreme and tangent continuous at the other. The minimal degree for a zero
curvature at each extremes is really 5. However, I would use a degree 6
Bezier arc because you get too restricted setting p2 to the vertex of the
polygon. I did a experiment with degree 6 with the following strategy.

I'm a little puzzled.  Maybe you are using the word degree differently than
I think?  I was thinking a degree 3 Bezier is a cubic polynomial and has 4
control points.  It can be set to zero curvature at both ends but has only
one degree of freedom, which just controls the size of the curve.  That
isn't enough.  It appears to me that degree 4, with 5 control points, is
sufficient.  Yes, you do need to put p2 on the vertex.  This doesn't seem to
cause any undesirable restriction, and it is definitely possible to satisfy
the zero curvature condition.  One parameter remains that controls the
degree of curvature, as I noted in my previous message.  Having fewer
parameters is often better than more, so I'm not sure about what the value
of more degrees of freedom is of going to the case with 6 control points
(which is a 5th degree polynomial).  I did experiment a bit with your code
and you can get some rather sharp cornered results.  It seemed like r1
usually had little effect.

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

Ronaldo wrote > You are right, a degree 3 Bezier arc would at most be zero curvature at > one > extreme and tangent continuous at the other. The minimal degree for a zero > curvature at each extremes is really 5. However, I would use a degree 6 > Bezier arc because you get too restricted setting p2 to the vertex of the > polygon. I did a experiment with degree 6 with the following strategy. I'm a little puzzled. Maybe you are using the word degree differently than I think? I was thinking a degree 3 Bezier is a cubic polynomial and has 4 control points. It can be set to zero curvature at both ends but has only one degree of freedom, which just controls the size of the curve. That isn't enough. It appears to me that degree 4, with 5 control points, is sufficient. Yes, you do need to put p2 on the vertex. This doesn't seem to cause any undesirable restriction, and it is definitely possible to satisfy the zero curvature condition. One parameter remains that controls the degree of curvature, as I noted in my previous message. Having fewer parameters is often better than more, so I'm not sure about what the value of more degrees of freedom is of going to the case with 6 control points (which is a 5th degree polynomial). I did experiment a bit with your code and you can get some rather sharp cornered results. It seemed like r1 usually had little effect. -- Sent from: http://forum.openscad.org/
RW
Rogier Wolff
Thu, Mar 14, 2019 8:55 AM

On Wed, Mar 13, 2019 at 12:52:07PM +0100, Rogier Wolff wrote:

On Wed, Mar 13, 2019 at 11:41:30AM +0000, nop head wrote:

Isn't it just some for loops and list comprehension? I don't think it is
much harder than sweep if you want a regular array of surface points.

Hmm.. Ok. Maybe it's doable... I'll give it a go later on. Maybe this
weekend. Feel free to remind me. I might forget.

[... I already wrote .. ]

wrong!

I started over. I now have a bezier curve in 2D. This is at $fn = 15,
the parameter has not yet been added to the function.

Roger. 

--
** R.E.Wolff@BitWizard.nl ** https://www.BitWizard.nl/ ** +31-15-2049110 **
**    Delftechpark 11 2628 XJ  Delft, The Netherlands.  KVK: 27239233    **
The plan was simple, like my brother-in-law Phil. But unlike
Phil, this plan just might work.

On Wed, Mar 13, 2019 at 12:52:07PM +0100, Rogier Wolff wrote: > On Wed, Mar 13, 2019 at 11:41:30AM +0000, nop head wrote: > > Isn't it just some for loops and list comprehension? I don't think it is > > much harder than sweep if you want a regular array of surface points. > > Hmm.. Ok. Maybe it's doable... I'll give it a go later on. Maybe this > weekend. Feel free to remind me. I might forget. > [... I already wrote .. ] wrong! I started over. I now have a bezier curve in 2D. This is at $fn = 15, the parameter has not yet been added to the function. Roger. -- ** R.E.Wolff@BitWizard.nl ** https://www.BitWizard.nl/ ** +31-15-2049110 ** ** Delftechpark 11 2628 XJ Delft, The Netherlands. KVK: 27239233 ** The plan was simple, like my brother-in-law Phil. But unlike Phil, this plan just might work.
RW
Rogier Wolff
Thu, Mar 14, 2019 9:46 AM

Hi,

I now have a bezier patch in 3d: <see attachment>

Roger. 

--
** R.E.Wolff@BitWizard.nl ** https://www.BitWizard.nl/ ** +31-15-2049110 **
**    Delftechpark 11 2628 XJ  Delft, The Netherlands.  KVK: 27239233    **
The plan was simple, like my brother-in-law Phil. But unlike
Phil, this plan just might work.

Hi, I now have a bezier patch in 3d: <see attachment> Roger. -- ** R.E.Wolff@BitWizard.nl ** https://www.BitWizard.nl/ ** +31-15-2049110 ** ** Delftechpark 11 2628 XJ Delft, The Netherlands. KVK: 27239233 ** The plan was simple, like my brother-in-law Phil. But unlike Phil, this plan just might work.
RP
Ronaldo Persiano
Thu, Mar 14, 2019 6:52 PM

adrianv avm4@cornell.edu wrote:

I'm a little puzzled.  Maybe you are using the word degree differently than
I think?  I was thinking a degree 3 Bezier is a cubic polynomial and has 4
control points.  It can be set to zero curvature at both ends but has only
one degree of freedom, which just controls the size of the curve.  That
isn't enough.  It appears to me that degree 4, with 5 control points, is
sufficient.  Yes, you do need to put p2 on the vertex.  This doesn't seem
to
cause any undesirable restriction, and it is definitely possible to satisfy
the zero curvature condition.  One parameter remains that controls the
degree of curvature, as I noted in my previous message.  Having fewer
parameters is often better than more, so I'm not sure about what the value
of more degrees of freedom is of going to the case with 6 control points
(which is a 5th degree polynomial).  I did experiment a bit with your code
and you can get some rather sharp cornered results.  It seemed like r1
usually had little effect.

You are right regarding the degrees. I wrongly said 5 instead of 4 and 6
instead of 5. A degree n Bezier curve has n+1 control points.

However I disagree that you could meet the zero curvature constraint at
both end with degree 3 curves. To have a zero curvature at the beginning of
the arc, the first 3 control points should co-linear. The same is true for
the ending point. If we require zero curvature at both ends all four
control points should be co-linear and the arc reduces to a straight
segment.

Degree 4 is in fact the minimal degree for zero curvature at both ends for
a non-straight line Bezier arc. However degree 5 solution give us not only
more degrees of freedom but a better arc shape as will see bellow. Degree 4
solution produces an arc with a greater curvature variation and a more
pointed arc. Degree 5 shape is able to produce arcs that resemble circular
arcs.

I have revised my codes in order to generate alternatively both solutions.
The two missed functions and line() module are defined as before.

q = [ [0,0], [30,0], [30,30], [0,30] ];

color("blue")  roundedPoly(q, 20, 4, 1/3);
color("yellow") roundedPoly(q, 20, 4, 2/3);
color("red")    roundedPoly(q, 20, 4,  1);

translate([35,0,0]) {
color("blue")  roundedPoly(q, 20, 5, 1/3, 17/32);
color("yellow") roundedPoly(q, 20, 5, 2/3, 17/32);
color("red")    roundedPoly(q, 20, 5,  1, 17/32);
color("green")  translate([15,15,-1]) circle(15);
}

module roundedPoly(p, n=20, degree=4, r=1/4, r0=2/3, r1=17/32)
{
assert(len(p)>2, "polygonal has less than 3 points");
assert(r>0 && r<=1, "r out of range");
assert(r0>0 && r<=1, "r0 out of range");
assert(degree==4 || degree==5, "degree should be 4 or 5");
assert(degree==5 || (r1>0 && r1<=1), "r1 out of range");
l = len(p);
q = [for(i=[0:l-1])
let( p0 = (1-r/2)p[i] + rp[(i+l-1)%l]/2 ,
p1 = p[i],
p2 = (1-r/2)p[i] + rp[(i+1)%l]/2 )
each BZeroCurvature(p0,p1,p2,n,degree,r0,r1) ];
line(q, closed=true,w=0.2);
}

// a Bezier arc of degree 4 or 5 from p0 to p2, tangent to
// [p0,p1] at p0, tangent to [p1,p2) at p2 and
// with zero curvature at p0 and p2
// n  - # of points in the arc
// r0 - form factor in the interval [0,1]
// r1 - form factor in the interval [0,1] (for degree=5 only)
function BZeroCurvature(p0,p1,p2,n=20,degree=4,r0=2/3,r1=1/2) =
assert(r0>0 && r0<=1, "r0 out of range")
assert(degree==4 || degree==5, "degree should be 4 or 5")
assert(degree==5 || (r1>0 && r1<=1), "r1 out of range")
let( r1 = degree==4 ? 1 : r1,
p  = [ p0,
p0 + r0*(p1-p0)r1,
each degree==4 ?
[p1] :
[p0 + r0
(p1-p0), p2 + r0*(p1-p2)],
p2 + r0*(p1-p2)*r1,
p2 ] )
BezierCurve(p,n);

And got the following image:

[image: roundedPoly2.PNG]

At left we have the arcs of degree 4 and at right the degree 5 alternative
for similar form factors. With r=1, which means that the straight lines
between arcs reduce to a point, drawn here with red lines, the degree 4
solution keeps the middle point of each arc much nearer to the polygon
vertex. With degree 5 on the other hand it is possible to get a good
approximation of a circular arc with r1~= 17/32, a value I got empirically.

adrianv <avm4@cornell.edu> wrote: > I'm a little puzzled. Maybe you are using the word degree differently than > I think? I was thinking a degree 3 Bezier is a cubic polynomial and has 4 > control points. It can be set to zero curvature at both ends but has only > one degree of freedom, which just controls the size of the curve. That > isn't enough. It appears to me that degree 4, with 5 control points, is > sufficient. Yes, you do need to put p2 on the vertex. This doesn't seem > to > cause any undesirable restriction, and it is definitely possible to satisfy > the zero curvature condition. One parameter remains that controls the > degree of curvature, as I noted in my previous message. Having fewer > parameters is often better than more, so I'm not sure about what the value > of more degrees of freedom is of going to the case with 6 control points > (which is a 5th degree polynomial). I did experiment a bit with your code > and you can get some rather sharp cornered results. It seemed like r1 > usually had little effect. > You are right regarding the degrees. I wrongly said 5 instead of 4 and 6 instead of 5. A degree n Bezier curve has n+1 control points. However I disagree that you could meet the zero curvature constraint at both end with degree 3 curves. To have a zero curvature at the beginning of the arc, the first 3 control points should co-linear. The same is true for the ending point. If we require zero curvature at both ends all four control points should be co-linear and the arc reduces to a straight segment. Degree 4 is in fact the minimal degree for zero curvature at both ends for a non-straight line Bezier arc. However degree 5 solution give us not only more degrees of freedom but a better arc shape as will see bellow. Degree 4 solution produces an arc with a greater curvature variation and a more pointed arc. Degree 5 shape is able to produce arcs that resemble circular arcs. I have revised my codes in order to generate alternatively both solutions. The two missed functions and line() module are defined as before. q = [ [0,0], [30,0], [30,30], [0,30] ]; color("blue") roundedPoly(q, 20, 4, 1/3); color("yellow") roundedPoly(q, 20, 4, 2/3); color("red") roundedPoly(q, 20, 4, 1); translate([35,0,0]) { color("blue") roundedPoly(q, 20, 5, 1/3, 17/32); color("yellow") roundedPoly(q, 20, 5, 2/3, 17/32); color("red") roundedPoly(q, 20, 5, 1, 17/32); color("green") translate([15,15,-1]) circle(15); } module roundedPoly(p, n=20, degree=4, r=1/4, r0=2/3, r1=17/32) { assert(len(p)>2, "polygonal has less than 3 points"); assert(r>0 && r<=1, "r out of range"); assert(r0>0 && r<=1, "r0 out of range"); assert(degree==4 || degree==5, "degree should be 4 or 5"); assert(degree==5 || (r1>0 && r1<=1), "r1 out of range"); l = len(p); q = [for(i=[0:l-1]) let( p0 = (1-r/2)*p[i] + r*p[(i+l-1)%l]/2 , p1 = p[i], p2 = (1-r/2)*p[i] + r*p[(i+1)%l]/2 ) each BZeroCurvature(p0,p1,p2,n,degree,r0,r1) ]; line(q, closed=true,w=0.2); } // a Bezier arc of degree 4 or 5 from p0 to p2, tangent to // [p0,p1] at p0, tangent to [p1,p2) at p2 and // with zero curvature at p0 and p2 // n - # of points in the arc // r0 - form factor in the interval [0,1] // r1 - form factor in the interval [0,1] (for degree=5 only) function BZeroCurvature(p0,p1,p2,n=20,degree=4,r0=2/3,r1=1/2) = assert(r0>0 && r0<=1, "r0 out of range") assert(degree==4 || degree==5, "degree should be 4 or 5") assert(degree==5 || (r1>0 && r1<=1), "r1 out of range") let( r1 = degree==4 ? 1 : r1, p = [ p0, p0 + r0*(p1-p0)*r1, each degree==4 ? [p1] : [p0 + r0*(p1-p0), p2 + r0*(p1-p2)], p2 + r0*(p1-p2)*r1, p2 ] ) BezierCurve(p,n); And got the following image: [image: roundedPoly2.PNG] At left we have the arcs of degree 4 and at right the degree 5 alternative for similar form factors. With r=1, which means that the straight lines between arcs reduce to a point, drawn here with red lines, the degree 4 solution keeps the middle point of each arc much nearer to the polygon vertex. With degree 5 on the other hand it is possible to get a good approximation of a circular arc with r1~= 17/32, a value I got empirically.
HL
Hans L
Thu, Mar 14, 2019 7:27 PM

I played around a little bit with Bezier curves in OpenSCAD before, and its
fairly trivial to write a recursive bezier curve function that can handle
arbitrary curve orders.  They are also agnostic to the dimension of points
2D/3D(or higher dimension?)

Here are the functions I have used:

// return point along curve at position "t" in range [0,1]
// use ctlPts[index] as the first control point
// Bezier curve has order == n
function BezierPoint(ctlPts, t, index, n) =
let (
l = len(ctlPts),
end = index+n
)
//assert(end < l)
(n > 0) ?
BezierPoint([
for (i = [index:end])
let (p1 = ctlPts[i], p2 = ctlPts[i+1]) p1 + t * (p2 - p1)
], t, 0, n-1) :
ctlPts[0];

function flatten(l) = [ for (a = l) for (b = a) b ];

// n sets the order of the Bezier curves that will be stitched together
// if no parameter n is given, points will be generated for a single curve
of order == len(ctlPts) - 1
function BezierPath(ctlPts, index, n) =
let (
l1 = $fn > 3 ? $fn-1 : 200,
index = index == undef ? 0 : index,
l2 = len(ctlPts),
n = (n == undef || n > l2-1) ? l2 - 1 : n
)
//assert(n > 0)
flatten([for (segment = [index:1:l2-1-n])
[for (i = [0:l1] ) BezierPoint(ctlPts, i / l1, index+segment*n, n)]
]);

On Thu, Mar 14, 2019 at 1:53 PM Ronaldo Persiano rcmpersiano@gmail.com
wrote:

adrianv avm4@cornell.edu wrote:

I'm a little puzzled.  Maybe you are using the word degree differently
than
I think?  I was thinking a degree 3 Bezier is a cubic polynomial and has 4
control points.  It can be set to zero curvature at both ends but has only
one degree of freedom, which just controls the size of the curve.  That
isn't enough.  It appears to me that degree 4, with 5 control points, is
sufficient.  Yes, you do need to put p2 on the vertex.  This doesn't seem
to
cause any undesirable restriction, and it is definitely possible to
satisfy
the zero curvature condition.  One parameter remains that controls the
degree of curvature, as I noted in my previous message.  Having fewer
parameters is often better than more, so I'm not sure about what the value
of more degrees of freedom is of going to the case with 6 control points
(which is a 5th degree polynomial).  I did experiment a bit with your code
and you can get some rather sharp cornered results.  It seemed like r1
usually had little effect.

You are right regarding the degrees. I wrongly said 5 instead of 4 and 6
instead of 5. A degree n Bezier curve has n+1 control points.

However I disagree that you could meet the zero curvature constraint at
both end with degree 3 curves. To have a zero curvature at the beginning of
the arc, the first 3 control points should co-linear. The same is true for
the ending point. If we require zero curvature at both ends all four
control points should be co-linear and the arc reduces to a straight
segment.

Degree 4 is in fact the minimal degree for zero curvature at both ends for
a non-straight line Bezier arc. However degree 5 solution give us not only
more degrees of freedom but a better arc shape as will see bellow. Degree 4
solution produces an arc with a greater curvature variation and a more
pointed arc. Degree 5 shape is able to produce arcs that resemble circular
arcs.

I have revised my codes in order to generate alternatively both solutions.
The two missed functions and line() module are defined as before.

q = [ [0,0], [30,0], [30,30], [0,30] ];

color("blue")  roundedPoly(q, 20, 4, 1/3);
color("yellow") roundedPoly(q, 20, 4, 2/3);
color("red")    roundedPoly(q, 20, 4,  1);

translate([35,0,0]) {
color("blue")  roundedPoly(q, 20, 5, 1/3, 17/32);
color("yellow") roundedPoly(q, 20, 5, 2/3, 17/32);
color("red")    roundedPoly(q, 20, 5,  1, 17/32);
color("green")  translate([15,15,-1]) circle(15);
}

module roundedPoly(p, n=20, degree=4, r=1/4, r0=2/3, r1=17/32)
{
assert(len(p)>2, "polygonal has less than 3 points");
assert(r>0 && r<=1, "r out of range");
assert(r0>0 && r<=1, "r0 out of range");
assert(degree==4 || degree==5, "degree should be 4 or 5");
assert(degree==5 || (r1>0 && r1<=1), "r1 out of range");
l = len(p);
q = [for(i=[0:l-1])
let( p0 = (1-r/2)p[i] + rp[(i+l-1)%l]/2 ,
p1 = p[i],
p2 = (1-r/2)p[i] + rp[(i+1)%l]/2 )
each BZeroCurvature(p0,p1,p2,n,degree,r0,r1) ];
line(q, closed=true,w=0.2);
}

// a Bezier arc of degree 4 or 5 from p0 to p2, tangent to
// [p0,p1] at p0, tangent to [p1,p2) at p2 and
// with zero curvature at p0 and p2
// n  - # of points in the arc
// r0 - form factor in the interval [0,1]
// r1 - form factor in the interval [0,1] (for degree=5 only)
function BZeroCurvature(p0,p1,p2,n=20,degree=4,r0=2/3,r1=1/2) =
assert(r0>0 && r0<=1, "r0 out of range")
assert(degree==4 || degree==5, "degree should be 4 or 5")
assert(degree==5 || (r1>0 && r1<=1), "r1 out of range")
let( r1 = degree==4 ? 1 : r1,
p  = [ p0,
p0 + r0*(p1-p0)r1,
each degree==4 ?
[p1] :
[p0 + r0
(p1-p0), p2 + r0*(p1-p2)],
p2 + r0*(p1-p2)*r1,
p2 ] )
BezierCurve(p,n);

And got the following image:

[image: roundedPoly2.PNG]

At left we have the arcs of degree 4 and at right the degree 5 alternative
for similar form factors. With r=1, which means that the straight lines
between arcs reduce to a point, drawn here with red lines, the degree 4
solution keeps the middle point of each arc much nearer to the polygon
vertex. With degree 5 on the other hand it is possible to get a good
approximation of a circular arc with r1~= 17/32, a value I got empirically.


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

I played around a little bit with Bezier curves in OpenSCAD before, and its fairly trivial to write a recursive bezier curve function that can handle arbitrary curve orders. They are also agnostic to the dimension of points 2D/3D(or higher dimension?) Here are the functions I have used: // return point along curve at position "t" in range [0,1] // use ctlPts[index] as the first control point // Bezier curve has order == n function BezierPoint(ctlPts, t, index, n) = let ( l = len(ctlPts), end = index+n ) //assert(end < l) (n > 0) ? BezierPoint([ for (i = [index:end]) let (p1 = ctlPts[i], p2 = ctlPts[i+1]) p1 + t * (p2 - p1) ], t, 0, n-1) : ctlPts[0]; function flatten(l) = [ for (a = l) for (b = a) b ]; // n sets the order of the Bezier curves that will be stitched together // if no parameter n is given, points will be generated for a single curve of order == len(ctlPts) - 1 function BezierPath(ctlPts, index, n) = let ( l1 = $fn > 3 ? $fn-1 : 200, index = index == undef ? 0 : index, l2 = len(ctlPts), n = (n == undef || n > l2-1) ? l2 - 1 : n ) //assert(n > 0) flatten([for (segment = [index:1:l2-1-n]) [for (i = [0:l1] ) BezierPoint(ctlPts, i / l1, index+segment*n, n)] ]); On Thu, Mar 14, 2019 at 1:53 PM Ronaldo Persiano <rcmpersiano@gmail.com> wrote: > > > adrianv <avm4@cornell.edu> wrote: > >> I'm a little puzzled. Maybe you are using the word degree differently >> than >> I think? I was thinking a degree 3 Bezier is a cubic polynomial and has 4 >> control points. It can be set to zero curvature at both ends but has only >> one degree of freedom, which just controls the size of the curve. That >> isn't enough. It appears to me that degree 4, with 5 control points, is >> sufficient. Yes, you do need to put p2 on the vertex. This doesn't seem >> to >> cause any undesirable restriction, and it is definitely possible to >> satisfy >> the zero curvature condition. One parameter remains that controls the >> degree of curvature, as I noted in my previous message. Having fewer >> parameters is often better than more, so I'm not sure about what the value >> of more degrees of freedom is of going to the case with 6 control points >> (which is a 5th degree polynomial). I did experiment a bit with your code >> and you can get some rather sharp cornered results. It seemed like r1 >> usually had little effect. >> > > You are right regarding the degrees. I wrongly said 5 instead of 4 and 6 > instead of 5. A degree n Bezier curve has n+1 control points. > > However I disagree that you could meet the zero curvature constraint at > both end with degree 3 curves. To have a zero curvature at the beginning of > the arc, the first 3 control points should co-linear. The same is true for > the ending point. If we require zero curvature at both ends all four > control points should be co-linear and the arc reduces to a straight > segment. > > Degree 4 is in fact the minimal degree for zero curvature at both ends for > a non-straight line Bezier arc. However degree 5 solution give us not only > more degrees of freedom but a better arc shape as will see bellow. Degree 4 > solution produces an arc with a greater curvature variation and a more > pointed arc. Degree 5 shape is able to produce arcs that resemble circular > arcs. > > I have revised my codes in order to generate alternatively both solutions. > The two missed functions and line() module are defined as before. > > q = [ [0,0], [30,0], [30,30], [0,30] ]; > > color("blue") roundedPoly(q, 20, 4, 1/3); > color("yellow") roundedPoly(q, 20, 4, 2/3); > color("red") roundedPoly(q, 20, 4, 1); > > translate([35,0,0]) { > color("blue") roundedPoly(q, 20, 5, 1/3, 17/32); > color("yellow") roundedPoly(q, 20, 5, 2/3, 17/32); > color("red") roundedPoly(q, 20, 5, 1, 17/32); > color("green") translate([15,15,-1]) circle(15); > } > > module roundedPoly(p, n=20, degree=4, r=1/4, r0=2/3, r1=17/32) > { > assert(len(p)>2, "polygonal has less than 3 points"); > assert(r>0 && r<=1, "r out of range"); > assert(r0>0 && r<=1, "r0 out of range"); > assert(degree==4 || degree==5, "degree should be 4 or 5"); > assert(degree==5 || (r1>0 && r1<=1), "r1 out of range"); > l = len(p); > q = [for(i=[0:l-1]) > let( p0 = (1-r/2)*p[i] + r*p[(i+l-1)%l]/2 , > p1 = p[i], > p2 = (1-r/2)*p[i] + r*p[(i+1)%l]/2 ) > each BZeroCurvature(p0,p1,p2,n,degree,r0,r1) ]; > line(q, closed=true,w=0.2); > } > > // a Bezier arc of degree 4 or 5 from p0 to p2, tangent to > // [p0,p1] at p0, tangent to [p1,p2) at p2 and > // with zero curvature at p0 and p2 > // n - # of points in the arc > // r0 - form factor in the interval [0,1] > // r1 - form factor in the interval [0,1] (for degree=5 only) > function BZeroCurvature(p0,p1,p2,n=20,degree=4,r0=2/3,r1=1/2) = > assert(r0>0 && r0<=1, "r0 out of range") > assert(degree==4 || degree==5, "degree should be 4 or 5") > assert(degree==5 || (r1>0 && r1<=1), "r1 out of range") > let( r1 = degree==4 ? 1 : r1, > p = [ p0, > p0 + r0*(p1-p0)*r1, > each degree==4 ? > [p1] : > [p0 + r0*(p1-p0), p2 + r0*(p1-p2)], > p2 + r0*(p1-p2)*r1, > p2 ] ) > BezierCurve(p,n); > > > And got the following image: > > [image: roundedPoly2.PNG] > > At left we have the arcs of degree 4 and at right the degree 5 alternative > for similar form factors. With r=1, which means that the straight lines > between arcs reduce to a point, drawn here with red lines, the degree 4 > solution keeps the middle point of each arc much nearer to the polygon > vertex. With degree 5 on the other hand it is possible to get a good > approximation of a circular arc with r1~= 17/32, a value I got empirically. > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >
A
adrianv
Thu, Mar 14, 2019 10:02 PM

Ronaldo wrote

adrianv <

avm4@

> wrote:

However I disagree that you could meet the zero curvature constraint at
both end with degree 3 curves. To have a zero curvature at the beginning
of
the arc, the first 3 control points should co-linear. The same is true for
the ending point. If we require zero curvature at both ends all four
control points should be co-linear and the arc reduces to a straight
segment.

No it doesn't.  I posted graphs a few messages back showing zero curvature
order 3 beziers, and I had directly verified that the curvature was indeed
zero by calculating the derivatives both symbolically and numerically, so I
am reasonably sure it was correct.  With p0=p3 set to the endpoints of the
arc you then set p1=p2 equal to the point of the corner.  You achieve the
co-linearity condition in a degenerate fashion, since p1 and p2 are on both
lines.

Degree 4 is in fact the minimal degree for zero curvature at both ends for
a non-straight line Bezier arc. However degree 5 solution give us not only
more degrees of freedom but a better arc shape as will see bellow. Degree
4
solution produces an arc with a greater curvature variation and a more
pointed arc. Degree 5 shape is able to produce arcs that resemble circular
arcs.

It appears that your degree 4 code can also generate a nearly circular arc:
just set r1 very small, like .01 and you get something visually
indistinguishable from a circle.  In fact, it looks very similar to your
empirically determined 17/32 value.  I wonder what are the parameters for
the order 5 bezier that reduce it to the order 4.

On the left is order 4 with r1=0.01 and on the right, order 5 with r1=17/32.

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

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

Ronaldo wrote > adrianv &lt; > avm4@ > &gt; wrote: > > > However I disagree that you could meet the zero curvature constraint at > both end with degree 3 curves. To have a zero curvature at the beginning > of > the arc, the first 3 control points should co-linear. The same is true for > the ending point. If we require zero curvature at both ends all four > control points should be co-linear and the arc reduces to a straight > segment. No it doesn't. I posted graphs a few messages back showing zero curvature order 3 beziers, and I had directly verified that the curvature was indeed zero by calculating the derivatives both symbolically and numerically, so I am reasonably sure it was correct. With p0=p3 set to the endpoints of the arc you then set p1=p2 equal to the point of the corner. You achieve the co-linearity condition in a degenerate fashion, since p1 and p2 are on both lines. > Degree 4 is in fact the minimal degree for zero curvature at both ends for > a non-straight line Bezier arc. However degree 5 solution give us not only > more degrees of freedom but a better arc shape as will see bellow. Degree > 4 > solution produces an arc with a greater curvature variation and a more > pointed arc. Degree 5 shape is able to produce arcs that resemble circular > arcs. It appears that your degree 4 code can also generate a nearly circular arc: just set r1 very small, like .01 and you get something visually indistinguishable from a circle. In fact, it looks very similar to your empirically determined 17/32 value. I wonder what are the parameters for the order 5 bezier that reduce it to the order 4. On the left is order 4 with r1=0.01 and on the right, order 5 with r1=17/32. <http://forum.openscad.org/file/t2477/round2.png> -- Sent from: http://forum.openscad.org/
HL
Hans L
Thu, Mar 14, 2019 11:07 PM

Well I'm a bit embarrassed after playing with the Bezier code I previously
posted(hadn't messed with it in a while).  I realized it had some bugs and
some inefficiencies.
I fixed it up a bit and included a more complete example with example of
various orders along random path, and a classic circle approximation.

Posting gist this time in case I need to update it again, but I believe the
code is correct now :
https://gist.github.com/thehans/2da9f7c608f4a689456e714eaa2189e6

On Thu, Mar 14, 2019 at 5:03 PM adrianv avm4@cornell.edu wrote:

Ronaldo wrote

adrianv <

avm4@

> wrote:

However I disagree that you could meet the zero curvature constraint at
both end with degree 3 curves. To have a zero curvature at the beginning
of
the arc, the first 3 control points should co-linear. The same is true

for

the ending point. If we require zero curvature at both ends all four
control points should be co-linear and the arc reduces to a straight
segment.

No it doesn't.  I posted graphs a few messages back showing zero curvature
order 3 beziers, and I had directly verified that the curvature was indeed
zero by calculating the derivatives both symbolically and numerically, so I
am reasonably sure it was correct.  With p0=p3 set to the endpoints of the
arc you then set p1=p2 equal to the point of the corner.  You achieve the
co-linearity condition in a degenerate fashion, since p1 and p2 are on both
lines.

Degree 4 is in fact the minimal degree for zero curvature at both ends

for

a non-straight line Bezier arc. However degree 5 solution give us not

only

more degrees of freedom but a better arc shape as will see bellow. Degree
4
solution produces an arc with a greater curvature variation and a more
pointed arc. Degree 5 shape is able to produce arcs that resemble

circular

arcs.

It appears that your degree 4 code can also generate a nearly circular arc:
just set r1 very small, like .01 and you get something visually
indistinguishable from a circle.  In fact, it looks very similar to your
empirically determined 17/32 value.  I wonder what are the parameters for
the order 5 bezier that reduce it to the order 4.

On the left is order 4 with r1=0.01 and on the right, order 5 with
r1=17/32.

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

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


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

Well I'm a bit embarrassed after playing with the Bezier code I previously posted(hadn't messed with it in a while). I realized it had some bugs and some inefficiencies. I fixed it up a bit and included a more complete example with example of various orders along random path, and a classic circle approximation. Posting gist this time in case I need to update it again, but I believe the code is correct now : https://gist.github.com/thehans/2da9f7c608f4a689456e714eaa2189e6 On Thu, Mar 14, 2019 at 5:03 PM adrianv <avm4@cornell.edu> wrote: > Ronaldo wrote > > adrianv &lt; > > > avm4@ > > > &gt; wrote: > > > > > > However I disagree that you could meet the zero curvature constraint at > > both end with degree 3 curves. To have a zero curvature at the beginning > > of > > the arc, the first 3 control points should co-linear. The same is true > for > > the ending point. If we require zero curvature at both ends all four > > control points should be co-linear and the arc reduces to a straight > > segment. > > No it doesn't. I posted graphs a few messages back showing zero curvature > order 3 beziers, and I had directly verified that the curvature was indeed > zero by calculating the derivatives both symbolically and numerically, so I > am reasonably sure it was correct. With p0=p3 set to the endpoints of the > arc you then set p1=p2 equal to the point of the corner. You achieve the > co-linearity condition in a degenerate fashion, since p1 and p2 are on both > lines. > > > > Degree 4 is in fact the minimal degree for zero curvature at both ends > for > > a non-straight line Bezier arc. However degree 5 solution give us not > only > > more degrees of freedom but a better arc shape as will see bellow. Degree > > 4 > > solution produces an arc with a greater curvature variation and a more > > pointed arc. Degree 5 shape is able to produce arcs that resemble > circular > > arcs. > > It appears that your degree 4 code can also generate a nearly circular arc: > just set r1 very small, like .01 and you get something visually > indistinguishable from a circle. In fact, it looks very similar to your > empirically determined 17/32 value. I wonder what are the parameters for > the order 5 bezier that reduce it to the order 4. > > On the left is order 4 with r1=0.01 and on the right, order 5 with > r1=17/32. > > <http://forum.openscad.org/file/t2477/round2.png> > > > > > > -- > Sent from: http://forum.openscad.org/ > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >
RP
Ronaldo Persiano
Fri, Mar 15, 2019 3:14 AM

No it doesn't.  I posted graphs a few messages back showing zero curvature
order 3 beziers, and I had directly verified that the curvature was indeed
zero by calculating the derivatives both symbolically and numerically, so I
am reasonably sure it was correct.  With p0=p3 set to the endpoints of the
arc you then set p1=p2 equal to the point of the corner.  You achieve the
co-linearity condition in a degenerate fashion, since p1 and p2 are on both
lines.

You are right. Putting both intermediate control points at the corner will
meet the conditions of zero curvature at the two ends of a degree 3 Bezier
arc. I could not imagine that solution before. And certainly this is a very
constrained alternative.

It appears that your degree 4 code can also generate a nearly circular arc:
just set r1 very small, like .01 and you get something visually
indistinguishable from a circle.  In fact, it looks very similar to your
empirically determined 17/32 value.  I wonder what are the parameters for
the order 5 bezier that reduce it to the order 4.

I have confirmed your statement about the approximation of circular arcs by
degree 4 curves. It seems even better than the degree 5 arc with r0=17/32.

I have applied the degree elevation formulas to deduce algebraically the
conditions r0 and r1 should satisfy in order the degree 4 and degree 5
curves be equal. From my math exercise, we should have:

degree 5 with  r0 = 3/5  and r1=0 will be equivalent to
degree 4 with r0=0

I also found that r0 may be set to 0 for degree 4 and r1 may be set to 0
for degree 5 but r0 should not be 0 for degree 5 because the arc degenerate
into a line segment. I have changed the assert conditions in the my
functions accordingly.

I agree that rounding corners with degree 4 Bezier arcs give us enough
flexibility and there is no point to use greater degree. In my functions,
the parameter r of roundedPoly() controls how much the corner is rounded
like your proposed d parameter. That parameter sets the end points
relatively to the polygon edge length instead of an absolute value. The
problem with this solution is that the arc will not be symmetrical when the
two edges meeting a corner have different length. But the alternative of a
absolute value d requires a validation to avoid that two arcs rounding the
two corners of an edge intercept.

Finally, I have checked that my code works well even with not convex
polygons as can be seen in the image.

> > No it doesn't. I posted graphs a few messages back showing zero curvature > order 3 beziers, and I had directly verified that the curvature was indeed > zero by calculating the derivatives both symbolically and numerically, so I > am reasonably sure it was correct. With p0=p3 set to the endpoints of the > arc you then set p1=p2 equal to the point of the corner. You achieve the > co-linearity condition in a degenerate fashion, since p1 and p2 are on both > lines. You are right. Putting both intermediate control points at the corner will meet the conditions of zero curvature at the two ends of a degree 3 Bezier arc. I could not imagine that solution before. And certainly this is a very constrained alternative. > It appears that your degree 4 code can also generate a nearly circular arc: > just set r1 very small, like .01 and you get something visually > indistinguishable from a circle. In fact, it looks very similar to your > empirically determined 17/32 value. I wonder what are the parameters for > the order 5 bezier that reduce it to the order 4. > I have confirmed your statement about the approximation of circular arcs by degree 4 curves. It seems even better than the degree 5 arc with r0=17/32. I have applied the degree elevation formulas to deduce algebraically the conditions r0 and r1 should satisfy in order the degree 4 and degree 5 curves be equal. From my math exercise, we should have: degree 5 with r0 = 3/5 and r1=0 will be equivalent to degree 4 with r0=0 I also found that r0 may be set to 0 for degree 4 and r1 may be set to 0 for degree 5 but r0 should not be 0 for degree 5 because the arc degenerate into a line segment. I have changed the assert conditions in the my functions accordingly. I agree that rounding corners with degree 4 Bezier arcs give us enough flexibility and there is no point to use greater degree. In my functions, the parameter r of roundedPoly() controls how much the corner is rounded like your proposed d parameter. That parameter sets the end points relatively to the polygon edge length instead of an absolute value. The problem with this solution is that the arc will not be symmetrical when the two edges meeting a corner have different length. But the alternative of a absolute value d requires a validation to avoid that two arcs rounding the two corners of an edge intercept. Finally, I have checked that my code works well even with not convex polygons as can be seen in the image.
NH
nop head
Fri, Mar 15, 2019 8:11 AM

Going back to the apple article I don't think the change in shade is
anything to do with curvature. Reflected light is related to the surface
angle and that doesn't change discontinuously. It's rate of change does but
I don't see how that would affect reflected light. It looks like the left
corner is lit from both sides and the right corner is lit from right side
only.

On Fri, 15 Mar 2019 at 03:15, Ronaldo Persiano rcmpersiano@gmail.com
wrote:

No it doesn't.  I posted graphs a few messages back showing zero curvature

order 3 beziers, and I had directly verified that the curvature was indeed
zero by calculating the derivatives both symbolically and numerically, so
I
am reasonably sure it was correct.  With p0=p3 set to the endpoints of
the
arc you then set p1=p2 equal to the point of the corner.  You achieve the
co-linearity condition in a degenerate fashion, since p1 and p2 are on
both
lines.

You are right. Putting both intermediate control points at the corner will
meet the conditions of zero curvature at the two ends of a degree 3 Bezier
arc. I could not imagine that solution before. And certainly this is a very
constrained alternative.

It appears that your degree 4 code can also generate a nearly circular
arc:
just set r1 very small, like .01 and you get something visually
indistinguishable from a circle.  In fact, it looks very similar to your
empirically determined 17/32 value.  I wonder what are the parameters for
the order 5 bezier that reduce it to the order 4.

I have confirmed your statement about the approximation of circular arcs
by degree 4 curves. It seems even better than the degree 5 arc with
r0=17/32.

I have applied the degree elevation formulas to deduce algebraically the
conditions r0 and r1 should satisfy in order the degree 4 and degree 5
curves be equal. From my math exercise, we should have:

degree 5 with  r0 = 3/5  and r1=0 will be equivalent to
degree 4 with r0=0

I also found that r0 may be set to 0 for degree 4 and r1 may be set to 0
for degree 5 but r0 should not be 0 for degree 5 because the arc degenerate
into a line segment. I have changed the assert conditions in the my
functions accordingly.

I agree that rounding corners with degree 4 Bezier arcs give us enough
flexibility and there is no point to use greater degree. In my functions,
the parameter r of roundedPoly() controls how much the corner is rounded
like your proposed d parameter. That parameter sets the end points
relatively to the polygon edge length instead of an absolute value. The
problem with this solution is that the arc will not be symmetrical when the
two edges meeting a corner have different length. But the alternative of a
absolute value d requires a validation to avoid that two arcs rounding the
two corners of an edge intercept.

Finally, I have checked that my code works well even with not convex
polygons as can be seen in the image.


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

Going back to the apple article I don't think the change in shade is anything to do with curvature. Reflected light is related to the surface angle and that doesn't change discontinuously. It's rate of change does but I don't see how that would affect reflected light. It looks like the left corner is lit from both sides and the right corner is lit from right side only. On Fri, 15 Mar 2019 at 03:15, Ronaldo Persiano <rcmpersiano@gmail.com> wrote: > No it doesn't. I posted graphs a few messages back showing zero curvature >> order 3 beziers, and I had directly verified that the curvature was indeed >> zero by calculating the derivatives both symbolically and numerically, so >> I >> am reasonably sure it was correct. With p0=p3 set to the endpoints of >> the >> arc you then set p1=p2 equal to the point of the corner. You achieve the >> co-linearity condition in a degenerate fashion, since p1 and p2 are on >> both >> lines. > > > You are right. Putting both intermediate control points at the corner will > meet the conditions of zero curvature at the two ends of a degree 3 Bezier > arc. I could not imagine that solution before. And certainly this is a very > constrained alternative. > > >> It appears that your degree 4 code can also generate a nearly circular >> arc: >> just set r1 very small, like .01 and you get something visually >> indistinguishable from a circle. In fact, it looks very similar to your >> empirically determined 17/32 value. I wonder what are the parameters for >> the order 5 bezier that reduce it to the order 4. >> > > I have confirmed your statement about the approximation of circular arcs > by degree 4 curves. It seems even better than the degree 5 arc with > r0=17/32. > > I have applied the degree elevation formulas to deduce algebraically the > conditions r0 and r1 should satisfy in order the degree 4 and degree 5 > curves be equal. From my math exercise, we should have: > > degree 5 with r0 = 3/5 and r1=0 will be equivalent to > degree 4 with r0=0 > > > I also found that r0 may be set to 0 for degree 4 and r1 may be set to 0 > for degree 5 but r0 should not be 0 for degree 5 because the arc degenerate > into a line segment. I have changed the assert conditions in the my > functions accordingly. > > I agree that rounding corners with degree 4 Bezier arcs give us enough > flexibility and there is no point to use greater degree. In my functions, > the parameter r of roundedPoly() controls how much the corner is rounded > like your proposed d parameter. That parameter sets the end points > relatively to the polygon edge length instead of an absolute value. The > problem with this solution is that the arc will not be symmetrical when the > two edges meeting a corner have different length. But the alternative of a > absolute value d requires a validation to avoid that two arcs rounding the > two corners of an edge intercept. > > Finally, I have checked that my code works well even with not convex > polygons as can be seen in the image. > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >
RP
Ronaldo Persiano
Fri, Mar 15, 2019 2:07 PM

I understand your point because I am also unable to perceive visually
curvature discontinuities. But people from visual arts have training eye to
perceive it. However, even for people like us it may be noticible on
shinning and reflecting surfaces.

The following YouTube video gives an idea of the effect of different kinds
of continuity.

https://youtu.be/ryVe0aTTfrc

It was clearer to me the effect of the various kinds of continuity with the
stripe view. Designers from automobile industry are very concerned with the
effect of shadows and light reflexions on the surface of their models.

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.

I understand your point because I am also unable to perceive visually curvature discontinuities. But people from visual arts have training eye to perceive it. However, even for people like us it may be noticible on shinning and reflecting surfaces. The following YouTube video gives an idea of the effect of different kinds of continuity. https://youtu.be/ryVe0aTTfrc It was clearer to me the effect of the various kinds of continuity with the stripe view. Designers from automobile industry are very concerned with the effect of shadows and light reflexions on the surface of their models. 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. >
P
Parkinbot
Fri, Mar 15, 2019 3:01 PM

nophead wrote

Going back to the apple article I don't think the change in shade is
anything to do with curvature. Reflected light is related to the surface
angle and that doesn't change discontinuously. It's rate of change does
but
I don't see how that would affect reflected light. It looks like the left
corner is lit from both sides and the right corner is lit from right side
only.

You wouldn't see it on completely mat or reflected surface. But on brushed
or structured surfaces a lot of additional effects accumulate. Neverless,
DIY-people like most of us in this forum, me including, with a "function
first" attitude usually have only a poor understanding of surface erotics.
Only after having read "Zen And The Art Of Motorcycle Maintenance" I could
develop a first poor understandig about what kind of gears seem to purr
within Apple customer brains.

In Open Source based 3D printing, where 90% of the prints are done with
layers >= 0.2 mm and nozzles >= 0.4mm there is no point in trying to
optimize curvatures to C3 or more.

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

nophead wrote > Going back to the apple article I don't think the change in shade is > anything to do with curvature. Reflected light is related to the surface > angle and that doesn't change discontinuously. It's rate of change does > but > I don't see how that would affect reflected light. It looks like the left > corner is lit from both sides and the right corner is lit from right side > only. You wouldn't see it on completely mat or reflected surface. But on brushed or structured surfaces a lot of additional effects accumulate. Neverless, DIY-people like most of us in this forum, me including, with a "function first" attitude usually have only a poor understanding of surface erotics. Only after having read "Zen And The Art Of Motorcycle Maintenance" I could develop a first poor understandig about what kind of gears seem to purr within Apple customer brains. In Open Source based 3D printing, where 90% of the prints are done with layers >= 0.2 mm and nozzles >= 0.4mm there is no point in trying to optimize curvatures to C3 or more. -- Sent from: http://forum.openscad.org/
G
Gadgetmind
Fri, Mar 15, 2019 4:39 PM

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

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
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/
A
adrianv
Wed, Mar 20, 2019 1:41 AM

I did a 3d printing test to assess how much of a difference these roundovers
make in the real world.    I printed four 50mm squares and rounded them
using my previous code with a "cut" setting.  I made one using circular arcs
with a cut of 5mm (and found a bug in my code---circles are definitely more
trouble) and I did the other three using the settings [5,.7], [5,.5], and
[5*.97,.3]  where I reduced the last one so the roundover would fit on the
square.

In comparing the printed objects, I note first of all that the circular
rounded model shows a clear line visible in reflected light as I shift it
around, so the transition between the flat part of the model and the curved
part is visible.  No such transition line is visible in any of the
continuous curvature 3 cases.  In comparing the 0.3 case to the 0.7 case I
am able to see the flat section light up in reflected light all at once, but
it does so without the sharp edges of the circular case.  The 0.3 case has
no flat section so it never has a section that lights up.

If I feel the models the circular model has what feels like a perceptible
lump at the transition.  The transition is tactile.  The other three cases
are indistinguishable and all feel smooth, with no perceptible transition.

My conclusion is that for models where appearance and/or feel are important,
it's better to choose the continuous curvature roundover.  And really,
there's no reason not to use it for 2d scenarios since the code is now
available in cases like this (or, if you prefer to write yourself...it's
easier to write than the circular case).

The other conclusion is that it doesn't seem to matter much if you pick the
curvature parameter anywhere in the range of [0.3,0.7], as they all feel the
same.  I think that the 0.3 looks slightly more elegant visually---the more
gradual curve is visually perceptible---but it does require a lot more room
to execute the curve.  I would suggest that if elegant appearance is
paramount, choose the smallest curvature parameter that fits with your
model.

I would post pictures but I don't think any of this stuff can be conveyed
photographically.  I asked a second person to examine the models without
explaining what was different, and presenting the models in a blind fashion,
and my observations were confirmed, so I think I didn't just dream it up.

Of course, I now wonder about the analogous 3d roundover problem.  Can we
make a continuous curvature rounded cube in a similar fashion?

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

I did a 3d printing test to assess how much of a difference these roundovers make in the real world. I printed four 50mm squares and rounded them using my previous code with a "cut" setting. I made one using circular arcs with a cut of 5mm (and found a bug in my code---circles are definitely more trouble) and I did the other three using the settings [5,.7], [5,.5], and [5*.97,.3] where I reduced the last one so the roundover would fit on the square. In comparing the printed objects, I note first of all that the circular rounded model shows a clear line visible in reflected light as I shift it around, so the transition between the flat part of the model and the curved part is visible. No such transition line is visible in any of the continuous curvature 3 cases. In comparing the 0.3 case to the 0.7 case I am able to see the flat section light up in reflected light all at once, but it does so without the sharp edges of the circular case. The 0.3 case has no flat section so it never has a section that lights up. If I feel the models the circular model has what feels like a perceptible lump at the transition. The transition is tactile. The other three cases are indistinguishable and all feel smooth, with no perceptible transition. My conclusion is that for models where appearance and/or feel are important, it's better to choose the continuous curvature roundover. And really, there's no reason not to use it for 2d scenarios since the code is now available in cases like this (or, if you prefer to write yourself...it's easier to write than the circular case). The other conclusion is that it doesn't seem to matter much if you pick the curvature parameter anywhere in the range of [0.3,0.7], as they all feel the same. I think that the 0.3 looks slightly more elegant visually---the more gradual curve is visually perceptible---but it does require a lot more room to execute the curve. I would suggest that if elegant appearance is paramount, choose the smallest curvature parameter that fits with your model. I would post pictures but I don't think any of this stuff can be conveyed photographically. I asked a second person to examine the models without explaining what was different, and presenting the models in a blind fashion, and my observations were confirmed, so I think I didn't just dream it up. Of course, I now wonder about the analogous 3d roundover problem. Can we make a continuous curvature rounded cube in a similar fashion? -- Sent from: http://forum.openscad.org/
P
Parkinbot
Wed, Mar 20, 2019 2:24 PM

adrianv wrote

Of course, I now wonder about the analogous 3d roundover problem.  Can we
make a continuous curvature rounded cube in a similar fashion?

It shouldn't be too difficult to rotate_extrude such an arc rounding a 90°
corner and to translate/rotate 8 instances to the corners of a cube and to
hull them. Have a try.

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

adrianv wrote > Of course, I now wonder about the analogous 3d roundover problem. Can we > make a continuous curvature rounded cube in a similar fashion? It shouldn't be too difficult to rotate_extrude such an arc rounding a 90° corner and to translate/rotate 8 instances to the corners of a cube and to hull them. Have a try. -- Sent from: http://forum.openscad.org/
A
adrianv
Wed, Mar 20, 2019 3:43 PM

Parkinbot wrote

adrianv wrote

Of course, I now wonder about the analogous 3d roundover problem.  Can we
make a continuous curvature rounded cube in a similar fashion?

It shouldn't be too difficult to rotate_extrude such an arc rounding a 90°
corner and to translate/rotate 8 instances to the corners of a cube and to
hull them. Have a try.

Wouldn't rotate extruding give a shape with discontinuous curvature in the
direction of rotation?  It's the equivalent of the circular roundover, so
where it meets the linear section (the rounded edge) the curvature of the
edge will be zero and the curvature of the extruded corner will be nonzero.
It seems like some 3d bezier approach is necessary to construct the shape in
the corner.  And curvature on a surface now is a vector of two values, so
maybe matching curvature is more difficult?

If I wanted a cylinder with a rounded end the rotate extrude method should
work.

Perhaps if I did a sweep of the shape I have already constructed along a
path defined by the same shape?  Would that work?

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

Parkinbot wrote > adrianv wrote >> Of course, I now wonder about the analogous 3d roundover problem. Can we >> make a continuous curvature rounded cube in a similar fashion? > > It shouldn't be too difficult to rotate_extrude such an arc rounding a 90° > corner and to translate/rotate 8 instances to the corners of a cube and to > hull them. Have a try. Wouldn't rotate extruding give a shape with discontinuous curvature in the direction of rotation? It's the equivalent of the circular roundover, so where it meets the linear section (the rounded edge) the curvature of the edge will be zero and the curvature of the extruded corner will be nonzero. It seems like some 3d bezier approach is necessary to construct the shape in the corner. And curvature on a surface now is a vector of two values, so maybe matching curvature is more difficult? If I wanted a cylinder with a rounded end the rotate extrude method should work. Perhaps if I did a sweep of the shape I have already constructed along a path defined by the same shape? Would that work? -- Sent from: http://forum.openscad.org/
P
Parkinbot
Wed, Mar 20, 2019 5:24 PM

adrianv wrote

Wouldn't rotate extruding give a shape with discontinuous curvature in the
direction of rotation?  It's the equivalent of the circular roundover, so

this is correct. But it is a start.

Looking at a poor man's cube with rounded edges:

r0 = 5;
r = 10;
hull() for(i=[-r, r], j=[-r, r],k=[-r, r]) translate([i,j,k]) sphere(r0,
$fn=40);

http://forum.openscad.org/file/t887/roundedcube.png

shows that you have to produce appropriate corner pieces that will have
proper transitions of the three corners. If you know where you have to go,
you can try to define a sweep path for it. For this you need to find a
proper parametrization of your path along the z-axis, that will transit from
a rect to the rounded path.

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

adrianv wrote > Wouldn't rotate extruding give a shape with discontinuous curvature in the > direction of rotation? It's the equivalent of the circular roundover, so this is correct. But it is a start. Looking at a poor man's cube with rounded edges: r0 = 5; r = 10; hull() for(i=[-r, r], j=[-r, r],k=[-r, r]) translate([i,j,k]) sphere(r0, $fn=40); <http://forum.openscad.org/file/t887/roundedcube.png> shows that you have to produce appropriate corner pieces that will have proper transitions of the three corners. If you know where you have to go, you can try to define a sweep path for it. For this you need to find a proper parametrization of your path along the z-axis, that will transit from a rect to the rounded path. -- Sent from: http://forum.openscad.org/
A
adrianv
Wed, Mar 20, 2019 5:47 PM

Maybe my idea wasn't clear.  Suppose I start with square =
[[0,0],[1,0],[1,1],[0,1]], and then apply my roundcorners function, so
roundsquare = roundedcorners(square,...).  Now roundsquare is a path that
traces out a square with continuously rounded corners.  If I use roundsquare
as a shape and sweep it along the path (elevated to 3d) of 5*roundsquare
that should give me a sort of rectangular torus with smooth edges.  So I
union in some filler cube in the center and the result should hopefully be a
rounded cube with continuous curvature.

It seems like the alternative approach would be to actually figure out how
bezier curves work in 3d and directly implement the required corner patch

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

Maybe my idea wasn't clear. Suppose I start with square = [[0,0],[1,0],[1,1],[0,1]], and then apply my roundcorners function, so roundsquare = roundedcorners(square,...). Now roundsquare is a path that traces out a square with continuously rounded corners. If I use roundsquare as a shape and sweep it along the path (elevated to 3d) of 5*roundsquare that should give me a sort of rectangular torus with smooth edges. So I union in some filler cube in the center and the result should hopefully be a rounded cube with continuous curvature. It seems like the alternative approach would be to actually figure out how bezier curves work in 3d and directly implement the required corner patch -- Sent from: http://forum.openscad.org/
P
Parkinbot
Wed, Mar 20, 2019 6:29 PM

adrianv wrote

Maybe my idea wasn't clear.  Suppose I start with square =
[[0,0],[1,0],[1,1],[0,1]], and then apply my roundcorners function, so
roundsquare = roundedcorners(square,...).  Now roundsquare is a path that
traces out a square with continuously rounded corners.

I understand this and that you want to go the hard way (for which
rotate_extrude will not do).
In order to do a sweep you need to create a sequence of polygons that can be
coated. Thus you have to define this sequence so that the polygons also will
grow in the desired way (as given by roundsquare) and find the
z-coordinate sequence that will also reflect the roundsquare path and the
roundedcorners rules.
With reference to my last image: You will have to define and arrange the
extrusion polygons in the way it is shown there as layers.
As I understand your approach you currently can gradually refine a given
corner in xy-space, but you don't have the means (parameters) to produce a
sequence arranged in the same sense as these layers are: so that the middle
point will follow the roundsquare path in z direction, as well as in any
other direction.

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

adrianv wrote > Maybe my idea wasn't clear. Suppose I start with square = > [[0,0],[1,0],[1,1],[0,1]], and then apply my roundcorners function, so > roundsquare = roundedcorners(square,...). Now roundsquare is a path that > traces out a square with continuously rounded corners. I understand this and that you want to go the hard way (for which rotate_extrude will not do). In order to do a sweep you need to create a sequence of polygons that can be coated. Thus you have to define this sequence so that the polygons also will *grow* in the desired way (as given by roundsquare) and find the z-coordinate sequence that will also reflect the roundsquare path and the roundedcorners rules. With reference to my last image: You will have to define and arrange the extrusion polygons in the way it is shown there as layers. As I understand your approach you currently can gradually refine a given corner in xy-space, but you don't have the means (parameters) to produce a sequence arranged in the same sense as these layers are: so that the middle point will follow the roundsquare path in z direction, as well as in any other direction. -- Sent from: http://forum.openscad.org/
P
Parkinbot
Wed, Mar 20, 2019 10:38 PM

Here some code for my initial approach using rotate_extrude to make a corner
and hull it. I used Ronaldos Bezier implementation. The horizontal edge
roundings are Bezier roundings, and the vertical ones are quarter circles,
due to the rotate_extrude call.
Now, look at the corner and study how you would sweep the rounding (xy) with
a Bezier instead of a quarter circle.

http://forum.openscad.org/file/t887/BezierCube.png

BezierCube(30, 200);
// #cube(200, center = true);  // sizetest

module BezierCube(r = 30, s = 100)
{
q = [[0,r], [r,r], [r,0]];
p = concat([[0,0]], BZeroCurvature(q[0],q[1],q[2],n=20,r0=2/3,r1=1/2)); //
the polygon
hull() // construct the cube by hulling the corners
for(i=[0:3], j=[1,-1]) scale(j)rotate(i*90) translate([s/2-r,s/2-r,
s/2-r]) corner(p);
}
module corner(p)  rotate_extrude(angle = 90, $fa=1) polygon(p);

function BezierPoint(p, u) =
(len(p) == 2)?
u*p[1] + (1-u)p[0] :
u
BezierPoint([for(i=[1:len(p)-1]) p[i] ], u)
+ (1-u)*BezierPoint([for(i=[0:len(p)-2]) p[i] ], u);

function BezierCurve(p, n=10) = [for(i=[0:n-1]) BezierPoint(p, i/(n-1)) ];

function BZeroCurvature(p0,p1,p2,n=20,r0=2/3,r1=1/2) =
assert(r0>0 && r0<1 && r1>0 && r1<1, "improper value of r0 or r1")
let( p = [ p0,
p0 + r0*(p1-p0)r1,
p0 + r0
(p1-p0),
p2 + r0*(p1-p2),
p2 + r0*(p1-p2)*r1,
p2 ] )
BezierCurve(p,n);

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

Here some code for my initial approach using rotate_extrude to make a corner and hull it. I used Ronaldos Bezier implementation. The horizontal edge roundings are Bezier roundings, and the vertical ones are quarter circles, due to the rotate_extrude call. Now, look at the corner and study how you would sweep the rounding (xy) with a Bezier instead of a quarter circle. <http://forum.openscad.org/file/t887/BezierCube.png> BezierCube(30, 200); // #cube(200, center = true); // sizetest module BezierCube(r = 30, s = 100) { q = [[0,r], [r,r], [r,0]]; p = concat([[0,0]], BZeroCurvature(q[0],q[1],q[2],n=20,r0=2/3,r1=1/2)); // the polygon hull() // construct the cube by hulling the corners for(i=[0:3], j=[1,-1]) scale(j)rotate(i*90) translate([s/2-r,s/2-r, s/2-r]) corner(p); } module corner(p) rotate_extrude(angle = 90, $fa=1) polygon(p); function BezierPoint(p, u) = (len(p) == 2)? u*p[1] + (1-u)*p[0] : u*BezierPoint([for(i=[1:len(p)-1]) p[i] ], u) + (1-u)*BezierPoint([for(i=[0:len(p)-2]) p[i] ], u); function BezierCurve(p, n=10) = [for(i=[0:n-1]) BezierPoint(p, i/(n-1)) ]; function BZeroCurvature(p0,p1,p2,n=20,r0=2/3,r1=1/2) = assert(r0>0 && r0<1 && r1>0 && r1<1, "improper value of r0 or r1") let( p = [ p0, p0 + r0*(p1-p0)*r1, p0 + r0*(p1-p0), p2 + r0*(p1-p2), p2 + r0*(p1-p2)*r1, p2 ] ) BezierCurve(p,n); -- Sent from: http://forum.openscad.org/
P
Parkinbot
Wed, Mar 20, 2019 11:44 PM

OK, and here is some code that sweeps the corners in the desired way. It
scales each polygon in the sequence to get the desired extension for the xy
path before putting it into 3D (by z-rotating it (Rz)). By this you get a
bezier in all three directions.
Although it is another piece of work, it shouldn't be too difficult to
transfer this scheme into a single (and fast processing) sweep path to avoid
the unions.

http://forum.openscad.org/file/t887/BezierCube1.png

use <Naca_Sweep.scad>  // https://www.thingiverse.com/thing:1208001

BezierCube(30, 200);

module BezierCube(r = 30, s = 100)
{
q = [[0.001,r], [r,r], [r,0.001]];
b = BZeroCurvature(q[0],q[1],q[2],n=20,r0=4/5,r1=2/3);
hull() // construct the cube by hulling the corners
for(i=[0:3], j=[1,-1]) scale(j)rotate(i*90) translate([s/2-r,s/2-r,
s/2-r])
bcorner(b, r);
}

module bcorner(b, r)
{
sweep(gendata(b,r));
function gendata(b,r) =
[
let(step = 90/(len(b)-1))
for(x=[0:len(b)-1])
let(l = norm(b[x])/r)  // scale by bezier
Rz(x*step, Sx(l, Rx(90, vec3(b)))) // rotatex, scalex and rotatez
];
}

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

OK, and here is some code that sweeps the corners in the desired way. It scales each polygon in the sequence to get the desired extension for the xy path before putting it into 3D (by z-rotating it (Rz)). By this you get a bezier in all three directions. Although it is another piece of work, it shouldn't be too difficult to transfer this scheme into a single (and fast processing) sweep path to avoid the unions. <http://forum.openscad.org/file/t887/BezierCube1.png> use <Naca_Sweep.scad> // https://www.thingiverse.com/thing:1208001 BezierCube(30, 200); module BezierCube(r = 30, s = 100) { q = [[0.001,r], [r,r], [r,0.001]]; b = BZeroCurvature(q[0],q[1],q[2],n=20,r0=4/5,r1=2/3); hull() // construct the cube by hulling the corners for(i=[0:3], j=[1,-1]) scale(j)rotate(i*90) translate([s/2-r,s/2-r, s/2-r]) bcorner(b, r); } module bcorner(b, r) { sweep(gendata(b,r)); function gendata(b,r) = [ let(step = 90/(len(b)-1)) for(x=[0:len(b)-1]) let(l = norm(b[x])/r) // scale by bezier Rz(x*step, Sx(l, Rx(90, vec3(b)))) // rotatex, scalex and rotatez ]; } -- Sent from: http://forum.openscad.org/
RP
Ronaldo Persiano
Thu, Mar 21, 2019 1:34 AM

adrianv avm4@cornell.edu wrote:

It seems like the alternative approach would be to actually figure out how
bezier curves work in 3d and directly implement the required corner patch.

Yes, that is far better and easier than the sweep idea. I am travelling
without my notebook and have no way to develop it here in detail. But I
will give you some general ideas.

A rectangular Bézier surface patch is a parametric bivariate polynomial.
Its control points (CP) are usually represented by a bidimensional matrix
of points whose columns represent the control of one of the parameter and
the rows the control of the other parameter. For instance, the surface
patch of the roundover of a cube edge like you suggested has a CP matrix
with two columns with 5 points each. It is a degree 1 by degree 4 Bézier
surface.

For the corner, we will need at least a degree 4 by degree 4 Bézier patch
which has 25 control points in a matrix 5x5.

A point in a Bézier patch with a matrix of control points P corresponding
to a pair of parameters (u, v) can be easily computed by the following
simple code:

function BPatchPoint(P, u, v) =
transpose(BezierPoint(transpose(BezierPoint(P, u)), v));

where transpose() is the matrix transpose and BezierPoint() is the function
I defined before. A polyhedral approximation of the patch can be generated
by calling this function for a matrix of parameters (ui, vi).

Given two patches joined side by side, to have curvature continuity between
them all that is needed is to satisfy the curvature continuity condition by
the rows of CPs, row by row, as they were CPs of simple independent curves.

With that in mind, we could devise a patch to roundover a cube corner with
curvature continuity.

I will be back home soon and I hope to detail this stuff in two days. I
also have some comments about your curvature study and graphs but I have to
test my ideas first.

adrianv <avm4@cornell.edu> wrote: > > It seems like the alternative approach would be to actually figure out how > bezier curves work in 3d and directly implement the required corner patch. > Yes, that is far better and easier than the sweep idea. I am travelling without my notebook and have no way to develop it here in detail. But I will give you some general ideas. A rectangular Bézier surface patch is a parametric bivariate polynomial. Its control points (CP) are usually represented by a bidimensional matrix of points whose columns represent the control of one of the parameter and the rows the control of the other parameter. For instance, the surface patch of the roundover of a cube edge like you suggested has a CP matrix with two columns with 5 points each. It is a degree 1 by degree 4 Bézier surface. For the corner, we will need at least a degree 4 by degree 4 Bézier patch which has 25 control points in a matrix 5x5. A point in a Bézier patch with a matrix of control points P corresponding to a pair of parameters (u, v) can be easily computed by the following simple code: function BPatchPoint(P, u, v) = transpose(BezierPoint(transpose(BezierPoint(P, u)), v)); where transpose() is the matrix transpose and BezierPoint() is the function I defined before. A polyhedral approximation of the patch can be generated by calling this function for a matrix of parameters (ui, vi). Given two patches joined side by side, to have curvature continuity between them all that is needed is to satisfy the curvature continuity condition by the rows of CPs, row by row, as they were CPs of simple independent curves. With that in mind, we could devise a patch to roundover a cube corner with curvature continuity. I will be back home soon and I hope to detail this stuff in two days. I also have some comments about your curvature study and graphs but I have to test my ideas first.
RP
Ronaldo Persiano
Thu, Mar 21, 2019 3:35 PM

A point in a Bézier patch with a matrix of control points P corresponding
to a pair of parameters (u, v) can be easily computed by the following
simple code:

function BPatchPoint(P, u, v) =
transpose(BezierPoint(transpose(BezierPoint(P, u)), v));

where transpose() is the matrix transpose and BezierPoint() is the
function I defined before.

There is an error in that code: transposition is not needed. The correct
code is even simpler:

function BPatchPoint(P, u, v) =
BezierPoint(BezierPoint(P, u), v);

As the shape of the corner roundover patch is triangular I am considering
to model it with triangular Bezier patches of degree 6.

> > A point in a Bézier patch with a matrix of control points P corresponding > to a pair of parameters (u, v) can be easily computed by the following > simple code: > > function BPatchPoint(P, u, v) = > transpose(BezierPoint(transpose(BezierPoint(P, u)), v)); > > where transpose() is the matrix transpose and BezierPoint() is the > function I defined before. > There is an error in that code: transposition is not needed. The correct code is even simpler: function BPatchPoint(P, u, v) = BezierPoint(BezierPoint(P, u), v); As the shape of the corner roundover patch is triangular I am considering to model it with triangular Bezier patches of degree 6.
P
Parkinbot
Thu, Mar 21, 2019 8:15 PM

Ronaldo wrote

As the shape of the corner roundover patch is triangular I am considering
to model it with triangular Bezier patches of degree 6.

No doubt that this can be easily done. I remember an older thread, where you
showed it. But how would you automatically weave in such a patch into a
sweep or polyhedron that coats a larger structure like a roundedCube? Wasn't
that one the problems?
I didn't show it in my code, but it is straightforward if you have a quad
patch (which is squashed at one end).

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

Ronaldo wrote > As the shape of the corner roundover patch is triangular I am considering > to model it with triangular Bezier patches of degree 6. No doubt that this can be easily done. I remember an older thread, where you showed it. But how would you automatically weave in such a patch into a sweep or polyhedron that coats a larger structure like a roundedCube? Wasn't that one the problems? I didn't show it in my code, but it is straightforward if you have a quad patch (which is squashed at one end). -- Sent from: http://forum.openscad.org/
RP
Ronaldo Persiano
Fri, Mar 22, 2019 1:19 PM

Given two patches joined side by side, to have curvature continuity
between them all that is needed is to satisfy the curvature continuity
condition by the rows of CPs, row by row, as they were CPs of simple
independent curves.
With that in mind, we could devise a patch to roundover a cube corner with
curvature continuity.

Following that line of thought, here is a rectangular patch to provide a
curvature continuity in rounding a corner of a cube.

[image: cornerRoundingI (1).PNG]
The following image shows the mesh of control points (CPs) compared with
with the patch itself.

[image: cornerRounding-CP.PNG]

As can be seen, all CPs rest on the faces of the cube in an array where one
full row of the mesh is collapsed to a point. Some intermediate rows and
columns of the mesh are movable by changing a shape parameter, others CPs
have immutable positions. The mesh of CPs of a corner were computed by the
following code:

function cornerPatchCP(P0,d,r0=0.5) =
let( P1 = P0+d*[1,0,0],
P2 = P0+d*[0,1,0],
P3 = P0+d*[0,0,1] )
[ [for(j=[0:4]) P1+P2],                                  // i=0
let(p0=P1+(1-r0)P2,p1=(P1+P2)(1-r0),p2=P1*(1-r0)+P2) // i=1
[p0,p0+r0*(p1-p0),p1,p2+r0*(p1-p2),p2],
let(p0=P1,p1=P0,p2=P2)                                // i=2
[p0,p0+r0*(p1-p0),p1,p2+r0*(p1-p2),p2],
let(p0=P1+(1-r0)P3,p1=(1-r0)P3,p2=P2+(1-r0)P3)      // i=3
[p0,p0+r0
(p1-p0),p1,p2+r0
(p1-p2),p2],
let(p0=P1+P3,p1=P3,p2=P2+P3)                          // i=4
[p0,p0+r0
(p1-p0),p1,p2+r0*(p1-p2),p2] ];

Although it is an awkward code, it was easier to be written following the
continuity conditions. The arguments of this function are:

P0 - the coordinates of the corner
d  - the extent of cube corner that will be rounded
r0 - a shape parameter equivalent to the shape parameter of the degree 4
curves with curvature continuity

From the CP matrix, we can sample points on the corner surface by

evaluating BPatchPoint(CPs,u,v) for various values of u and v in the
interval [0,1] and draw isoparametric lines or build a mesh for a
polyhedron call.

I don't like this solution. The collapse of one CP matrix row creates an
inconvenient asymmetry that can be observed by comparing the corner
rounding surface for r0 = 0.073 with the surface of a sphere:

[image: cornerRounding-sphere.PNG]

The image suggests that we have just one symmetry axis instead of 3 as
would be desirable.

Besides, a regular sample of parameters to compute points on the surface
are very irregular with a high concentration of points in the neighborhood
of the point the row was collapsed. That is a reason to pursuit a solution
based on Bezier triangular patches.

The corner surface described above has 25 CPs and a total degree of 8. My
first glance on that indicates that a degree 4 and degree 5 Bezier
triangular patch have not enough degree of freedom to accommodate the
curvature continuity conditions. Possibly a degree 6 triangular patch, with
28 CPs, will have room to satisfy all needed conditions. That will be my
next investigation.

Parkinbot rudolf@digitaldocument.de wrote:

But how would you automatically weave in such a patch into a
sweep or polyhedron that coats a larger structure like a roundedCube?
Wasn't
that one the problems?

I have solved this problem before and reported here. My lazyUnion function
is able to not only union closed manifold but stitch patches. It is
irrelevant for that module whether the patches are manifold or not. The
only condition is that each element of the incoming list is in a polyhedron
data format. And to generate a polyhedron data format for a matrix of
points (a regular mesh) or even a triangular patch is an easy task. To have
a manifold at the end is user responsability. To get it we need that the
points on the border of a patch match the points on border of a patch it
should join to and that the whole model is watertight.

> > Given two patches joined side by side, to have curvature continuity > between them all that is needed is to satisfy the curvature continuity > condition by the rows of CPs, row by row, as they were CPs of simple > independent curves. > With that in mind, we could devise a patch to roundover a cube corner with > curvature continuity. Following that line of thought, here is a rectangular patch to provide a curvature continuity in rounding a corner of a cube. [image: cornerRoundingI (1).PNG] The following image shows the mesh of control points (CPs) compared with with the patch itself. [image: cornerRounding-CP.PNG] As can be seen, all CPs rest on the faces of the cube in an array where one full row of the mesh is collapsed to a point. Some intermediate rows and columns of the mesh are movable by changing a shape parameter, others CPs have immutable positions. The mesh of CPs of a corner were computed by the following code: function cornerPatchCP(P0,d,r0=0.5) = let( P1 = P0+d*[1,0,0], P2 = P0+d*[0,1,0], P3 = P0+d*[0,0,1] ) [ [for(j=[0:4]) P1+P2], // i=0 let(p0=P1+(1-r0)*P2,p1=(P1+P2)*(1-r0),p2=P1*(1-r0)+P2) // i=1 [p0,p0+r0*(p1-p0),p1,p2+r0*(p1-p2),p2], let(p0=P1,p1=P0,p2=P2) // i=2 [p0,p0+r0*(p1-p0),p1,p2+r0*(p1-p2),p2], let(p0=P1+(1-r0)*P3,p1=(1-r0)*P3,p2=P2+(1-r0)*P3) // i=3 [p0,p0+r0*(p1-p0),p1,p2+r0*(p1-p2),p2], let(p0=P1+P3,p1=P3,p2=P2+P3) // i=4 [p0,p0+r0*(p1-p0),p1,p2+r0*(p1-p2),p2] ]; Although it is an awkward code, it was easier to be written following the continuity conditions. The arguments of this function are: P0 - the coordinates of the corner d - the extent of cube corner that will be rounded r0 - a shape parameter equivalent to the shape parameter of the degree 4 curves with curvature continuity >From the CP matrix, we can sample points on the corner surface by evaluating BPatchPoint(CPs,u,v) for various values of u and v in the interval [0,1] and draw isoparametric lines or build a mesh for a polyhedron call. I don't like this solution. The collapse of one CP matrix row creates an inconvenient asymmetry that can be observed by comparing the corner rounding surface for r0 = 0.073 with the surface of a sphere: [image: cornerRounding-sphere.PNG] The image suggests that we have just one symmetry axis instead of 3 as would be desirable. Besides, a regular sample of parameters to compute points on the surface are very irregular with a high concentration of points in the neighborhood of the point the row was collapsed. That is a reason to pursuit a solution based on Bezier triangular patches. The corner surface described above has 25 CPs and a total degree of 8. My first glance on that indicates that a degree 4 and degree 5 Bezier triangular patch have not enough degree of freedom to accommodate the curvature continuity conditions. Possibly a degree 6 triangular patch, with 28 CPs, will have room to satisfy all needed conditions. That will be my next investigation. Parkinbot <rudolf@digitaldocument.de> wrote: > But how would you automatically weave in such a patch into a > sweep or polyhedron that coats a larger structure like a roundedCube? > Wasn't > that one the problems? > I have solved this problem before and reported here. My lazyUnion function is able to not only union closed manifold but stitch patches. It is irrelevant for that module whether the patches are manifold or not. The only condition is that each element of the incoming list is in a polyhedron data format. And to generate a polyhedron data format for a matrix of points (a regular mesh) or even a triangular patch is an easy task. To have a manifold at the end is user responsability. To get it we need that the points on the border of a patch match the points on border of a patch it should join to and that the whole model is watertight.
P
Parkinbot
Sat, Mar 23, 2019 12:43 AM

Ronaldo,

well, the outcome of your solution doesn't look very different to mine. I
had to debug the corner() code a bit to use the correct rotation sequence.
The code for the Bezier triangle is rather simple and moved into the
function corner(). I think it shows a triple symmetrie. I transposed the
vertex matrix which is NxN to get a polygon sequence ordered by z. Therefore
the polygons can easily be extended to prepare a more complex sweep, like a
Bezier cube.

A BezierCube module implementing such a sweep on the basis of your Bezier
functions is shown by the following code. It renders in 0.5s  on my system.
However, the union test with a cube lasts 15s.

http://forum.openscad.org/file/t887/BezierCube2.png

use <Naca_sweep.scad>  // https://www.thingiverse.com/thing:1208001
BezierCube([200, 100, 50], 30, $fn=30, center =true);

module BezierCube(s = 100, r = 30, r0 = 3/4, r1=2/3, center = false)
{
n=$fn?$fn:360/$fa;  // resolution
s=s[0]==undef?[s,s,s]:s; // allow for vector and number
r = abs(r);
if(r==0)
cube(s, center=center);
else
translate(center?[0, 0, 0]:s/2+[r, r, r])
{
q = [[0.001,r], [r,r], [r,0.001]];
b = BZeroCurvature(q[0],q[1],q[2],n=n,r0=r0,r1=r1);
gd = corner(b,r);  // just a corner
sweep(composeCube(s/2, r, data=gd));
}

function composeCube(s, r, data) =
let(upper = [for(j=[0:len(data)-1])
let(S=[[s[0],s[1],0],[-s[0],s[1],0],[-s[0],-s[1],0],[s[0],-s[1], 0]])
[each for(i=[0:3]) Tz(s[2],T(S[i], Rz(90i, data[j])))]])
let(lower = [for(j=[len(data)-1:-1:0])
let(S=[[s[0],s[1],0],[-s[0],s[1],0],[-s[0],-s[1],0],[s[0],-s[1], 0]])
[each for(i=[0:3]) Tz(-s[2],T(S[i], Rz(90
i, Sz(-1, data[j]))))]])
concat(upper, lower) ;

function corner(b,r) = //
let(step = 90/(len(b)-1))
let (m=[for(x=[0: len(b)-1])
let(l = norm(b[x])/r)  // scale by bezier
let(a=atan(b[x][0]/b[x][1])) // get angle
Rz(a, Sx((l), Rx(90, vec3(b))))]) // rotatex, scalex and
rotatez
[for(i=[0:len(m)-1]) [for( j=[0:len(m[0])-1]) m[j][i]]]; // transpose
}

function BezierPoint(p, u) =
(len(p) == 2)?
u*p[1] + (1-u)p[0] :
u
BezierPoint([for(i=[1:len(p)-1]) p[i] ], u)
+ (1-u)*BezierPoint([for(i=[0:len(p)-2]) p[i] ], u);

function BezierCurve(p, n=10) = [for(i=[0:n-1]) BezierPoint(p, i/(n-1)) ];

function BZeroCurvature(p0,p1,p2,n=20,r0=2/3,r1=1/2) =
assert(r0>0 && r0<1 && r1>0 && r1<1, "improper value of r0 or r1")
let( p = [ p0,
p0 + r0*(p1-p0)r1,
p0 + r0
(p1-p0),
p2 + r0*(p1-p2),
p2 + r0*(p1-p2)*r1,
p2 ] )
BezierCurve(p,n);

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

Ronaldo, well, the outcome of your solution doesn't look very different to mine. I had to debug the corner() code a bit to use the correct rotation sequence. The code for the Bezier triangle is rather simple and moved into the function corner(). I think it shows a triple symmetrie. I transposed the vertex matrix which is NxN to get a polygon sequence ordered by z. Therefore the polygons can easily be extended to prepare a more complex sweep, like a Bezier cube. A BezierCube module implementing such a sweep on the basis of your Bezier functions is shown by the following code. It renders in 0.5s on my system. However, the union test with a cube lasts 15s. <http://forum.openscad.org/file/t887/BezierCube2.png> use <Naca_sweep.scad> // https://www.thingiverse.com/thing:1208001 BezierCube([200, 100, 50], 30, $fn=30, center =true); module BezierCube(s = 100, r = 30, r0 = 3/4, r1=2/3, center = false) { n=$fn?$fn:360/$fa; // resolution s=s[0]==undef?[s,s,s]:s; // allow for vector and number r = abs(r); if(r==0) cube(s, center=center); else translate(center?[0, 0, 0]:s/2+[r, r, r]) { q = [[0.001,r], [r,r], [r,0.001]]; b = BZeroCurvature(q[0],q[1],q[2],n=n,r0=r0,r1=r1); gd = corner(b,r); // just a corner sweep(composeCube(s/2, r, data=gd)); } function composeCube(s, r, data) = let(upper = [for(j=[0:len(data)-1]) let(S=[[s[0],s[1],0],[-s[0],s[1],0],[-s[0],-s[1],0],[s[0],-s[1], 0]]) [each for(i=[0:3]) Tz(s[2],T(S[i], Rz(90*i, data[j])))]]) let(lower = [for(j=[len(data)-1:-1:0]) let(S=[[s[0],s[1],0],[-s[0],s[1],0],[-s[0],-s[1],0],[s[0],-s[1], 0]]) [each for(i=[0:3]) Tz(-s[2],T(S[i], Rz(90*i, Sz(-1, data[j]))))]]) concat(upper, lower) ; function corner(b,r) = // let(step = 90/(len(b)-1)) let (m=[for(x=[0: len(b)-1]) let(l = norm(b[x])/r) // scale by bezier let(a=atan(b[x][0]/b[x][1])) // get angle Rz(a, Sx((l), Rx(90, vec3(b))))]) // rotatex, scalex and rotatez [for(i=[0:len(m)-1]) [for( j=[0:len(m[0])-1]) m[j][i]]]; // transpose } function BezierPoint(p, u) = (len(p) == 2)? u*p[1] + (1-u)*p[0] : u*BezierPoint([for(i=[1:len(p)-1]) p[i] ], u) + (1-u)*BezierPoint([for(i=[0:len(p)-2]) p[i] ], u); function BezierCurve(p, n=10) = [for(i=[0:n-1]) BezierPoint(p, i/(n-1)) ]; function BZeroCurvature(p0,p1,p2,n=20,r0=2/3,r1=1/2) = assert(r0>0 && r0<1 && r1>0 && r1<1, "improper value of r0 or r1") let( p = [ p0, p0 + r0*(p1-p0)*r1, p0 + r0*(p1-p0), p2 + r0*(p1-p2), p2 + r0*(p1-p2)*r1, p2 ] ) BezierCurve(p,n); -- Sent from: http://forum.openscad.org/
RP
Ronaldo Persiano
Sat, Mar 23, 2019 5:14 PM

That seems to be nice (I have not tried yet). However, I have devised what
seems to be a solution simplest than the patchwork I suggested before.

Compute one Bezier corner, lazyUnion() it with its rotation and mirror to
cover all cube vertices roundover and hull() it. As lazyUnion() and hull()
are fast, that may be faster than any other solution.

That seems to be nice (I have not tried yet). However, I have devised what seems to be a solution simplest than the patchwork I suggested before. Compute one Bezier corner, lazyUnion() it with its rotation and mirror to cover all cube vertices roundover and hull() it. As lazyUnion() and hull() are fast, that may be faster than any other solution.
P
Parkinbot
Sat, Mar 23, 2019 6:13 PM

Ronaldo wrote

Compute one Bezier corner, lazyUnion() it with its rotation and mirror to
cover all cube vertices roundover and hull() it. As lazyUnion() and hull()
are fast, that may be faster than any other solution.

Good point and strategy.
That was actually the solution I showed in
http://forum.openscad.org/Rounded-Polygon-tp21897p25905.html where I did a
sweep to create a corner and hulled over 8 instances of this corner.
And it wasn't as fast as the full sweep() (30s vs. 5s), but that was (as I
started to remember), because I had used a for-loop. And a for loop always
implies a union.
I just tried a run for which I put each corner as an explicite instance into
the hull body. It looks like the compile time is indeed even faster than a
full sweep (1s only). This seems to shout for a hull_for() operator that
behaves similar like the intersection_for.

Anyway, "fast" is of course always relative, because any further Boolean
operation will take its time with these vertex monsters.

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

Ronaldo wrote > Compute one Bezier corner, lazyUnion() it with its rotation and mirror to > cover all cube vertices roundover and hull() it. As lazyUnion() and hull() > are fast, that may be faster than any other solution. Good point and strategy. That was actually the solution I showed in http://forum.openscad.org/Rounded-Polygon-tp21897p25905.html where I did a sweep to create a corner and hulled over 8 instances of this corner. And it wasn't as fast as the full sweep() (30s vs. 5s), but that was (as I started to remember), because I had used a for-loop. And a for loop always implies a union. I just tried a run for which I put each corner as an explicite instance into the hull body. It looks like the compile time is indeed even faster than a full sweep (1s only). This seems to shout for a hull_for() operator that behaves similar like the intersection_for. Anyway, "fast" is of course always relative, because any further Boolean operation will take its time with these vertex monsters. -- Sent from: http://forum.openscad.org/
A
adrianv
Sat, Mar 23, 2019 11:00 PM

Parkinbot wrote

I just tried a run for which I put each corner as an explicite instance
into
the hull body. It looks like the compile time is indeed even faster than a
full sweep (1s only). This seems to shout for a hull_for() operator that
behaves similar like the intersection_for.

I have not yet had the time to go over what you guys have done, but I will
get to it in a few days.

What would hull_for() do?  And is the real answer not another special
command but rather a way of passing the output of a for command as a set of
children to a calling module?  Because it seems like there are multiple
occasions where you'd like to be able to generate a set of objects with
for() and then pass them to another module that operates on them
individually.  Iff a non-unioning for() command existed then it could
replace intersection_for and would have applications in a variety of places,
I think.  Is this a simpler concept than the idea of generically being able
to return multiple children from a module?

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

Parkinbot wrote > I just tried a run for which I put each corner as an explicite instance > into > the hull body. It looks like the compile time is indeed even faster than a > full sweep (1s only). This seems to shout for a hull_for() operator that > behaves similar like the intersection_for. I have not yet had the time to go over what you guys have done, but I will get to it in a few days. What would hull_for() do? And is the real answer not another special command but rather a way of passing the output of a for command as a set of children to a calling module? Because it seems like there are multiple occasions where you'd like to be able to generate a set of objects with for() and then pass them to another module that operates on them individually. Iff a non-unioning for() command existed then it could replace intersection_for and would have applications in a variety of places, I think. Is this a simpler concept than the idea of generically being able to return multiple children from a module? -- Sent from: http://forum.openscad.org/
NH
nop head
Sun, Mar 24, 2019 12:01 AM

There is already a PR for a non-union option for for() as part of a built
in sweep recently. It would make intersection_for() redundant as well I
think.

On Sat, 23 Mar 2019 at 23:01, adrianv avm4@cornell.edu wrote:

Parkinbot wrote

I just tried a run for which I put each corner as an explicite instance
into
the hull body. It looks like the compile time is indeed even faster than

a

full sweep (1s only). This seems to shout for a hull_for() operator that
behaves similar like the intersection_for.

I have not yet had the time to go over what you guys have done, but I will
get to it in a few days.

What would hull_for() do?  And is the real answer not another special
command but rather a way of passing the output of a for command as a set of
children to a calling module?  Because it seems like there are multiple
occasions where you'd like to be able to generate a set of objects with
for() and then pass them to another module that operates on them
individually.  Iff a non-unioning for() command existed then it could
replace intersection_for and would have applications in a variety of
places,
I think.  Is this a simpler concept than the idea of generically being able
to return multiple children from a module?

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


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

There is already a PR for a non-union option for for() as part of a built in sweep recently. It would make intersection_for() redundant as well I think. On Sat, 23 Mar 2019 at 23:01, adrianv <avm4@cornell.edu> wrote: > Parkinbot wrote > > I just tried a run for which I put each corner as an explicite instance > > into > > the hull body. It looks like the compile time is indeed even faster than > a > > full sweep (1s only). This seems to shout for a hull_for() operator that > > behaves similar like the intersection_for. > > I have not yet had the time to go over what you guys have done, but I will > get to it in a few days. > > What would hull_for() do? And is the real answer not another special > command but rather a way of passing the output of a for command as a set of > children to a calling module? Because it seems like there are multiple > occasions where you'd like to be able to generate a set of objects with > for() and then pass them to another module that operates on them > individually. Iff a non-unioning for() command existed then it could > replace intersection_for and would have applications in a variety of > places, > I think. Is this a simpler concept than the idea of generically being able > to return multiple children from a module? > > > > > > -- > Sent from: http://forum.openscad.org/ > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >
P
Parkinbot
Sun, Mar 24, 2019 12:30 AM

adrianv wrote

Iff a non-unioning for() command existed then it could
replace intersection_for and would have applications in a variety of
places,
I think.

This is correct. And it has been discussed several times before. I think a
practical solution would be to introduce an ungroup() operator that cancels
out a following group(){} clause in the csg file, which implicitly forces a
union.

hull() for(i=[10,20]) cube(i);

translates into the CSG tree:

hull() {
group() {
cube(size = [10, 10, 10], center = false);
cube(size = [20, 20, 20], center = false);
}
}

If you edit the CSG file to

hull() {
cube(size = [10, 10, 10], center = false);
cube(size = [20, 20, 20], center = false);
}

you obviously get the desired result. Therefore

hull() ungroup() for(i=[10,20]) cube(i);

would translate into

hull() {
ungroup{
group() {
cube(size = [10, 10, 10], center = false);
cube(size = [20, 20, 20], center = false);
}
}
}

and ungroup() would inhibit the immediately following group() clause. If no
immediate group() follows, ungroup() will be ignored or cancelled out. But,
I guess there might be also semantical implications.

@thehans, what do you think?

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

adrianv wrote > Iff a non-unioning for() command existed then it could > replace intersection_for and would have applications in a variety of > places, > I think. This is correct. And it has been discussed several times before. I think a practical solution would be to introduce an ungroup() operator that cancels out a following group(){} clause in the csg file, which implicitly forces a union. hull() for(i=[10,20]) cube(i); translates into the CSG tree: hull() { group() { cube(size = [10, 10, 10], center = false); cube(size = [20, 20, 20], center = false); } } If you edit the CSG file to hull() { cube(size = [10, 10, 10], center = false); cube(size = [20, 20, 20], center = false); } you obviously get the desired result. Therefore hull() ungroup() for(i=[10,20]) cube(i); would translate into hull() { ungroup{ group() { cube(size = [10, 10, 10], center = false); cube(size = [20, 20, 20], center = false); } } } and ungroup() would inhibit the immediately following group() clause. If no immediate group() follows, ungroup() will be ignored or cancelled out. But, I guess there might be also semantical implications. @thehans, what do you think? -- Sent from: http://forum.openscad.org/
TP
Torsten Paul
Sun, Mar 24, 2019 12:49 AM

It's not a problem of the language description, it's the internal
processing logic that currently forces each node to return a single
geometry object.
Changing that should open up further options. So basically right
now, every node has to do the implicit union regardless of the
actual need for that. Pushing the responsibility of the to the
level above should help improving a couple of cases, like hull()
with children generated with for(), translate() just translating
the list of children separately or doing an intersection() on
multiple volumes imported from a single 3MF file.

ciao,
Torsten.

It's not a problem of the language description, it's the internal processing logic that currently forces each node to return a single geometry object. Changing that should open up further options. So basically right now, every node has to do the implicit union regardless of the actual need for that. Pushing the responsibility of the to the level above should help improving a couple of cases, like hull() with children generated with for(), translate() just translating the list of children separately or doing an intersection() on multiple volumes imported from a single 3MF file. ciao, Torsten.
NH
nop head
Sun, Mar 24, 2019 12:58 AM

Somehow this PR gets around the problem with hull() for( ..., union=false).
See https://github.com/openscad/openscad/pull/2796#issuecomment-466836941

On Sun, 24 Mar 2019 at 00:50, Torsten Paul Torsten.Paul@gmx.de wrote:

It's not a problem of the language description, it's the internal
processing logic that currently forces each node to return a single
geometry object.
Changing that should open up further options. So basically right
now, every node has to do the implicit union regardless of the
actual need for that. Pushing the responsibility of the to the
level above should help improving a couple of cases, like hull()
with children generated with for(), translate() just translating
the list of children separately or doing an intersection() on
multiple volumes imported from a single 3MF file.

ciao,
Torsten.


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

Somehow this PR gets around the problem with hull() for( ..., union=false). See https://github.com/openscad/openscad/pull/2796#issuecomment-466836941 On Sun, 24 Mar 2019 at 00:50, Torsten Paul <Torsten.Paul@gmx.de> wrote: > It's not a problem of the language description, it's the internal > processing logic that currently forces each node to return a single > geometry object. > Changing that should open up further options. So basically right > now, every node has to do the implicit union regardless of the > actual need for that. Pushing the responsibility of the to the > level above should help improving a couple of cases, like hull() > with children generated with for(), translate() just translating > the list of children separately or doing an intersection() on > multiple volumes imported from a single 3MF file. > > ciao, > Torsten. > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >
A
adrianv
Sun, Mar 24, 2019 1:10 AM

Parkinbot wrote

adrianv wrote

hull() for(i=[10,20]) cube(i);

translates into the CSG tree:

hull() {
group() {
cube(size = [10, 10, 10], center = false);
cube(size = [20, 20, 20], center = false);
}
}

If you edit the CSG file to

hull() {
cube(size = [10, 10, 10], center = false);
cube(size = [20, 20, 20], center = false);
}

you obviously get the desired result. Therefore

What is the difference between these two things?  Taking the hull() of an
individual cube won't do anything.

I thought the interesting case was wanting to do sequential hulls, like the
hull of every adjacent pair of objects in a list, where the list was
produced by for().

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

Parkinbot wrote > adrianv wrote > > hull() for(i=[10,20]) cube(i); > > translates into the CSG tree: > > hull() { > group() { > cube(size = [10, 10, 10], center = false); > cube(size = [20, 20, 20], center = false); > } > } > > If you edit the CSG file to > > hull() { > cube(size = [10, 10, 10], center = false); > cube(size = [20, 20, 20], center = false); > } > > you obviously get the desired result. Therefore What is the difference between these two things? Taking the hull() of an individual cube won't do anything. I thought the interesting case was wanting to do sequential hulls, like the hull of every adjacent pair of objects in a list, where the list was produced by for(). -- Sent from: http://forum.openscad.org/
P
Parkinbot
Sun, Mar 24, 2019 1:37 AM

adrianv wrote

What is the difference between these two things?  Taking the hull() of an
individual cube won't do anything.

The code hulls two cubes. They could be translated to create something
meaningful, but this doesn't matter for the argument. The cubes will get
unioned in the first case and then hulled, and in the second case they
only get hulled. (Better think of 8 (translated) corners to be hulled to
gain a BezierCube).
While the result is the same, it is a significant runtime difference,
whether hull() will operate over a set of objects or a unioned object.
hull() is much faster then union().

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

adrianv wrote > What is the difference between these two things? Taking the hull() of an > individual cube won't do anything. The code hulls *two* cubes. They could be translated to create something meaningful, but this doesn't matter for the argument. The cubes will get unioned in the first case and then hulled, and in the second case they *only* get hulled. (Better think of 8 (translated) corners to be hulled to gain a BezierCube). While the result is the same, it is a significant runtime difference, whether hull() will operate over a set of objects or a unioned object. hull() is much faster then union(). -- Sent from: http://forum.openscad.org/
RP
Ronaldo Persiano
Sun, Mar 24, 2019 2:03 AM

Parkinbot rudolf@digitaldocument.de wrote:

While the result is the same, it is a significant runtime difference,
whether hull() will operate over a set of objects or a unioned object.
hull() is much faster then union().

Hum... There is something strange here. The following code generates a
regular cube even with F6:

hull()
for(i=[0,1]){
polyhedron([[0,0,i],[1,0,i],[1,1,i],[0,1,i]],[[0,1,2,3,4]]);
cube(0.5);
}

although the two polyhedron are defective (non-manifold). If we drop the
hull() we get a non-manifold warning with F6. So, I don't think the hull()
for(){  } construct really does any union before the hull().

Parkinbot <rudolf@digitaldocument.de> wrote: > While the result is the same, it is a significant runtime difference, > whether hull() will operate over a set of objects or a unioned object. > hull() is much faster then union(). Hum... There is something strange here. The following code generates a regular cube even with F6: hull() for(i=[0,1]){ polyhedron([[0,0,i],[1,0,i],[1,1,i],[0,1,i]],[[0,1,2,3,4]]); cube(0.5); } although the two polyhedron are defective (non-manifold). If we drop the hull() we get a non-manifold warning with F6. So, I don't think the hull() for(){ } construct really does any union before the hull().
RP
Ronaldo Persiano
Sun, Mar 24, 2019 3:56 AM

Parkinbot rudolf@digitaldocument.de wrote:

I just tried a run for which I put each corner as an explicite instance
into
the hull body. It looks like the compile time is indeed even faster than a
full sweep (1s only). This seems to shout for a hull_for() operator that
behaves similar like the intersection_for.

We don't need a hull_for() to have a faster run. hull() disregards any edge
or facets of the objects we collect for it. It operates just on the
vertices. As we don't have a primitive point, we need to resort to
polyhedron to hull() a list of points like I do here:

$fn= 10;          // number of points in all roundover
r0 = 0.15;        // shape parameter
r  = 2;            // rounding "radius"
s  = [10,15,20];  // cube edge length

roundedCube(s,r,r0);

module roundedCube(s=10, r=1, r0=0.073) {
n=$fn?$fn:360/$fa;      // resolution
s=s[0]==undef?[s,s,s]:s; // allow for vector and number
r = abs(r);
if(r==0)
cube(s, center=true);
else {
cp  = cornerPatchCP(-s/2,r,r0);
cp0 = PatchSample(cp,n);            // corner at -s/2
Mx  =[[-1,0,0],[0, 1,0],[0,0, 1]];
My  =[[ 1,0,0],[0,-1,0],[0,0, 1]];
Mz  =[[ 1,0,0],[0, 1,0],[0,0,-1]];
cp2 = concat( cp0, [for(pi=cp0) Mxpi] );
cp4 = concat( cp2, [for(pi=cp2) My
pi] );
cp8 = concat( cp4, [for(pi=cp4) Mz*pi] );
hull() polyhedron(cp8, [[for(i=[0:len(cp8)-1]) i]]);
}
}

function BezierPoint(p, u) =
(len(p) == 2)?
u*p[1] + (1-u)p[0] :
u
BezierPoint([for(i=[1:len(p)-1]) p[i] ], u)
+ (1-u)*BezierPoint([for(i=[0:len(p)-2]) p[i] ], u);

function BPatchPoint(p,u,v) =
BezierPoint(BezierPoint(p, u), v);

function PatchSample(cp,n) =
[for(i=[0:n-1], j=[0:i])
BPatchPoint(cp,i/(n-1),i==0? 0 : j/i) ];

function cornerPatchCP(P0,d,r0=0.5) =
let( dx = d*[1,0,0],
dy = d*[0,1,0],
dz = d*[0,0,1] )
[ [for(j=[0:4]) P0+dx+dy],
cCP([P0+dx+(1-r0)dy, P0+(dx+dy)(1-r0), P0+dx*(1-r0)+dy],r0),
cCP([P0+dx, P0, P0+dy], r0),
cCP([P0+dx+(1-r0)*dz, P0+(1-r0)*dz, P0+dy+(1-r0)*dz],r0),
cCP([P0+dx+dz, P0+dz, P0+dy+dz],r0) ];

function cCP(p,r0=0.5) =
[ p[0],
p[0]+r0*(p[1]-p[0]),
p[1],
p[2]+r0*(p[1]-p[2]),
p[2] ];

This is the fastest strategy I can imagine. The points sampled from the
corner patches are collected in a simple list which will be the vertices of
the fake polyhedron to be hulled. That fake polyhedron has just one face
collecting all the vertex indices. This polyhedron is defective and it is
not a manifold at all but that polyhedron is not really built, just hulled.

The second aspect of the code is that it samples the corner patch in an non
uniform distribution in the parameter space. The sample rate is poor near
the collapsed row of the rectangular patch and increases linearly up to the
opposed patch edge. As the patch is really triangular, the sampling is
geometrically more uniform.

[image: cornerSampling.PNG]

I haven't tried your code yet (although I have borrowed some lines of code
from it :) ) but I believe this last code is faster. It renders the cube in
1s with $fn=50 and in 12s with $fn=100.

Anyway, "fast" is of course always relative, because any further Boolean

operation will take its time with these vertex monsters.

It is not a monster. The number of vertices of the rounded cube is about
the same of one sphere with the same $fn. So, I would not expect anything
worst than the boolean operation with a sphere. In fact, it required just
9s to difference a cylinder crossing a rounded edge with $fn=32.

Parkinbot <rudolf@digitaldocument.de> wrote: > I just tried a run for which I put each corner as an explicite instance > into > the hull body. It looks like the compile time is indeed even faster than a > full sweep (1s only). This seems to shout for a hull_for() operator that > behaves similar like the intersection_for. > We don't need a hull_for() to have a faster run. hull() disregards any edge or facets of the objects we collect for it. It operates just on the vertices. As we don't have a primitive point, we need to resort to polyhedron to hull() a list of points like I do here: $fn= 10; // number of points in all roundover r0 = 0.15; // shape parameter r = 2; // rounding "radius" s = [10,15,20]; // cube edge length roundedCube(s,r,r0); module roundedCube(s=10, r=1, r0=0.073) { n=$fn?$fn:360/$fa; // resolution s=s[0]==undef?[s,s,s]:s; // allow for vector and number r = abs(r); if(r==0) cube(s, center=true); else { cp = cornerPatchCP(-s/2,r,r0); cp0 = PatchSample(cp,n); // corner at -s/2 Mx =[[-1,0,0],[0, 1,0],[0,0, 1]]; My =[[ 1,0,0],[0,-1,0],[0,0, 1]]; Mz =[[ 1,0,0],[0, 1,0],[0,0,-1]]; cp2 = concat( cp0, [for(pi=cp0) Mx*pi] ); cp4 = concat( cp2, [for(pi=cp2) My*pi] ); cp8 = concat( cp4, [for(pi=cp4) Mz*pi] ); hull() polyhedron(cp8, [[for(i=[0:len(cp8)-1]) i]]); } } function BezierPoint(p, u) = (len(p) == 2)? u*p[1] + (1-u)*p[0] : u*BezierPoint([for(i=[1:len(p)-1]) p[i] ], u) + (1-u)*BezierPoint([for(i=[0:len(p)-2]) p[i] ], u); function BPatchPoint(p,u,v) = BezierPoint(BezierPoint(p, u), v); function PatchSample(cp,n) = [for(i=[0:n-1], j=[0:i]) BPatchPoint(cp,i/(n-1),i==0? 0 : j/i) ]; function cornerPatchCP(P0,d,r0=0.5) = let( dx = d*[1,0,0], dy = d*[0,1,0], dz = d*[0,0,1] ) [ [for(j=[0:4]) P0+dx+dy], cCP([P0+dx+(1-r0)*dy, P0+(dx+dy)*(1-r0), P0+dx*(1-r0)+dy],r0), cCP([P0+dx, P0, P0+dy], r0), cCP([P0+dx+(1-r0)*dz, P0+(1-r0)*dz, P0+dy+(1-r0)*dz],r0), cCP([P0+dx+dz, P0+dz, P0+dy+dz],r0) ]; function cCP(p,r0=0.5) = [ p[0], p[0]+r0*(p[1]-p[0]), p[1], p[2]+r0*(p[1]-p[2]), p[2] ]; This is the fastest strategy I can imagine. The points sampled from the corner patches are collected in a simple list which will be the vertices of the fake polyhedron to be hulled. That fake polyhedron has just one face collecting all the vertex indices. This polyhedron is defective and it is not a manifold at all but that polyhedron is not really built, just hulled. The second aspect of the code is that it samples the corner patch in an non uniform distribution in the parameter space. The sample rate is poor near the collapsed row of the rectangular patch and increases linearly up to the opposed patch edge. As the patch is really triangular, the sampling is geometrically more uniform. [image: cornerSampling.PNG] I haven't tried your code yet (although I have borrowed some lines of code from it :) ) but I believe this last code is faster. It renders the cube in 1s with $fn=50 and in 12s with $fn=100. Anyway, "fast" is of course always relative, because any further Boolean > operation will take its time with these vertex monsters. > It is not a monster. The number of vertices of the rounded cube is about the same of one sphere with the same $fn. So, I would not expect anything worst than the boolean operation with a sphere. In fact, it required just 9s to difference a cylinder crossing a rounded edge with $fn=32.
P
Parkinbot
Sun, Mar 24, 2019 10:51 AM

Ronaldo wrote

although the two polyhedron are defective (non-manifold). If we drop the
hull() we get a non-manifold warning with F6. So, I don't think the hull()
for(){  } construct really does any union before the hull().

I think warnings are only tested and emitted on the final object.

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

Ronaldo wrote > although the two polyhedron are defective (non-manifold). If we drop the > hull() we get a non-manifold warning with F6. So, I don't think the hull() > for(){ } construct really does any union before the hull(). I think warnings are only tested and emitted on the final object. -- Sent from: http://forum.openscad.org/
P
Parkinbot
Sun, Mar 24, 2019 11:20 AM

Ronaldo wrote

We don't need a hull_for() to have a faster run. hull() disregards any
edge
or facets of the objects we collect for it. It operates just on the
vertices. As we don't have a primitive point, we need to resort to
polyhedron to hull() a list of points like I do here:

If you create a convex body it is indeed avoidable - even I would say, it is
a work-around if you have to recur to a lazy-union to avoid the "for union
problem".

The following code creates a random convex body and looks a bit dirty. I am
somehow very reluctant to build a serious library module on this technique:

points = [for(i=[0:30]) rands(-10, 10, 3)];
faces =  [[for(i=[0:len(points)-1]) i]];
hull() polyhedron(points, faces);  // tricky convex body

However, there are also non-convex shapes. For them you need to do a proper
sweep, so this strategy is quite limited. In general I prefer to create such
a patch in a way so that it can also be swept.

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

Ronaldo wrote > We don't need a hull_for() to have a faster run. hull() disregards any > edge > or facets of the objects we collect for it. It operates just on the > vertices. As we don't have a primitive point, we need to resort to > polyhedron to hull() a list of points like I do here: If you create a convex body it is indeed avoidable - even I would say, it is a work-around if you have to recur to a lazy-union to avoid the "for union problem". The following code creates a random convex body and looks a bit dirty. I am somehow very reluctant to build a serious library module on this technique: points = [for(i=[0:30]) rands(-10, 10, 3)]; faces = [[for(i=[0:len(points)-1]) i]]; hull() polyhedron(points, faces); // tricky convex body However, there are also non-convex shapes. For them you need to do a proper sweep, so this strategy is quite limited. In general I prefer to create such a patch in a way so that it can also be swept. -- Sent from: http://forum.openscad.org/
A
adrianv
Sun, Mar 24, 2019 11:43 AM

Wouldn't Oskar Linde's hull() function solve this problem?  I don't know its
runtime performance, but it takes a point list and computes faces of the
convex hull without the uncomfortable scheme of creating a bogus polyhedron.

https://github.com/openscad/scad-utils/blob/master/hull.scad

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

Wouldn't Oskar Linde's hull() function solve this problem? I don't know its runtime performance, but it takes a point list and computes faces of the convex hull without the uncomfortable scheme of creating a bogus polyhedron. https://github.com/openscad/scad-utils/blob/master/hull.scad -- Sent from: http://forum.openscad.org/
P
Parkinbot
Sun, Mar 24, 2019 12:53 PM

adrianv wrote

Wouldn't Oskar Linde's hull() function solve this problem?

It wouldn't solve the problem, because in general we have the case in which
a for-loop will create objects (even fancy polyhedra are objects) that get
hulled, and Oskar Linde's hull() function depends like a lazy union on a
point representation, which OpenSCAD is successfully hiding from user space.

But for fun, I did a quick runtime test and compared Oskar Linde's hull()
function with the fancy hull()polyhedron() approach. It turned out that
Oskar's function is indeed pretty much faster, when it comes to a higher
number of points. Good to know!

points = [for(i=[0:3000]) rands(-10, 10, 3)];

// polyhedron (points, hull(points));  // Oskar's approach: 6s

faces =  [[for(i=[0:len(points)-1]) i]];
hull() polyhedron(points, faces);  // tricky convex body 74s:

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

adrianv wrote > Wouldn't Oskar Linde's hull() function solve this problem? It wouldn't solve the problem, because in general we have the case in which a for-loop will create objects (even fancy polyhedra are objects) that get hulled, and Oskar Linde's hull() function depends like a lazy union on a point representation, which OpenSCAD is successfully hiding from user space. But for fun, I did a quick runtime test and compared Oskar Linde's hull() function with the fancy hull()polyhedron() approach. It turned out that Oskar's function is indeed pretty much faster, when it comes to a higher number of points. Good to know! points = [for(i=[0:3000]) rands(-10, 10, 3)]; // polyhedron (points, hull(points)); // Oskar's approach: 6s faces = [[for(i=[0:len(points)-1]) i]]; hull() polyhedron(points, faces); // tricky convex body 74s: -- Sent from: http://forum.openscad.org/
RP
Ronaldo Persiano
Sun, Mar 24, 2019 2:00 PM

I have never tried Oskar Linde's hull(). I will give it a go.

However, the bogus polyhedron technique seems to be faster and simpler. For
the advocates of more orthodox solutions, it is possible to apply hull to a
set of spherical regular polyhedron built by lazyUnion() the 8 corner
patches glued together. As hull() will consider just the vertices and
disregard the edges and faces, that seems to be a waste of running time and
coding effort.

I have not looked at the sweep technique in detail yet. My concern would
certainly be on the curvature continuity.

It is a great news (and surprise) that Oskar Linde's hull is so fast. I
will study it.

A domingo, 24/03/2019, 11:44, adrianv avm4@cornell.edu escreveu:

Wouldn't Oskar Linde's hull() function solve this problem?  I don't know
its
runtime performance, but it takes a point list and computes faces of the
convex hull without the uncomfortable scheme of creating a bogus
polyhedron.

https://github.com/openscad/scad-utils/blob/master/hull.scad

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


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

I have never tried Oskar Linde's hull(). I will give it a go. However, the bogus polyhedron technique seems to be faster and simpler. For the advocates of more orthodox solutions, it is possible to apply hull to a set of spherical regular polyhedron built by lazyUnion() the 8 corner patches glued together. As hull() will consider just the vertices and disregard the edges and faces, that seems to be a waste of running time and coding effort. I have not looked at the sweep technique in detail yet. My concern would certainly be on the curvature continuity. It is a great news (and surprise) that Oskar Linde's hull is so fast. I will study it. A domingo, 24/03/2019, 11:44, adrianv <avm4@cornell.edu> escreveu: > Wouldn't Oskar Linde's hull() function solve this problem? I don't know > its > runtime performance, but it takes a point list and computes faces of the > convex hull without the uncomfortable scheme of creating a bogus > polyhedron. > > https://github.com/openscad/scad-utils/blob/master/hull.scad > > > > -- > Sent from: http://forum.openscad.org/ > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >
RP
Ronaldo Persiano
Tue, Mar 26, 2019 12:46 AM

Parkinbot rudolf@digitaldocument.de wrote:

adrianv wrote

Wouldn't Oskar Linde's hull() function solve this problem?

(...)
But for fun, I did a quick runtime test and compared Oskar Linde's hull()
function with the fancy hull()polyhedron() approach. It turned out that
Oskar's function is indeed pretty much faster, when it comes to a higher
number of points. Good to know!

points = [for(i=[0:3000]) rands(-10, 10, 3)];

// polyhedron (points, hull(points));  // Oskar's approach: 6s

faces =  [[for(i=[0:len(points)-1]) i]];
hull() polyhedron(points, faces);  // tricky convex body 74s:

I have checked this comparison and concluded that the delay of the second
alternative is due to the big face in the polyhedron call. I guess that the
system does a triangulation of that bogus face. Instead of one big face I
have defined a big list of triangular faces covering all vertices and the
results were very different:

points = [for(i=[0:120000-1]) rands(-10, 10, 3)];
faces =  [for(i=[0:3:len(points)-1]) [i,i+1,i+2]];
hull() // hull() spent 0s
polyhedron(points, faces);  // tricky polyhedron spent 3s

On the other hand, Oskar Linde's hull() crashed with 6000 or more points.
If that function were used in a roundedCube code, it would crash with
$fn>=38.

Parkinbot <rudolf@digitaldocument.de> wrote: > adrianv wrote > > Wouldn't Oskar Linde's hull() function solve this problem? > (...) > But for fun, I did a quick runtime test and compared Oskar Linde's hull() > function with the fancy hull()polyhedron() approach. It turned out that > Oskar's function is indeed pretty much faster, when it comes to a higher > number of points. Good to know! > > points = [for(i=[0:3000]) rands(-10, 10, 3)]; > > // polyhedron (points, hull(points)); // Oskar's approach: 6s > > faces = [[for(i=[0:len(points)-1]) i]]; > hull() polyhedron(points, faces); // tricky convex body 74s: > I have checked this comparison and concluded that the delay of the second alternative is due to the big face in the polyhedron call. I guess that the system does a triangulation of that bogus face. Instead of one big face I have defined a big list of triangular faces covering all vertices and the results were very different: points = [for(i=[0:120000-1]) rands(-10, 10, 3)]; faces = [for(i=[0:3:len(points)-1]) [i,i+1,i+2]]; hull() // hull() spent 0s polyhedron(points, faces); // tricky polyhedron spent 3s On the other hand, Oskar Linde's hull() crashed with 6000 or more points. If that function were used in a roundedCube code, it would crash with $fn>=38.
P
Parkinbot
Tue, Mar 26, 2019 5:47 PM

Good solution. Your code took 16s on my machine.

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

Good solution. Your code took 16s on my machine. -- Sent from: http://forum.openscad.org/
RP
Ronaldo Persiano
Tue, Mar 26, 2019 8:10 PM

Ronaldo Persiano rcmpersiano@gmail.com wrote:

This is the fastest strategy I can imagine. The points sampled from the
corner patches are collected in a simple list which will be the vertices of
the fake polyhedron to be hulled. That fake polyhedron has just one face
collecting all the vertex indices. This polyhedron is defective and it is
not a manifold at all but that polyhedron is not really built, just hulled.

There is no need to resort to bogus polyhedra to follow the strategy based
on hull(). Instead, we just build a valid polyhedron for each corner and
hull() them all. Surprisingly, the preview and render times are nearly the
same as the bogus polyhedron previous code although the code is a bit more
complex.

$fn = 40;          // number of points in all roundover
// 6560 vertices for $fn = 40
r0  = 0.073;        // shape parameter (this value approximates a circular
arc)
r  = 1.5;          // rounding "radius"
s  = [15,15,20];  // cube edge length

difference(){
roundedCube(s,r,r0);
rotate(90,[1,1,0])cylinder(r=2,h=40); // to check F6 validity
}

// round the edges and vertices of a block with dimensions s centered at
the origin
//  s  - block dimensions; may be a number or a 3d vector
//  r  - the extension of the edge ends that are rounded;
//      equivalent to the radius of a circular rouding
//  r0 - rounding shape parameter ( 0<=r0<1 )
module roundedCube(s=10, r=1, r0=0.073) {
n = $fn ? $fn: 360/$fa;      // resolution
assert(0s==0 || 0s==[0,0,0], "improper size value s");
s = s[0]==undef ? [s,s,s]: s; // allow for vector and number
assert(s[0]>0 && s[1]>0 && s[2]>0, "improper cube dimensions s");
r = abs(r);
if(r==0)
cube(s, center=true);
else {
assert(2*r<=min(s), "radius r too large for the cube dimensions");
assert(r0>=0 && r0<1, "shape parameter r0 must satisfy 0<=ro<1" );
cp  =  cubeCornerPatchCP(-s/2,r,r0); // corner at -s/2
cp0 = PatchSample(cp,n);
pd0 = cornerPoly(cp0);              // base corner patch pdat
Mx  = [[-1,0,0],[0, 1,0],[0,0, 1]]; // mirror matrices
My  = [[ 1,0,0],[0,-1,0],[0,0, 1]];
Mz  = [[ 1,0,0],[0, 1,0],[0,0,-1]];
pd1 = [pd0];
pd2 = concat(pd1, transfPdata(Mx,pd1)); // patch mirrorings
pd4 = concat(pd2, transfPdata(My,pd2));
pd8 = concat(pd4, transfPdata(Mz,pd4));
hull()
lazyUnion(pd8);                      // union of the 8 corners
}
}

// unify the polyhedron data in list mPoly and call polyhedron
// assume the final polyhedron has no self-intersections
module lazyUnion(mPoly) {
// acc = accumSum(l) => acc[0]==0, acc[i]==acc[i-1]+l[i-1]
function accSum(l, res=[0]) =
len(res) == len(l) ?
res :
accSum(l, concat(res, [ res[len(res)-1]+l[len(res)-1] ] ));

verts = [for(p=mPoly) each p[0] ];
nvert = [for(p=mPoly) len(p[0]) ];
accv  = accSum(nvert);
faces = [for(i=[0:len(mPoly)-1], fac=mPoly[i][1] )
[for(v=fac) v+accv[i] ] ];
polyhedron(verts, faces);
}

// transform all the vertices of each polyhedron data in list pdat by
matrix M
function transfPdata(M, pdat) = [for(pdi=pdat) [ pdi[0]*M, pdi[1] ] ];

// the polyhedron of a corner in pdat format
function cornerPoly(tpatch) =
let( n = len(tpatch) ) echo(len(tpatch),[for(i=[0:n-1])  (n-1)n/2+i ])
[ [ for(i=[0:n-1], j=[0:i]) tpatch[i][j] ], // corner vertices
// corner faces
[ for(i=[1:n-1], j=[0:i-1]) let( k = i
(i+1)/2 )
each [ [ k+j, k+j-i, k+j+1 ],
if(j<i-1)[ k+j-i, k+j-i+1, k+j+1] ],
// triangular patch back faces
[for(i=[0:n-1])      i*(i+1)/2 ],
[for(i=[n-1:-1:0]) i*(i+1)/2+i ],
[for(i=[0:n-1])    (n-1)*n/2+i ],
[  0, (n-1)*n/2, (n-1)*n/2+n-1 ]
]
];

// a point in a Bezier curve
//  p - patch control points
//  u - parameter value
function BezierPoint(p, u) =
(len(p) == 2)?
u*p[1] + (1-u)p[0] :
u
BezierPoint([for(i=[1:len(p)-1]) p[i] ], u)
+ (1-u)*BezierPoint([for(i=[0:len(p)-2]) p[i] ], u);

// a point in a Bezier surface patch
//  p  - patch control points (matrix)
//  u,v - parameter values
function BPatchPoint(p,u,v) =
BezierPoint(BezierPoint(p, u), v);

// sample a Bezier patch with a triangular distribuition
// cp - control points of the patch
// n  - resolution
// a total of n*(n+1)/2 points are sampled
function PatchSample(cp,n) =
[for(i=[0:n-1])
[for(j=[0:i]) BPatchPoint(cp,i/(n-1),i==0? 0 : j/i) ] ];

// control points of a Bezier patch of a cube corner with curvature
continuity
//  P0 - cube corner vertex
//  r  - the ammount of the 3 edges at the corner to be rounded
//  r0 - shape parameter
function cubeCornerPatchCP(P0,r,r0=0.5) =
[for(p=curveCP([P0+[r,r,0],P0+[r,0,0],P0+[r,0,r]],r0))
curveCP([p, [p[1],p[1],p[2]], [p[1],p[0],p[2]] ], r0) ];

// control points of a degree 4 Bezier curve
// starting and ending with zero curvature
//  p  - corner to be rounded (list of 3 points)
//  r0 - shape parameter
function curveCP(p,r0=0.5) =
[ p[0], p[0]+r0*(p[1]-p[0]), p[1], p[2]+r0*(p[1]-p[2]), p[2] ];

That code is rather fast. It takes 14s to render a rounded block with 6560
vertices.

Parkinbot, wrote:

However, there are also non-convex shapes. For them you need to do a proper
sweep, so this strategy is quite limited. In general I prefer to create
such
a patch in a way so that it can also be swept.

Yes, this technique is valid just for convex bodies. For non-convex
objects, we will have eventually to recode the computation of the patches
and it will be hard to find general solutions for corners with more than 4
incoming edges. On the other hand, I don't see how to manage the rounding
for general cases with sweeps.

Ronaldo Persiano <rcmpersiano@gmail.com> wrote: > This is the fastest strategy I can imagine. The points sampled from the > corner patches are collected in a simple list which will be the vertices of > the fake polyhedron to be hulled. That fake polyhedron has just one face > collecting all the vertex indices. This polyhedron is defective and it is > not a manifold at all but that polyhedron is not really built, just hulled. > There is no need to resort to bogus polyhedra to follow the strategy based on hull(). Instead, we just build a valid polyhedron for each corner and hull() them all. Surprisingly, the preview and render times are nearly the same as the bogus polyhedron previous code although the code is a bit more complex. $fn = 40; // number of points in all roundover // 6560 vertices for $fn = 40 r0 = 0.073; // shape parameter (this value approximates a circular arc) r = 1.5; // rounding "radius" s = [15,15,20]; // cube edge length difference(){ roundedCube(s,r,r0); rotate(90,[1,1,0])cylinder(r=2,h=40); // to check F6 validity } // round the edges and vertices of a block with dimensions s centered at the origin // s - block dimensions; may be a number or a 3d vector // r - the extension of the edge ends that are rounded; // equivalent to the radius of a circular rouding // r0 - rounding shape parameter ( 0<=r0<1 ) module roundedCube(s=10, r=1, r0=0.073) { n = $fn ? $fn: 360/$fa; // resolution assert(0*s==0 || 0*s==[0,0,0], "improper size value s"); s = s[0]==undef ? [s,s,s]: s; // allow for vector and number assert(s[0]>0 && s[1]>0 && s[2]>0, "improper cube dimensions s"); r = abs(r); if(r==0) cube(s, center=true); else { assert(2*r<=min(s), "radius r too large for the cube dimensions"); assert(r0>=0 && r0<1, "shape parameter r0 must satisfy 0<=ro<1" ); cp = cubeCornerPatchCP(-s/2,r,r0); // corner at -s/2 cp0 = PatchSample(cp,n); pd0 = cornerPoly(cp0); // base corner patch pdat Mx = [[-1,0,0],[0, 1,0],[0,0, 1]]; // mirror matrices My = [[ 1,0,0],[0,-1,0],[0,0, 1]]; Mz = [[ 1,0,0],[0, 1,0],[0,0,-1]]; pd1 = [pd0]; pd2 = concat(pd1, transfPdata(Mx,pd1)); // patch mirrorings pd4 = concat(pd2, transfPdata(My,pd2)); pd8 = concat(pd4, transfPdata(Mz,pd4)); hull() lazyUnion(pd8); // union of the 8 corners } } // unify the polyhedron data in list mPoly and call polyhedron // assume the final polyhedron has no self-intersections module lazyUnion(mPoly) { // acc = accumSum(l) => acc[0]==0, acc[i]==acc[i-1]+l[i-1] function accSum(l, res=[0]) = len(res) == len(l) ? res : accSum(l, concat(res, [ res[len(res)-1]+l[len(res)-1] ] )); verts = [for(p=mPoly) each p[0] ]; nvert = [for(p=mPoly) len(p[0]) ]; accv = accSum(nvert); faces = [for(i=[0:len(mPoly)-1], fac=mPoly[i][1] ) [for(v=fac) v+accv[i] ] ]; polyhedron(verts, faces); } // transform all the vertices of each polyhedron data in list pdat by matrix M function transfPdata(M, pdat) = [for(pdi=pdat) [ pdi[0]*M, pdi[1] ] ]; // the polyhedron of a corner in pdat format function cornerPoly(tpatch) = let( n = len(tpatch) ) echo(len(tpatch),[for(i=[0:n-1]) (n-1)*n/2+i ]) [ [ for(i=[0:n-1], j=[0:i]) tpatch[i][j] ], // corner vertices // corner faces [ for(i=[1:n-1], j=[0:i-1]) let( k = i*(i+1)/2 ) each [ [ k+j, k+j-i, k+j+1 ], if(j<i-1)[ k+j-i, k+j-i+1, k+j+1] ], // triangular patch back faces [for(i=[0:n-1]) i*(i+1)/2 ], [for(i=[n-1:-1:0]) i*(i+1)/2+i ], [for(i=[0:n-1]) (n-1)*n/2+i ], [ 0, (n-1)*n/2, (n-1)*n/2+n-1 ] ] ]; // a point in a Bezier curve // p - patch control points // u - parameter value function BezierPoint(p, u) = (len(p) == 2)? u*p[1] + (1-u)*p[0] : u*BezierPoint([for(i=[1:len(p)-1]) p[i] ], u) + (1-u)*BezierPoint([for(i=[0:len(p)-2]) p[i] ], u); // a point in a Bezier surface patch // p - patch control points (matrix) // u,v - parameter values function BPatchPoint(p,u,v) = BezierPoint(BezierPoint(p, u), v); // sample a Bezier patch with a triangular distribuition // cp - control points of the patch // n - resolution // a total of n*(n+1)/2 points are sampled function PatchSample(cp,n) = [for(i=[0:n-1]) [for(j=[0:i]) BPatchPoint(cp,i/(n-1),i==0? 0 : j/i) ] ]; // control points of a Bezier patch of a cube corner with curvature continuity // P0 - cube corner vertex // r - the ammount of the 3 edges at the corner to be rounded // r0 - shape parameter function cubeCornerPatchCP(P0,r,r0=0.5) = [for(p=curveCP([P0+[r,r,0],P0+[r,0,0],P0+[r,0,r]],r0)) curveCP([p, [p[1],p[1],p[2]], [p[1],p[0],p[2]] ], r0) ]; // control points of a degree 4 Bezier curve // starting and ending with zero curvature // p - corner to be rounded (list of 3 points) // r0 - shape parameter function curveCP(p,r0=0.5) = [ p[0], p[0]+r0*(p[1]-p[0]), p[1], p[2]+r0*(p[1]-p[2]), p[2] ]; That code is rather fast. It takes 14s to render a rounded block with 6560 vertices. Parkinbot, wrote: > However, there are also non-convex shapes. For them you need to do a proper > sweep, so this strategy is quite limited. In general I prefer to create > such > a patch in a way so that it can also be swept. Yes, this technique is valid just for convex bodies. For non-convex objects, we will have eventually to recode the computation of the patches and it will be hard to find general solutions for corners with more than 4 incoming edges. On the other hand, I don't see how to manage the rounding for general cases with sweeps.
A
adrianv
Wed, Mar 27, 2019 7:35 PM

I took a look at the code.  Is it the case, Ronaldo, that your method is
creating a true bezier triangle, with the desired 3-axis symmetry?  I read
that the bezier triangular patch can be obtained by sampling a patch in a
triangle or by collapsing two points together, but details were sparse on
what happens to the control points under these transformations.

Is the only difference between the last two versions the method of getting
the hull()?  (Do they produce the same patch?)

And the sweep method Parkinbot posted is my original notion of sweeping the
bezier around the bezier, right?  Do you think the curvature condition will
not hold for this approach?  It seems like you could get into trouble if the
sweeping trajectory doesn't meet some kind of conditions (maybe a maximum
curvature condition?)

It seems hard to imagine generalizing continuous curvature corners beyond
solids created by linear extrusion, and for that case, it seems like the
sweep approach will be easier, no?  I could imagine, instead of making
corners and hulling, making a sweep around an entire shape, though I suppose
it gets to be a lot of vertices.  But this would handle concave corners, I
think?  (Corners that are concave in one direction but convex in the
other.)

With the bezier patch we have 4 edges so we could round over an octahedron,
I suppose, but it not a particularly powerful generalization.

I also noticed a couple things about using bogus faces to polyhedron().
When I use the second method of creating triangles, I somtimes get "PolySet
has degenerate polygons".  What does that mean?  Some triangle is colinear,
or a polygon includes some colinear points?  What does polyhedron do if you
give it a non-coplanar polygon?

When I tried swapping in this method into the bezier code the run time
increased from 2s to 3s for me (with
$fn=100, 40400 points in a corner patch.)  I tried increasing to $fn=200,
and now 160800 points in a corner patch, and then the triangles are much
faster.

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

I took a look at the code. Is it the case, Ronaldo, that your method is creating a true bezier triangle, with the desired 3-axis symmetry? I read that the bezier triangular patch can be obtained by sampling a patch in a triangle or by collapsing two points together, but details were sparse on what happens to the control points under these transformations. Is the only difference between the last two versions the method of getting the hull()? (Do they produce the same patch?) And the sweep method Parkinbot posted is my original notion of sweeping the bezier around the bezier, right? Do you think the curvature condition will not hold for this approach? It seems like you could get into trouble if the sweeping trajectory doesn't meet some kind of conditions (maybe a maximum curvature condition?) It seems hard to imagine generalizing continuous curvature corners beyond solids created by linear extrusion, and for that case, it seems like the sweep approach will be easier, no? I could imagine, instead of making corners and hulling, making a sweep around an entire shape, though I suppose it gets to be a lot of vertices. But this would handle concave corners, I think? (Corners that are concave in one direction but convex in the other.) With the bezier patch we have 4 edges so we could round over an octahedron, I suppose, but it not a particularly powerful generalization. I also noticed a couple things about using bogus faces to polyhedron(). When I use the second method of creating triangles, I somtimes get "PolySet has degenerate polygons". What does that mean? Some triangle is colinear, or a polygon includes some colinear points? What does polyhedron do if you give it a non-coplanar polygon? When I tried swapping in this method into the bezier code the run time increased from 2s to 3s for me (with $fn=100, 40400 points in a corner patch.) I tried increasing to $fn=200, and now 160800 points in a corner patch, and then the triangles are much faster. -- Sent from: http://forum.openscad.org/
RP
Ronaldo Persiano
Wed, Mar 27, 2019 9:35 PM

adrianv avm4@cornell.edu wrote:

I took a look at the code.  Is it the case, Ronaldo, that your method is
creating a true bezier triangle, with the desired 3-axis symmetry?

In that last code, I still use rectangular Bezier patches with a collapsing
row of control points so I would not expect a 3-axis symmetry. The corner
patch is the same it was used in the previous code (I have just simplified
the function that computes the patch CP).

I read that the bezier triangular patch can be obtained by sampling a
patch in a

triangle or by collapsing two points together, but details were sparse on

what happens to the control points under these transformations.

I am afraid that information is not correct.

Is the only difference between the last two versions the method of getting
the hull()?  (Do they produce the same patch?)

Yes, see above.

And the sweep method Parkinbot posted is my original notion of sweeping the
bezier around the bezier, right?  Do you think the curvature condition will
not hold for this approach?  It seems like you could get into trouble if
the
sweeping trajectory doesn't meet some kind of conditions (maybe a maximum
curvature condition?)

Your sweep conception seems to lead to a curvature continuity in the two
axis but I have not analysed it in detail. I can not say that the Parkinbot
sweep code really follows you original conception because I have not
studied his code. Anyway, the results of a sweeping method would be
different in nature from what I have done. I would expect that the planar
face of the rounded block by the sweep method will not be a rectangle (as
in my model) but a rounded rectangle.

It seems hard to imagine generalizing continuous curvature corners beyond
solids created by linear extrusion, and for that case, it seems like the
sweep approach will be easier, no?

I would say that this last code could be easily extended to round any
convex polyhedron where just three edges meet at each vertices (like for
instance a dodecahedron). It is possible to remodel the corner patch in
order to round corners where 4 edges meet but I don't know how extend that
to more general cases where more than 4 edges meet at some corner. I don't
know how to apply the sweep method to round a dodecahedron.

I could imagine, instead of making
corners and hulling, making a sweep around an entire shape, though I
suppose
it gets to be a lot of vertices.  But this would handle concave corners, I
think?  (Corners that are concave in one direction but convex in the
other.)

With the bezier patch we have 4 edges so we could round over an octahedron,
I suppose, but it not a particularly powerful generalization.

Yes, see above.

I also noticed a couple things about using bogus faces to polyhedron().
When I use the second method of creating triangles, I somtimes get "PolySet
has degenerate polygons".  What does that mean?  Some triangle is colinear,
or a polygon includes some colinear points?  What does polyhedron do if you
give it a non-coplanar polygon?

Did you get that warning with my last code? That warning usually means that
there is degenerated faces (colinear points)  or a badly structured face
list or the point list has some point not referenced by any face. If some
face is non-planar, the system triangulate it in some arbitrary way. In my
last code, the corner polyhedron has 3 non-triangulated planar faces.

When I tried swapping in this method into the bezier code the run time
increased from 2s to 3s for me (with
$fn=100, 40400 points in a corner patch.)  I tried increasing to $fn=200,
and now 160800 points in a corner patch, and then the triangles are much
faster.

I haven't understood what you have done here.

adrianv <avm4@cornell.edu> wrote: > I took a look at the code. Is it the case, Ronaldo, that your method is > creating a true bezier triangle, with the desired 3-axis symmetry? In that last code, I still use rectangular Bezier patches with a collapsing row of control points so I would not expect a 3-axis symmetry. The corner patch is the same it was used in the previous code (I have just simplified the function that computes the patch CP). > I read that the bezier triangular patch can be obtained by sampling a > patch in a triangle or by collapsing two points together, but details were sparse on what happens to the control points under these transformations. I am afraid that information is not correct. > Is the only difference between the last two versions the method of getting > the hull()? (Do they produce the same patch?) > Yes, see above. > And the sweep method Parkinbot posted is my original notion of sweeping the > bezier around the bezier, right? Do you think the curvature condition will > not hold for this approach? It seems like you could get into trouble if > the > sweeping trajectory doesn't meet some kind of conditions (maybe a maximum > curvature condition?) > Your sweep conception seems to lead to a curvature continuity in the two axis but I have not analysed it in detail. I can not say that the Parkinbot sweep code really follows you original conception because I have not studied his code. Anyway, the results of a sweeping method would be different in nature from what I have done. I would expect that the planar face of the rounded block by the sweep method will not be a rectangle (as in my model) but a rounded rectangle. > It seems hard to imagine generalizing continuous curvature corners beyond > solids created by linear extrusion, and for that case, it seems like the > sweep approach will be easier, no? I would say that this last code could be easily extended to round any convex polyhedron where just three edges meet at each vertices (like for instance a dodecahedron). It is possible to remodel the corner patch in order to round corners where 4 edges meet but I don't know how extend that to more general cases where more than 4 edges meet at some corner. I don't know how to apply the sweep method to round a dodecahedron. > I could imagine, instead of making > corners and hulling, making a sweep around an entire shape, though I > suppose > it gets to be a lot of vertices. But this would handle concave corners, I > think? (Corners that are concave in one direction but convex in the > other.) > > With the bezier patch we have 4 edges so we could round over an octahedron, > I suppose, but it not a particularly powerful generalization. > Yes, see above. > I also noticed a couple things about using bogus faces to polyhedron(). > When I use the second method of creating triangles, I somtimes get "PolySet > has degenerate polygons". What does that mean? Some triangle is colinear, > or a polygon includes some colinear points? What does polyhedron do if you > give it a non-coplanar polygon? > Did you get that warning with my last code? That warning usually means that there is degenerated faces (colinear points) or a badly structured face list or the point list has some point not referenced by any face. If some face is non-planar, the system triangulate it in some arbitrary way. In my last code, the corner polyhedron has 3 non-triangulated planar faces. > When I tried swapping in this method into the bezier code the run time > increased from 2s to 3s for me (with > $fn=100, 40400 points in a corner patch.) I tried increasing to $fn=200, > and now 160800 points in a corner patch, and then the triangles are much > faster. > I haven't understood what you have done here.
A
adrianv
Wed, Mar 27, 2019 11:08 PM

Ronaldo wrote

adrianv <

avm4@

> wrote:

I took a look at the code.  Is it the case, Ronaldo, that your method is
creating a true bezier triangle, with the desired 3-axis symmetry?

In that last code, I still use rectangular Bezier patches with a
collapsing
row of control points so I would not expect a 3-axis symmetry. The corner
patch is the same it was used in the previous code (I have just simplified
the function that computes the patch CP).

I read that the bezier triangular patch can be obtained by sampling a
patch in a
triangle or by collapsing two points together, but details were sparse
on
what happens to the control points under these transformations.

I am afraid that information is not correct.

Are you sure?  Are bezier patches or curves a different representation of
the degree n (or degree n,m) polynomial, or are there polynomials not
represented by the bezier framework?  It appears just based on counting
parameters that it should be possible to get all polynomials with a bezier
representation, which would mean the claim I quoted above is true...but
perhaps not very interesting without a control point mapping.

And the sweep method Parkinbot posted is my original notion of sweeping
the
bezier around the bezier, right?  Do you think the curvature condition
will
not hold for this approach?  It seems like you could get into trouble if
the
sweeping trajectory doesn't meet some kind of conditions (maybe a maximum
curvature condition?)

Your sweep conception seems to lead to a curvature continuity in the two
axis but I have not analysed it in detail. I can not say that the
Parkinbot
sweep code really follows you original conception because I have not
studied his code. Anyway, the results of a sweeping method would be
different in nature from what I have done. I would expect that the planar
face of the rounded block by the sweep method will not be a rectangle (as
in my model) but a rounded rectangle.

I haven't studied his code yet either.  I have to first understand the sweep
function, so it seemed like a bit more work.  It seems possible that the
result would be different in nature, but I don't agree that the planar face
would be rounded.  Suppose I sweep a square along a line.  The result---a
standard linear extrude---is a cuboid shape with rectangular faces.  If I
sweep a rounded-corner square along a line I will get a cuboid shape with
rounded edges, four rectangular faces, and then two ends whose faces are the
rounded corner square.  If I sweep a rounded corner square along a rounded
corner square then (assuming the roundover doesn't dominate the square), the
square's sides will have flat sections and the sweep will convert these into
rectangular faces.  I think that the resulting shape should actually be
identical to the shape produced from the bezier method except (possibly) at
the corners.

It seems hard to imagine generalizing continuous curvature corners beyond
solids created by linear extrusion, and for that case, it seems like the
sweep approach will be easier, no?

I would say that this last code could be easily extended to round any
convex polyhedron where just three edges meet at each vertices (like for
instance a dodecahedron). It is possible to remodel the corner patch in
order to round corners where 4 edges meet but I don't know how extend that
to more general cases where more than 4 edges meet at some corner. I don't
know how to apply the sweep method to round a dodecahedron.

Yes, definitely it should be straight forward to adapt your approach to a
meeting of 3 edges, and the ordinary square bezier can handle corners where
4 edges meet.  I wonder if the triangular bezier can be generalized to an
n-gon bezier defined somehow on a regular n-gon?

What the sweep approach can (at least in principle) do is apply a roundover
to an (arbitrary?) shape that is generated by linear extrusion.  Basically
instead of doing linear extrusion you sweep along the shape's boundary a
rounded rectangle of the appropriate dimensions to create the desired shape.

I also noticed a couple things about using bogus faces to polyhedron().
When I use the second method of creating triangles, I somtimes get
"PolySet
has degenerate polygons".  What does that mean?  Some triangle is
colinear,
or a polygon includes some colinear points?  What does polyhedron do if
you
give it a non-coplanar polygon?

Did you get that warning with my last code? That warning usually means
that
there is degenerated faces (colinear points)  or a badly structured face
list or the point list has some point not referenced by any face. If some
face is non-planar, the system triangulate it in some arbitrary way. In my
last code, the corner polyhedron has 3 non-triangulated planar faces.

No, not with the latest version of your code.  With tests of the application
of hull() to bogus polyhedra.

When I tried swapping in this method into the bezier code the run time
increased from 2s to 3s for me (with
$fn=100, 40400 points in a corner patch.)  I tried increasing to
$fn=200,
and now 160800 points in a corner patch, and then the triangles are much
faster.

I haven't understood what you have done here.

Your earlier version of the bezier code used the bogus polyhedron method
with one large face.  I substituted small bogus triangles and it got
slightly slower when there were 40000 points in the patch.  But when there
were 160000 bogus triangles were much faster than one huge bogus face.


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

Ronaldo wrote > adrianv &lt; > avm4@ > &gt; wrote: > >> I took a look at the code. Is it the case, Ronaldo, that your method is >> creating a true bezier triangle, with the desired 3-axis symmetry? > > > In that last code, I still use rectangular Bezier patches with a > collapsing > row of control points so I would not expect a 3-axis symmetry. The corner > patch is the same it was used in the previous code (I have just simplified > the function that computes the patch CP). > > >> I read that the bezier triangular patch can be obtained by sampling a >> patch in a >> triangle or by collapsing two points together, but details were sparse >> on >> what happens to the control points under these transformations. > > I am afraid that information is not correct. Are you sure? Are bezier patches or curves a different representation of the degree n (or degree n,m) polynomial, or are there polynomials not represented by the bezier framework? It appears just based on counting parameters that it should be possible to get all polynomials with a bezier representation, which would mean the claim I quoted above is true...but perhaps not very interesting without a control point mapping. >> And the sweep method Parkinbot posted is my original notion of sweeping >> the >> bezier around the bezier, right? Do you think the curvature condition >> will >> not hold for this approach? It seems like you could get into trouble if >> the >> sweeping trajectory doesn't meet some kind of conditions (maybe a maximum >> curvature condition?) >> > > Your sweep conception seems to lead to a curvature continuity in the two > axis but I have not analysed it in detail. I can not say that the > Parkinbot > sweep code really follows you original conception because I have not > studied his code. Anyway, the results of a sweeping method would be > different in nature from what I have done. I would expect that the planar > face of the rounded block by the sweep method will not be a rectangle (as > in my model) but a rounded rectangle. I haven't studied his code yet either. I have to first understand the sweep function, so it seemed like a bit more work. It seems possible that the result would be different in nature, but I don't agree that the planar face would be rounded. Suppose I sweep a square along a line. The result---a standard linear extrude---is a cuboid shape with rectangular faces. If I sweep a rounded-corner square along a line I will get a cuboid shape with rounded edges, four rectangular faces, and then two ends whose faces are the rounded corner square. If I sweep a rounded corner square along a rounded corner square then (assuming the roundover doesn't dominate the square), the square's sides will have flat sections and the sweep will convert these into rectangular faces. I think that the resulting shape should actually be identical to the shape produced from the bezier method except (possibly) at the corners. >> It seems hard to imagine generalizing continuous curvature corners beyond >> solids created by linear extrusion, and for that case, it seems like the >> sweep approach will be easier, no? > > I would say that this last code could be easily extended to round any > convex polyhedron where just three edges meet at each vertices (like for > instance a dodecahedron). It is possible to remodel the corner patch in > order to round corners where 4 edges meet but I don't know how extend that > to more general cases where more than 4 edges meet at some corner. I don't > know how to apply the sweep method to round a dodecahedron. Yes, definitely it should be straight forward to adapt your approach to a meeting of 3 edges, and the ordinary square bezier can handle corners where 4 edges meet. I wonder if the triangular bezier can be generalized to an n-gon bezier defined somehow on a regular n-gon? What the sweep approach can (at least in principle) do is apply a roundover to an (arbitrary?) shape that is generated by linear extrusion. Basically instead of doing linear extrusion you sweep along the shape's boundary a rounded rectangle of the appropriate dimensions to create the desired shape. >> I also noticed a couple things about using bogus faces to polyhedron(). >> When I use the second method of creating triangles, I somtimes get >> "PolySet >> has degenerate polygons". What does that mean? Some triangle is >> colinear, >> or a polygon includes some colinear points? What does polyhedron do if >> you >> give it a non-coplanar polygon? >> > > Did you get that warning with my last code? That warning usually means > that > there is degenerated faces (colinear points) or a badly structured face > list or the point list has some point not referenced by any face. If some > face is non-planar, the system triangulate it in some arbitrary way. In my > last code, the corner polyhedron has 3 non-triangulated planar faces. No, not with the latest version of your code. With tests of the application of hull() to bogus polyhedra. >> When I tried swapping in this method into the bezier code the run time >> increased from 2s to 3s for me (with >> $fn=100, 40400 points in a corner patch.) I tried increasing to >> $fn=200, >> and now 160800 points in a corner patch, and then the triangles are much >> faster. >> > > I haven't understood what you have done here. Your earlier version of the bezier code used the bogus polyhedron method with one large face. I substituted small bogus triangles and it got slightly slower when there were 40000 points in the patch. But when there were 160000 bogus triangles were much faster than one huge bogus face. ___ -- Sent from: http://forum.openscad.org/
RP
Ronaldo Persiano
Thu, Mar 28, 2019 12:52 AM

adrianv avm4@cornell.edu wrote:

I read that the bezier triangular patch can be obtained by sampling a
patch in a
triangle or by collapsing two points together, but details were sparse
on
what happens to the control points under these transformations.

I am afraid that information is not correct.

Are you sure?  Are bezier patches or curves a different representation of
the degree n (or degree n,m) polynomial, or are there polynomials not
represented by the bezier framework?  It appears just based on counting
parameters that it should be possible to get all polynomials with a bezier
representation, which would mean the claim I quoted above is true...but
perhaps not very interesting without a control point mapping.

Yes, I am quite sure. A rectangular Bezier patch with degrees n and m is in
a (large but incomplete) subset of all two variables polynomials of degree
(n+m). A triangular Bezier patch of degree n is really a  two variable
polynomial of degree n and it has (n+1)(n+2)/2 coefficients (CPs). In our
case, degree 4, triangular patches have 15 CPs while a rectangular patch of
degree 4x4 will have 25 CPs. I guess that positioning appropriately those
25 CPs we would get any degree 4 polynomial in two variable. But the
interrelations of those CPs will be something much more complex than you
have referred. At the end, just 15 degree of freedom will remain. There is
no sampling that would exempt the fulfillment of those 10 relations.

Yes, definitely it should be straight forward to adapt your approach to a

meeting of 3 edges, and the ordinary square bezier can handle corners where
4 edges meet.  I wonder if the triangular bezier can be generalized to an
n-gon bezier defined somehow on a regular n-gon?

As far as I know, there is no n-gon Bézier patch for n>4.

Did you get that warning with my last code? That warning usually means

that
there is degenerated faces (colinear points)  or a badly structured face
list or the point list has some point not referenced by any face. If some
face is non-planar, the system triangulate it in some arbitrary way. In

my

last code, the corner polyhedron has 3 non-triangulated planar faces.

No, not with the latest version of your code.  With tests of the
application
of hull() to bogus polyhedra.

The way I have defined that large bogus face, by taking each 3 points in
sequence as vertices of a triangle, some vertices may remain untouched by
any face when the number of vertices is not multiple of 3 and that will
generate a warning like you get.

Your earlier version of the bezier code used the bogus polyhedron method
with one large face.  I substituted small bogus triangles and it got
slightly slower when there were 40000 points in the patch.  But when there
were 160000 bogus triangles were much faster than one huge bogus face.

Were you comparing the running time of the bogus polyhedron process with
the Oskar Linde's hull() of points?

adrianv <avm4@cornell.edu> wrote: > >> I read that the bezier triangular patch can be obtained by sampling a > >> patch in a > >> triangle or by collapsing two points together, but details were sparse > >> on > >> what happens to the control points under these transformations. > > > > I am afraid that information is not correct. > > Are you sure? Are bezier patches or curves a different representation of > the degree n (or degree n,m) polynomial, or are there polynomials not > represented by the bezier framework? It appears just based on counting > parameters that it should be possible to get all polynomials with a bezier > representation, which would mean the claim I quoted above is true...but > perhaps not very interesting without a control point mapping. > Yes, I am quite sure. A rectangular Bezier patch with degrees n and m is in a (large but incomplete) subset of all two variables polynomials of degree (n+m). A triangular Bezier patch of degree n is really a two variable polynomial of degree n and it has (n+1)(n+2)/2 coefficients (CPs). In our case, degree 4, triangular patches have 15 CPs while a rectangular patch of degree 4x4 will have 25 CPs. I guess that positioning appropriately those 25 CPs we would get any degree 4 polynomial in two variable. But the interrelations of those CPs will be something much more complex than you have referred. At the end, just 15 degree of freedom will remain. There is no sampling that would exempt the fulfillment of those 10 relations. Yes, definitely it should be straight forward to adapt your approach to a > meeting of 3 edges, and the ordinary square bezier can handle corners where > 4 edges meet. I wonder if the triangular bezier can be generalized to an > n-gon bezier defined somehow on a regular n-gon? As far as I know, there is no n-gon Bézier patch for n>4. > Did you get that warning with my last code? That warning usually means > > that > > there is degenerated faces (colinear points) or a badly structured face > > list or the point list has some point not referenced by any face. If some > > face is non-planar, the system triangulate it in some arbitrary way. In > my > > last code, the corner polyhedron has 3 non-triangulated planar faces. > > No, not with the latest version of your code. With tests of the > application > of hull() to bogus polyhedra. > The way I have defined that large bogus face, by taking each 3 points in sequence as vertices of a triangle, some vertices may remain untouched by any face when the number of vertices is not multiple of 3 and that will generate a warning like you get. > Your earlier version of the bezier code used the bogus polyhedron method > with one large face. I substituted small bogus triangles and it got > slightly slower when there were 40000 points in the patch. But when there > were 160000 bogus triangles were much faster than one huge bogus face. Were you comparing the running time of the bogus polyhedron process with the Oskar Linde's hull() of points?
A
adrianv
Fri, Mar 29, 2019 4:04 AM

I have made an attempt at the triangular bezier patch.  I do not know if I
have picked parameters that achieve continuous curvature, but the patch is
looking reasonable.  Here is one corner, with control points displayed.
There are 3 control points that appear "free" in some sense---that is, not
falling on the edge with their value already determined to achieve the
continuous curvature edge curve.

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

Here's the code.  It seems like computing the bezier points is kind of slow,
but I don't know if there's a more clever way to do it.

h=0.6;
corner = [0,0,0];
dx = [-1,0,0];
dy = [0,-1,0];
dz = [0,0,-1];
P1 = corner-dx-dy;
P2 = corner-dx-dz;
P3 = corner-dy-dz;
P12 = corner-dx;
P13 = corner-dy;
P23 = corner-dz;
P2face = corner-hdx-hdz;
P1face = corner - hdx-hdy;
P3face = corner-hdy-hdz;

P = [
[P1,              P12+h*(P1-P12), P12,    P12+h*(P2-P12), P2],
[P13 + h*(P1-P13), P1face,        P2face, P23+h*(P2-P23)],
[P13,              P3face,        P23],
[P13 + h*(P3-P13), P23 + h*(P3-P23)],
[P3]
];

sdx=1/16;
pts = ( [for(u=[0:sdx:1])
each [for(v=[0:sdx:1-u]) tribez(P,u,v)]]);
echo(len(pts), "points");

fastpointhull(pts);  //polyhedron(pts, faces=hull(pts));

function tribez(P,u,v) = len(P) == 1 ? P[0][0] :
let(
n = len(P)-1,
Pu = [for(i=[0:n-1]) select(P[i],[1:len(P[i])-1])], //
select(P[i],1,-1)],
Pv = [for(i=[0:n-1]) select(P[i],[0:len(P[i])-2])], //
select(P[i],0,len(P[i])-2)],
Pw = select(P,[1:n])
)
tribez(uPu+vPv+(1-u-v)*Pw,u,v);

%cube(size=[1,1,1]);

module fastpointhull(points){
//points = simplify3d_path(points);  // colinear points are not on the
hull and generate a warning message
extra = len(points)%3;
list = concat(
[[for(i=[0:extra+2])i]],
[for(i=[extra+3:3:len(points)-3])[i,i+1,i+2]]);
hull() polyhedron(points, faces=list);
}

function select(vector,indices) = [ for (index = indices) vector[index] ];

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

I have made an attempt at the triangular bezier patch. I do not know if I have picked parameters that achieve continuous curvature, but the patch is looking reasonable. Here is one corner, with control points displayed. There are 3 control points that appear "free" in some sense---that is, not falling on the edge with their value already determined to achieve the continuous curvature edge curve. <http://forum.openscad.org/file/t2477/tribez2.png> Here's the code. It seems like computing the bezier points is kind of slow, but I don't know if there's a more clever way to do it. h=0.6; corner = [0,0,0]; dx = [-1,0,0]; dy = [0,-1,0]; dz = [0,0,-1]; P1 = corner-dx-dy; P2 = corner-dx-dz; P3 = corner-dy-dz; P12 = corner-dx; P13 = corner-dy; P23 = corner-dz; P2face = corner-h*dx-h*dz; P1face = corner - h*dx-h*dy; P3face = corner-h*dy-h*dz; P = [ [P1, P12+h*(P1-P12), P12, P12+h*(P2-P12), P2], [P13 + h*(P1-P13), P1face, P2face, P23+h*(P2-P23)], [P13, P3face, P23], [P13 + h*(P3-P13), P23 + h*(P3-P23)], [P3] ]; sdx=1/16; pts = ( [for(u=[0:sdx:1]) each [for(v=[0:sdx:1-u]) tribez(P,u,v)]]); echo(len(pts), "points"); fastpointhull(pts); //polyhedron(pts, faces=hull(pts)); function tribez(P,u,v) = len(P) == 1 ? P[0][0] : let( n = len(P)-1, Pu = [for(i=[0:n-1]) select(P[i],[1:len(P[i])-1])], // select(P[i],1,-1)], Pv = [for(i=[0:n-1]) select(P[i],[0:len(P[i])-2])], // select(P[i],0,len(P[i])-2)], Pw = select(P,[1:n]) ) tribez(u*Pu+v*Pv+(1-u-v)*Pw,u,v); %cube(size=[1,1,1]); module fastpointhull(points){ //points = simplify3d_path(points); // colinear points are not on the hull and generate a warning message extra = len(points)%3; list = concat( [[for(i=[0:extra+2])i]], [for(i=[extra+3:3:len(points)-3])[i,i+1,i+2]]); hull() polyhedron(points, faces=list); } function select(vector,indices) = [ for (index = indices) vector[index] ]; -- Sent from: http://forum.openscad.org/
RP
Ronaldo Persiano
Fri, Mar 29, 2019 2:47 PM

adrianv avm4@cornell.edu wrote:

I have made an attempt at the triangular bezier patch.  I do not know if I
have picked parameters that achieve continuous curvature, but the patch is
looking reasonable.  Here is one corner, with control points displayed.
There are 3 control points that appear "free" in some sense---that is, not
falling on the edge with their value already determined to achieve the
continuous curvature edge curve.

Nice work! I was following the same route but with degree 6 triangular
patch which is, I suppose, the minimum degree to have curvature continuity.
But I could not find a good way to compute curvature for triangular patches
to check my models. Anyway, I am afraid that the 3 CPs you consider free to
shape the surface should have precise positions to get curvature
continuity. I have drawn the triangular grid of your CPs and got the
following image with h=0.3.

As the central triangle is not coplanar with any of the corner planes I
think we would not have zero cross border second derivative at the patch
borders. Perhaps we get zero cross border curvature with h=0 but that is
too much restrictive.

My next step will be to compute the cross border curvature to check the
surface models.

adrianv <avm4@cornell.edu> wrote: > I have made an attempt at the triangular bezier patch. I do not know if I > have picked parameters that achieve continuous curvature, but the patch is > looking reasonable. Here is one corner, with control points displayed. > There are 3 control points that appear "free" in some sense---that is, not > falling on the edge with their value already determined to achieve the > continuous curvature edge curve. > Nice work! I was following the same route but with degree 6 triangular patch which is, I suppose, the minimum degree to have curvature continuity. But I could not find a good way to compute curvature for triangular patches to check my models. Anyway, I am afraid that the 3 CPs you consider free to shape the surface should have precise positions to get curvature continuity. I have drawn the triangular grid of your CPs and got the following image with h=0.3. As the central triangle is not coplanar with any of the corner planes I think we would not have zero cross border second derivative at the patch borders. Perhaps we get zero cross border curvature with h=0 but that is too much restrictive. My next step will be to compute the cross border curvature to check the surface models.
P
Parkinbot
Fri, Mar 29, 2019 5:23 PM

Looks like a patch, but it doesn't make a smooth connection on rotation ...

translate([-1, -1])fastpointhull(pts);
rotate([0,0,90])
translate([-1, -1])fastpointhull(pts);

http://forum.openscad.org/file/t887/patch.png

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

Looks like a patch, but it doesn't make a smooth connection on rotation ... translate([-1, -1])fastpointhull(pts); rotate([0,0,90]) translate([-1, -1])fastpointhull(pts); <http://forum.openscad.org/file/t887/patch.png> -- Sent from: http://forum.openscad.org/
A
adrianv
Fri, Mar 29, 2019 5:43 PM

It's not clear to me what the constraints are for controlling the derivative
matching for the triangular patch, but yes, it appears I have with order 4
not even matched the first derivative.

So this raises the questions:  Is the code correct?  Is it possible to match
derivatives as desired (with a patch of sufficient order)?

Should the edges of the patch match the 4th order 1d bezier curve with the
same control points?

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

It's not clear to me what the constraints are for controlling the derivative matching for the triangular patch, but yes, it appears I have with order 4 not even matched the first derivative. So this raises the questions: Is the code correct? Is it possible to match derivatives as desired (with a patch of sufficient order)? Should the edges of the patch match the 4th order 1d bezier curve with the same control points? -- Sent from: http://forum.openscad.org/
RP
Ronaldo Persiano
Fri, Mar 29, 2019 7:30 PM

Em sex, 29 de mar de 2019 às 17:44, adrianv avm4@cornell.edu escreveu:

It's not clear to me what the constraints are for controlling the
derivative
matching for the triangular patch, but yes, it appears I have with order 4
not even matched the first derivative.

The C1 continuity (first derivative) between two adjacent triangular
patches involves the co-planarity of some triangle pairs adjacent to the
common border (see fig. 1). It is in some sense an extension of the
condition that holds for curves. The C2 continuity (second order) requires
the coindicence of some points extending from some triangles in a second
row away from the common border (see fig. 2). The figures were taken from
Farin's paper found at
http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.413.7346&rep=rep1&type=pdf.
Although this is the main reference on the subject, its nomenclature is
hard to follow. I have tried without success, to express by triangular
patches the cylindrical surface of an edge rounded with the degree 4 curve.
That would help me to try meeting the necessary C2 continuity.

So this raises the questions:  Is the code correct?  Is it possible to match

derivatives as desired (with a patch of sufficient order)?

This depends on what you mean by correct. I haven't seen nothing wrong with
your functions.
I still believe we could achieve the necessary C2 conditions with
triangular patches with even degree. If the 4x4 rectangular patch I built
really matches the conditions (and I am still unsure about it), then at
least a degree 8=4+4 triangular patch will do it.

Should the edges of the patch match the 4th order 1d bezier curve with the
same control points?

Yes, possibly with a higher degree representation.

// given p, the Bezier CP of an arc of degree len(p),
// find the control points of the same arc expressed as a curve of degree
len(p)+n

function BzDegreeElevation(p, n) =
n==0 ? p :
let(q = [ p[0],
for(i=[1:len(p)-1], u = i/len(p))
u*p[i-1] + (1-u)*p[i] ,
p[len(p)-1] ] )
BzDegreeElevation  (q, n-1);

Em sex, 29 de mar de 2019 às 17:44, adrianv <avm4@cornell.edu> escreveu: > It's not clear to me what the constraints are for controlling the > derivative > matching for the triangular patch, but yes, it appears I have with order 4 > not even matched the first derivative. > The C1 continuity (first derivative) between two adjacent triangular patches involves the co-planarity of some triangle pairs adjacent to the common border (see fig. 1). It is in some sense an extension of the condition that holds for curves. The C2 continuity (second order) requires the coindicence of some points extending from some triangles in a second row away from the common border (see fig. 2). The figures were taken from Farin's paper found at http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.413.7346&rep=rep1&type=pdf. Although this is the main reference on the subject, its nomenclature is hard to follow. I have tried without success, to express by triangular patches the cylindrical surface of an edge rounded with the degree 4 curve. That would help me to try meeting the necessary C2 continuity. So this raises the questions: Is the code correct? Is it possible to match > derivatives as desired (with a patch of sufficient order)? This depends on what you mean by correct. I haven't seen nothing wrong with your functions. I still believe we could achieve the necessary C2 conditions with triangular patches with even degree. If the 4x4 rectangular patch I built really matches the conditions (and I am still unsure about it), then at least a degree 8=4+4 triangular patch will do it. > Should the edges of the patch match the 4th order 1d bezier curve with the > same control points? > Yes, possibly with a higher degree representation. // given p, the Bezier CP of an arc of degree len(p), // find the control points of the same arc expressed as a curve of degree len(p)+n function BzDegreeElevation(p, n) = n==0 ? p : let(q = [ p[0], for(i=[1:len(p)-1], u = i/len(p)) u*p[i-1] + (1-u)*p[i] , p[len(p)-1] ] ) BzDegreeElevation (q, n-1);
A
adrianv
Fri, Mar 29, 2019 11:55 PM

Ronaldo wrote

Em sex, 29 de mar de 2019 às 17:44, adrianv <

avm4@

> escreveu:

It's not clear to me what the constraints are for controlling the
derivative
matching for the triangular patch, but yes, it appears I have with order
4
not even matched the first derivative.

The C1 continuity (first derivative) between two adjacent triangular
patches involves the co-planarity of some triangle pairs adjacent to the
common border (see fig. 1). It is in some sense an extension of the
condition that holds for curves. The C2 continuity (second order) requires
the coindicence of some points extending from some triangles in a second
row away from the common border (see fig. 2). The figures were taken from
Farin's paper found at
http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.413.7346&rep=rep1&type=pdf.
Although this is the main reference on the subject, its nomenclature is
hard to follow. I have tried without success, to express by triangular
patches the cylindrical surface of an edge rounded with the degree 4
curve.
That would help me to try meeting the necessary C2 continuity.

My patch is failing C1 even though it appears to me that I meet the
coplanarity condition for the triangles adjacent to the edge.  What is
wrong?

I have not been successful thus far at deciphering the C2 condition from the
paper.

I did confirm that my patch edges matches the shape of the 1d curve I
previously produced with the order 4 bezier.

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

Ronaldo wrote > Em sex, 29 de mar de 2019 às 17:44, adrianv &lt; > avm4@ > &gt; escreveu: > >> It's not clear to me what the constraints are for controlling the >> derivative >> matching for the triangular patch, but yes, it appears I have with order >> 4 >> not even matched the first derivative. >> > > The C1 continuity (first derivative) between two adjacent triangular > patches involves the co-planarity of some triangle pairs adjacent to the > common border (see fig. 1). It is in some sense an extension of the > condition that holds for curves. The C2 continuity (second order) requires > the coindicence of some points extending from some triangles in a second > row away from the common border (see fig. 2). The figures were taken from > Farin's paper found at > http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.413.7346&rep=rep1&type=pdf. > Although this is the main reference on the subject, its nomenclature is > hard to follow. I have tried without success, to express by triangular > patches the cylindrical surface of an edge rounded with the degree 4 > curve. > That would help me to try meeting the necessary C2 continuity. My patch is failing C1 even though it appears to me that I meet the coplanarity condition for the triangles adjacent to the edge. What is wrong? I have not been successful thus far at deciphering the C2 condition from the paper. I did confirm that my patch edges matches the shape of the 1d curve I previously produced with the order 4 bezier. -- Sent from: http://forum.openscad.org/
A
adrianv
Wed, Apr 3, 2019 1:34 AM

I remain baffled by the lack of C1 agreement for my triangular patch.  I ran
across another reference which I think is a little bit easier to follow:

https://pdfs.semanticscholar.org/3854/c6e3ea6367eb7ad8b340f944ee4f1502ac10.pdf

But at least for C1, I don't see anything new---my control points are
coplanar and yet my patch lacks C1 continuity at the edge.  I tried
implementing a non-recursive calculation of the patch and it matched my
previous calculation.

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

I remain baffled by the lack of C1 agreement for my triangular patch. I ran across another reference which I think is a little bit easier to follow: https://pdfs.semanticscholar.org/3854/c6e3ea6367eb7ad8b340f944ee4f1502ac10.pdf But at least for C1, I don't see anything new---my control points are coplanar and yet my patch lacks C1 continuity at the edge. I tried implementing a non-recursive calculation of the patch and it matched my previous calculation. -- Sent from: http://forum.openscad.org/
RP
Ronaldo Persiano
Fri, Apr 5, 2019 3:25 PM

adrianv avm4@cornell.edu wrote:

I remain baffled by the lack of C1 agreement for my triangular patch.  I
ran
across another reference which I think is a little bit easier to follow:

Thank you for that reference: a very useful procedure.

I am also surprised that the coplanarity condition is not enough to a C1
joint. I guess I missed something from the references and that something
else is needed. I was not successful in my attempts to model a C2 or even a
C1 corner with degree 6 tripatches. However I got a tripatch model for the
cylindrical shape of the edges.

It is clear that the coplanarity condition is not preserved when we promote
a degree elevation of your degree 4 model. When we apply the degree
elevation of 1 degree to your model, the middle triangle of the border is
no longer orthogonal to the edge curve plane.

[image: DegreeElevationTo5.PNG]

To get the degree elevation I use the following function:

// find the representation of a degree n tripatch p as a degree n+m tripatch
function triPatchDegreeElevation(p, m) =
m==0? p:
let( n = len(p),
q = [ p[0],
for(i=[1:n-1], u = 1-i/n )
[ up[i][0] + (1-u)p[i-1][0],
for(j=[1:1:i-1], v = j/i )
(1-u)vp[i-1][j-1] +  (1-u)
(1-v)p[i-1][j] +
u
p[i][j],
u
p[i][i] + (1-u)p[i-1][i-1]
],
[ p[n-1][0],
for(j=[1:1:n-1], v = j/n ) v
p[n-1][j-1] + (1-v)*p[n-1][j],
p[n-1][n-1]
]
] )
triPatchDegreeElevation(q, m-1);

Note that this function supposes the input tripatch p is a triangular
matrix bellow the diagonal and not above as you defined in your codes.

The cylindrical shape of a rounded edge (a sweep of the degree 4 border
curve) may be modeled by:

function cylindricalPatchCP(p0, p1, p2, d, r0) =
let(  cv = curveG2CP([p0,p1,p2],r0),
bs = BzSubdiv(cv,1/2) )
[ [bs[4]+d],
[ bs[3]+3d/4, bs[5]+3d/4 ],
[ bs[2]+d/2, 2*(bs[4]+d/2)-(bs[2]+bs[6]+d)/2 , bs[6]+d/2 ],
[ bs[1]+d/4, (cv[1]+cv[2])/2+d/4, (cv[2]+cv[3])/2+d/4, bs[7]+d/4 ],
cv
];

// our well known degree 4 curve

function curveG2CP(p,r0=0.5) =
[ p[0], p[0]+r0*(p[1]-p[0]), p[1], p[2]+r0*(p[1]-p[2]), p[2] ];

// Bezier subdivision of CP p

function BzSubdiv(p,u) =
len(p) == 2 ? [p[0], (1-u)p[0]+up[1], p[1]] :
[ p[0],
each BzSubdiv([for(i=[0:len(p)-2]) (1-u)p[i]+up[i+1]],u),
p[len(p)-1] ];

That patch makes a clear C1 joint with its mirror image along axis x. This
two patches satisfy the planarity condition at the common border even with
a degree elevation.

Taking all this in consideration, my next attempt will be to find a model
such that both itself and its 1 degree elevation satisfy the condition of
orthogonality of the border triangles and the plane of border curve.

adrianv <avm4@cornell.edu> wrote: > I remain baffled by the lack of C1 agreement for my triangular patch. I > ran > across another reference which I think is a little bit easier to follow: > Thank you for that reference: a very useful procedure. I am also surprised that the coplanarity condition is not enough to a C1 joint. I guess I missed something from the references and that something else is needed. I was not successful in my attempts to model a C2 or even a C1 corner with degree 6 tripatches. However I got a tripatch model for the cylindrical shape of the edges. It is clear that the coplanarity condition is not preserved when we promote a degree elevation of your degree 4 model. When we apply the degree elevation of 1 degree to your model, the middle triangle of the border is no longer orthogonal to the edge curve plane. [image: DegreeElevationTo5.PNG] To get the degree elevation I use the following function: // find the representation of a degree n tripatch p as a degree n+m tripatch function triPatchDegreeElevation(p, m) = m==0? p: let( n = len(p), q = [ p[0], for(i=[1:n-1], u = 1-i/n ) [ u*p[i][0] + (1-u)*p[i-1][0], for(j=[1:1:i-1], v = j/i ) (1-u)*v*p[i-1][j-1] + (1-u)*(1-v)*p[i-1][j] + u*p[i][j], u*p[i][i] + (1-u)*p[i-1][i-1] ], [ p[n-1][0], for(j=[1:1:n-1], v = j/n ) v*p[n-1][j-1] + (1-v)*p[n-1][j], p[n-1][n-1] ] ] ) triPatchDegreeElevation(q, m-1); Note that this function supposes the input tripatch p is a triangular matrix bellow the diagonal and not above as you defined in your codes. The cylindrical shape of a rounded edge (a sweep of the degree 4 border curve) may be modeled by: function cylindricalPatchCP(p0, p1, p2, d, r0) = let( cv = curveG2CP([p0,p1,p2],r0), bs = BzSubdiv(cv,1/2) ) [ [bs[4]+d], [ bs[3]+3*d/4, bs[5]+3*d/4 ], [ bs[2]+d/2, 2*(bs[4]+d/2)-(bs[2]+bs[6]+d)/2 , bs[6]+d/2 ], [ bs[1]+d/4, (cv[1]+cv[2])/2+d/4, (cv[2]+cv[3])/2+d/4, bs[7]+d/4 ], cv ]; // our well known degree 4 curve function curveG2CP(p,r0=0.5) = [ p[0], p[0]+r0*(p[1]-p[0]), p[1], p[2]+r0*(p[1]-p[2]), p[2] ]; // Bezier subdivision of CP p function BzSubdiv(p,u) = len(p) == 2 ? [p[0], (1-u)*p[0]+u*p[1], p[1]] : [ p[0], each BzSubdiv([for(i=[0:len(p)-2]) (1-u)*p[i]+u*p[i+1]],u), p[len(p)-1] ]; That patch makes a clear C1 joint with its mirror image along axis x. This two patches satisfy the planarity condition at the common border even with a degree elevation. Taking all this in consideration, my next attempt will be to find a model such that both itself and its 1 degree elevation satisfy the condition of orthogonality of the border triangles and the plane of border curve.
RP
Ronaldo Persiano
Fri, Apr 5, 2019 3:36 PM

I forgot to mention: the parameter d in cylindricalPatchCP() should be
[0,0,0] to get the cylindrical shape. Parameter d deforms the shape without
changing its border derivatives.

I forgot to mention: the parameter d in cylindricalPatchCP() should be [0,0,0] to get the cylindrical shape. Parameter d deforms the shape without changing its border derivatives. >
RP
Ronaldo Persiano
Fri, Apr 5, 2019 4:17 PM

Wrong explanation!

In this version of cylindricalPatchCP(), p0, p1 and p2 are the three points
defining the degree 4 border of the patch. The parameter d is the tip of
the tripatch opposed to that border. A typical call would be:

cylCP  = cylindricalPatchCP([10,0,10], [10,0,0], [10,10,0], [30,0,0], r0);

Em sex, 5 de abr de 2019 às 16:36, Ronaldo Persiano rcmpersiano@gmail.com
escreveu:

I forgot to mention: the parameter d in cylindricalPatchCP() should be
[0,0,0] to get the cylindrical shape. Parameter d deforms the shape without
changing its border derivatives.

Wrong explanation! In this version of cylindricalPatchCP(), p0, p1 and p2 are the three points defining the degree 4 border of the patch. The parameter d is the tip of the tripatch opposed to that border. A typical call would be: cylCP = cylindricalPatchCP([10,0,10], [10,0,0], [10,10,0], [30,0,0], r0); Em sex, 5 de abr de 2019 às 16:36, Ronaldo Persiano <rcmpersiano@gmail.com> escreveu: > I forgot to mention: the parameter d in cylindricalPatchCP() should be > [0,0,0] to get the cylindrical shape. Parameter d deforms the shape without > changing its border derivatives. > >>
RP
Ronaldo Persiano
Sat, Apr 6, 2019 4:01 PM

I am also surprised that the coplanarity condition is not enough to a C1

joint. I guess I missed something from the references and that something
else is needed.

I understand now what was my misunderstanding of the coplanarity condition
for C1 joints. The condition is valid for the graph of real-valued
polynomials and not for muiti-valued polynomials as the tripatches. Both
references we got are concerned with interpolation problems of real-valued
data. In this case, the first two coordinates of the graph have very
specific position depending just on the triangle domain and the polynomial
degree. Although the graph may be regarded as a surface patch, the specific
positions of the projection of the CP on the xy plane does mater.

To get a C1 condition valid for three-variate polynomials we will need to
verify the coplanarity condition for each coordinate polynomial. Taking
adrian model degree 4 patch P as an example, I graphed the three
coordinates of it:

graph(revert(P), [0,0,0], [10,0,0], [0,10,0],[0,2,0], 0.05);
mirror([0,1,0]) graph(revert(P), [0,0,0], [10,0,0], [0,10,0],[0,2,0], 0.05);
translate([7,7,0]) scale([1,1,0.01]) text("X", size=1);

translate([10,0,0]){
graph(revert(P), [0,0,0], [10,0,0], [0,10,0],[2,0,0], 0.05);
mirror([0,1,0]) graph(revert(P), [0,0,0], [10,0,0], [0,10,0],[2,0,0], 0.05);
translate([7,7,0]) scale([1,1,0.01]) text("Y", size=1);
}

translate([20,0,0]){
graph(revert(P), [0,0,0], [10,0,0], [0,10,0],[0,0,2], 0.05);
mirror([0,1,0]) graph(revert(P), [0,0,0], [10,0,0], [0,10,0],[0,0,2], 0.05);
translate([7,7,0]) scale([1,1,0.01]) text("Z", size=1);
}

module graph(p, P0, P1, P2, d=[1,0,0], w) {
n = len(p);
base = [ [P0],  for(i=[1:n-1]) [for(j=[0:i]) (1-i/n)P0 + i/n(
(1-j/i)P1 + j/iP2) ]  ];
tri_grid(base,w);
graph = [for(i=[0:n-1]) [for(j=[0:i]) [base[i][j][0], base[i][j][1],
p[i][j]*d ] ] ];
translate([0,0,1])  color("red") tri_grid(graph,w);
}

module tri_grid(p, w=0.05) {
n = len(p);
for(i=[0:n-2]) for(j=[1:n-i-1]) line([p[n-i-1][j], p[n-i-1][j-1]], w=w);
for(j=[0:n-2]) for(i=[0:n-j-2]) line([p[n-i-1][j], p[n-i-2][j]],  w=w);
for(k=[0:n-2]) for(j=[1:n-k-1]) line([p[j+k][j],  p[j+k-1][j-1]], w=w);
}

function revert(p) = [for(i=[len(p)-1:-1:0]) p[i]];

The revert is needed due to the order adrian defined his patches.

The image outcome of this code is:

[image: graphs.PNG]

where the grids in blue represent the specific arranges the down projection
of the graph CP should have and the grids in red show the graph of each
coordinate of adrian surface. Besides, I mirror the graphs in order to
check the C1 conditions. It is clear from the image that just the
coordinate z has a C1 joint with it mirror image. Both coordinates X and Y
fails to have C1 continuity at those joints.

Based on that considerations we could try to build a patch that meets the
C1 condition (and perhaps the C2 condition) at the joints. However, what we
really need is G1 and G2 continuity, that is a geometric differentiabilty
and not a parametric one. Hard stuff!

I am also surprised that the coplanarity condition is not enough to a C1 >> joint. I guess I missed something from the references and that something >> else is needed. > > I understand now what was my misunderstanding of the coplanarity condition for C1 joints. The condition is valid for the graph of real-valued polynomials and not for muiti-valued polynomials as the tripatches. Both references we got are concerned with interpolation problems of real-valued data. In this case, the first two coordinates of the graph have very specific position depending just on the triangle domain and the polynomial degree. Although the graph may be regarded as a surface patch, the specific positions of the projection of the CP on the xy plane does mater. To get a C1 condition valid for three-variate polynomials we will need to verify the coplanarity condition for each coordinate polynomial. Taking adrian model degree 4 patch P as an example, I graphed the three coordinates of it: graph(revert(P), [0,0,0], [10,0,0], [0,10,0],[0,2,0], 0.05); mirror([0,1,0]) graph(revert(P), [0,0,0], [10,0,0], [0,10,0],[0,2,0], 0.05); translate([7,7,0]) scale([1,1,0.01]) text("X", size=1); translate([10,0,0]){ graph(revert(P), [0,0,0], [10,0,0], [0,10,0],[2,0,0], 0.05); mirror([0,1,0]) graph(revert(P), [0,0,0], [10,0,0], [0,10,0],[2,0,0], 0.05); translate([7,7,0]) scale([1,1,0.01]) text("Y", size=1); } translate([20,0,0]){ graph(revert(P), [0,0,0], [10,0,0], [0,10,0],[0,0,2], 0.05); mirror([0,1,0]) graph(revert(P), [0,0,0], [10,0,0], [0,10,0],[0,0,2], 0.05); translate([7,7,0]) scale([1,1,0.01]) text("Z", size=1); } module graph(p, P0, P1, P2, d=[1,0,0], w) { n = len(p); base = [ [P0], for(i=[1:n-1]) [for(j=[0:i]) (1-i/n)*P0 + i/n*( (1-j/i)*P1 + j/i*P2) ] ]; tri_grid(base,w); graph = [for(i=[0:n-1]) [for(j=[0:i]) [base[i][j][0], base[i][j][1], p[i][j]*d ] ] ]; translate([0,0,1]) color("red") tri_grid(graph,w); } module tri_grid(p, w=0.05) { n = len(p); for(i=[0:n-2]) for(j=[1:n-i-1]) line([p[n-i-1][j], p[n-i-1][j-1]], w=w); for(j=[0:n-2]) for(i=[0:n-j-2]) line([p[n-i-1][j], p[n-i-2][j]], w=w); for(k=[0:n-2]) for(j=[1:n-k-1]) line([p[j+k][j], p[j+k-1][j-1]], w=w); } function revert(p) = [for(i=[len(p)-1:-1:0]) p[i]]; The revert is needed due to the order adrian defined his patches. The image outcome of this code is: [image: graphs.PNG] where the grids in blue represent the specific arranges the down projection of the graph CP should have and the grids in red show the graph of each coordinate of adrian surface. Besides, I mirror the graphs in order to check the C1 conditions. It is clear from the image that just the coordinate z has a C1 joint with it mirror image. Both coordinates X and Y fails to have C1 continuity at those joints. Based on that considerations we could try to build a patch that meets the C1 condition (and perhaps the C2 condition) at the joints. However, what we really need is G1 and G2 continuity, that is a geometric differentiabilty and not a parametric one. Hard stuff!
RP
Ronaldo Persiano
Mon, Apr 8, 2019 5:48 PM

Based on that considerations we could try to build a patch that meets the
C1 condition (and perhaps the C2 condition) at the joints. However, what we
really need is G1 and G2 continuity, that is a geometric differentiability and
not a parametric one. Hard stuff!

Well, I have a good news and a definitely bad one. I have found in Farin's
book ("Curves and Surfaces for CAGD") the full condition for a C1 joint
between to tripatches. Besides the co-planarity condition it is required
that any pair of CP grid triangle adjacent to the meeting border of the two
patches is an affine image of the other pairs. This affine transform should
not include any reflection, just translations, rotations and positive
scales. The following image shows the C1 joint of a degree 2 patch with its
mirror image:

[image: C1joint.PNG]

The grid in red is a mirror image of the grid in blue. The transparent
pairs of triangles satisfy the conditions of being co-planar and each one
is an affine transform of the other pair without any reflection. The joint
is C1. For patches of degree n the number of pairs to be considered will be
n.  Note that the condition excludes reflections as a possible affine
transform and the following image shows what happens when the affine
transform between pairs does not meet that requirement:

[image: NonC1joint.PNG]

In this example the adjacent pairs of triangles although co-planar does not
meet the affine condition restriction. The joint is clearly not C1.

I did try to apply this condition to model a rounded corner with a tripatch
and that is the bad news: it seems impossible to get, even the C1
condition, with a tripatch of any degree with all the border constraints of
a rounded corner we need. To understand my point, consider the following
image that schematically represents a tripatch of undefined degree intended
to round a corner:

[image: SchematicCorner.PNG]

The blue lines are the patch border and some of the grid triangles near the
patch corner are represented. Besides I added the grid triangles of the
mirrored patch near patch corner B. To meet our constraints, the grid
triangles in the patch corner should be a rectangle triangle whose
hypotenuse is towards the patch center. Then, along the border AB, we need
to have the grid triangles as illustrated and no affine transform will
bring a triangle pair near A to a triangle pair near B except with some
negative scale factor (which is a reflection). So, the conditions to have a
rounded corner with curvature continuity does not allow to meet the
condition of of a C1 joint with tripatch of any degree.

We could try to model the corner with a set of tripatches like the
Clough-Tocher scheme that uses three patches, or Power-Sabin scheme with 6
tripatches. However, to get a C2 conditions between two patches of the
scheme seems to require higher degree polynomials.

The great advantage of the use of tripatch over the rectangular patch would
be the 3 symmetries that lacks in the later. It is possible to get a 3
symmetry based on the rectangular patch solution by taking the media of
sampling the three surface patches each one collapsing a row to one corner
vertex. That would be time consuming (three evaluations of a degree 8
polynomial for each sample point).

The asymmetry of the rectangular patch does not seems great enough to
justify that onus. Besides, I have confirmed that the collapsed rectangular
patch that rounds a corner is indeed curvature continuous as we had
supposed.

> > Based on that considerations we could try to build a patch that meets the > C1 condition (and perhaps the C2 condition) at the joints. However, what we > really need is G1 and G2 continuity, that is a geometric differentiability and > not a parametric one. Hard stuff! > Well, I have a good news and a definitely bad one. I have found in Farin's book ("Curves and Surfaces for CAGD") the full condition for a C1 joint between to tripatches. Besides the co-planarity condition it is required that any pair of CP grid triangle adjacent to the meeting border of the two patches is an affine image of the other pairs. This affine transform should not include any reflection, just translations, rotations and positive scales. The following image shows the C1 joint of a degree 2 patch with its mirror image: [image: C1joint.PNG] The grid in red is a mirror image of the grid in blue. The transparent pairs of triangles satisfy the conditions of being co-planar and each one is an affine transform of the other pair without any reflection. The joint is C1. For patches of degree n the number of pairs to be considered will be n. Note that the condition excludes reflections as a possible affine transform and the following image shows what happens when the affine transform between pairs does not meet that requirement: [image: NonC1joint.PNG] In this example the adjacent pairs of triangles although co-planar does not meet the affine condition restriction. The joint is clearly not C1. I did try to apply this condition to model a rounded corner with a tripatch and that is the bad news: it seems impossible to get, even the C1 condition, with a tripatch of any degree with all the border constraints of a rounded corner we need. To understand my point, consider the following image that schematically represents a tripatch of undefined degree intended to round a corner: [image: SchematicCorner.PNG] The blue lines are the patch border and some of the grid triangles near the patch corner are represented. Besides I added the grid triangles of the mirrored patch near patch corner B. To meet our constraints, the grid triangles in the patch corner should be a rectangle triangle whose hypotenuse is towards the patch center. Then, along the border AB, we need to have the grid triangles as illustrated and no affine transform will bring a triangle pair near A to a triangle pair near B except with some negative scale factor (which is a reflection). So, the conditions to have a rounded corner with curvature continuity does not allow to meet the condition of of a C1 joint with tripatch of any degree. We could try to model the corner with a set of tripatches like the Clough-Tocher scheme that uses three patches, or Power-Sabin scheme with 6 tripatches. However, to get a C2 conditions between two patches of the scheme seems to require higher degree polynomials. The great advantage of the use of tripatch over the rectangular patch would be the 3 symmetries that lacks in the later. It is possible to get a 3 symmetry based on the rectangular patch solution by taking the media of sampling the three surface patches each one collapsing a row to one corner vertex. That would be time consuming (three evaluations of a degree 8 polynomial for each sample point). The asymmetry of the rectangular patch does not seems great enough to justify that onus. Besides, I have confirmed that the collapsed rectangular patch that rounds a corner is indeed curvature continuous as we had supposed.
A
adrianv
Mon, Apr 8, 2019 9:21 PM

It is great to have a resolution to the questions about the triangular
patches.

Can you elaborate a bit on the condition?  In the first example, it appears
the two top triangles are not coplanar.  Is that just a rendering issue?  In
your second example (with the obvious C1 failure) it appears that the
bordering triangles can be mapped onto each other by a rotation.  I assume
the affine transformation is confined to the plane that contains the
triangles.

In musing a bit about symmetry it has occurred to me that most applications
for this would be shapes that lacked 3 axis symmetry anyway.  Most likely
an object would be rounded in a symmetric way in the x-y plane but then in a
different way in the z direction because the object might be much thinner in
the z direction, for example.  It seems like it makes sense to simply align
the odd axis along the collapsed line of the  square in the patch.

It does raise the question about potential advantages of the extrusion
approach.

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

It is great to have a resolution to the questions about the triangular patches. Can you elaborate a bit on the condition? In the first example, it appears the two top triangles are not coplanar. Is that just a rendering issue? In your second example (with the obvious C1 failure) it appears that the bordering triangles can be mapped onto each other by a rotation. I assume the affine transformation is confined to the plane that contains the triangles. In musing a bit about symmetry it has occurred to me that most applications for this would be shapes that lacked 3 axis symmetry anyway. Most likely an object would be rounded in a symmetric way in the x-y plane but then in a different way in the z direction because the object might be much thinner in the z direction, for example. It seems like it makes sense to simply align the odd axis along the collapsed line of the square in the patch. It does raise the question about potential advantages of the extrusion approach. -- Sent from: http://forum.openscad.org/
RP
Ronaldo Persiano
Tue, Apr 9, 2019 12:59 AM

Can you elaborate a bit on the condition?  In the first example, it appears
the two top triangles are not coplanar.  Is that just a rendering issue?

The condition for a C1 joint between two tripatches I have found in Farin's
book was just that small reference:

[image: C1Farin.PNG]

It is clear that if the pair is an affine map of the domain then each pair
is an affine map the other pairs. Although the text does not say it, I have
found in my experiments that the affine map in that condition cannot
include any reflection but just translations, rotations and positive
scales. The second example of my previous message corroborates that. I have
not checked whether shears are allowed.

In my examples, the pairs of triangles meeting at the border are all
coplanars. The view angle I used to generate the images might not have
being the best. You may experiment and check my conclusions playing with
the code I have used to produce the images:

// The C1 case CP
P = [ [[0,-3,0]],
[[0,-2,1.5],[-2,-2,0]],
[[2,0,0],[0,0,1.5],[-2,0,0]]
];

// The non-C1 case CP
Q = [ [[0,-3,0]],
[[2,-2,0],[-2,-2,0]],
[[2,0,0],[0,0,2],[-2,0,0]]
];

// The C1 case
translate(){
color("red")
tri_grid(P,w);
showTriPatch(P);
%showTriPatch([[P[2][0]], [P[2][1], P[1][0]]]);
%showTriPatch([[P[2][1]], [P[2][2], P[1][1]]]);
}
// Its mirror image
mirror([0,1,0]) {
color("blue")
tri_grid(P,w);
showTriPatch(P);
%showTriPatch([[P[2][0]], [P[2][1], P[1][0]]]);
%showTriPatch([[P[2][1]], [P[2][2], P[1][1]]]);
}

// The non-C1 case
translate([0,7,0]){
color("red")
tri_grid(Q,w);
showTriPatch(Q);
scale([1,1.5,1])
mirror([0,1,0]){
showTriPatch(Q);
color("blue")
tri_grid(Q,w);
}
}

// sample a tripatch with CP cp in a triangular array

function triPatchSample(cp,n) =
[for(i=[0:n-1]) [for(j=[0:i]) BtriPatchPoint(cp, (n-1-i)/(n-1), j/(n-1))
] ];

// generates the image of the surface of a tripatch p

module showTriPatch(p,n=10) {
pdat = trimesh2polyhedron(triPatchSample(p,n));
polyhedron(pdat[0],pdat[1]);
}

// computes the point in a tripatch mapped by the parameters (u,v)

function BtriPatchPoint(p,u,v) =
len(p) == 1 ? p[0][0] :
let( n  = len(p),
pu = [for(i=[0:n-2]) p[i] ],
pv = [for(i=[1:n-1]) [for(j=[0:i-1]) p[i][j] ] ],
pw = [for(i=[1:n-1]) [for(j=[1:  i]) p[i][j] ] ] )
BtriPatchPoint(upu + vpv + (1-u-v)*pw, u, v);

// generates the mesh of a triangular array of 3D points in a polyhedron
data format [verts, faces]

function trimesh2polyhedron(p,inv=false) =
let( n = len(p),
vertices = inv ?  [ for(i=[0:n-1], j=[0:i]) p[i][i-j] ]:
[ for(pt=p, q=pt) q ] ,
tris = concat(
[for(i=[1:n-1], j=[1:i])
[ j+(i+1)(i)/2, j-1+(i-1)(i)/2, j-1+(i+1)(i)/2 ]
],
n <= 2 ? [] :
[for(i=[1:n-2], j=[1:i])
[ j+(i+1)
(i+2)/2, j+(i+1)(i)/2, j-1+(i+1)(i)/2 ]
]) )
[ vertices, tris ];

module line(p,closed=false,dots=false,w=0.1)
if (dots)
for(i=[0:len(p)-1])
translate(p[i]) sphere(4*w);
else
for(i=[0:len(p)-(closed? 1:2)])
hull(){ translate(p[i])  sphere(w);
translate(p[(i+1)%len(p)]) sphere(w);
}

// draw the mesh of a triangular array of points

module tri_grid(p, w=0.05) {
n = len(p);
for(i=[0:n-2]) for(j=[1:n-i-1]) line([p[n-i-1][j], p[n-i-1][j-1]], w=w);
for(j=[0:n-2]) for(i=[0:n-j-2]) line([p[n-i-1][j], p[n-i-2][j]],  w=w);
for(k=[0:n-2]) for(j=[1:n-k-1]) line([p[j+k][j],  p[j+k-1][j-1]], w=w);
}

In your second example (with the obvious C1 failure) it appears that the

bordering triangles can be mapped onto each other by a rotation.  I assume
the affine transformation is confined to the plane that contains the
triangles.

Yes, they can but mapping the triangle of a patch in the triangle of the
other patch. In the code above, I changed one of the patches in order to
make this clearer. The two patches now are not the mirror image of each
other.

In musing a bit about symmetry it has occurred to me that most applications

for this would be shapes that lacked 3 axis symmetry anyway.  Most likely
an object would be rounded in a symmetric way in the x-y plane but then in
a
different way in the z direction because the object might be much thinner
in
the z direction, for example.  It seems like it makes sense to simply align
the odd axis along the collapsed line of the  square in the patch.

I am not sure this makes sense. In the method of rounding a cube by hulling
spheres, would you consider a smashed sphere to have that asymmetry?
Anyway, the asymmetry of the rectangular patch with a collapsed row is very
very mild and should not have any significant effect.

It does raise the question about potential advantages of the extrusion
approach.

I agree.

> Can you elaborate a bit on the condition? In the first example, it appears > the two top triangles are not coplanar. Is that just a rendering issue? > The condition for a C1 joint between two tripatches I have found in Farin's book was just that small reference: [image: C1Farin.PNG] It is clear that if the pair is an affine map of the domain then each pair is an affine map the other pairs. Although the text does not say it, I have found in my experiments that the affine map in that condition cannot include any reflection but just translations, rotations and positive scales. The second example of my previous message corroborates that. I have not checked whether shears are allowed. In my examples, the pairs of triangles meeting at the border are all coplanars. The view angle I used to generate the images might not have being the best. You may experiment and check my conclusions playing with the code I have used to produce the images: // The C1 case CP P = [ [[0,-3,0]], [[0,-2,1.5],[-2,-2,0]], [[2,0,0],[0,0,1.5],[-2,0,0]] ]; // The non-C1 case CP Q = [ [[0,-3,0]], [[2,-2,0],[-2,-2,0]], [[2,0,0],[0,0,2],[-2,0,0]] ]; // The C1 case translate(){ color("red") tri_grid(P,w); showTriPatch(P); %showTriPatch([[P[2][0]], [P[2][1], P[1][0]]]); %showTriPatch([[P[2][1]], [P[2][2], P[1][1]]]); } // Its mirror image mirror([0,1,0]) { color("blue") tri_grid(P,w); showTriPatch(P); %showTriPatch([[P[2][0]], [P[2][1], P[1][0]]]); %showTriPatch([[P[2][1]], [P[2][2], P[1][1]]]); } // The non-C1 case translate([0,7,0]){ color("red") tri_grid(Q,w); showTriPatch(Q); scale([1,1.5,1]) mirror([0,1,0]){ showTriPatch(Q); color("blue") tri_grid(Q,w); } } // sample a tripatch with CP cp in a triangular array function triPatchSample(cp,n) = [for(i=[0:n-1]) [for(j=[0:i]) BtriPatchPoint(cp, (n-1-i)/(n-1), j/(n-1)) ] ]; // generates the image of the surface of a tripatch p module showTriPatch(p,n=10) { pdat = trimesh2polyhedron(triPatchSample(p,n)); polyhedron(pdat[0],pdat[1]); } // computes the point in a tripatch mapped by the parameters (u,v) function BtriPatchPoint(p,u,v) = len(p) == 1 ? p[0][0] : let( n = len(p), pu = [for(i=[0:n-2]) p[i] ], pv = [for(i=[1:n-1]) [for(j=[0:i-1]) p[i][j] ] ], pw = [for(i=[1:n-1]) [for(j=[1: i]) p[i][j] ] ] ) BtriPatchPoint(u*pu + v*pv + (1-u-v)*pw, u, v); // generates the mesh of a triangular array of 3D points in a polyhedron data format [verts, faces] function trimesh2polyhedron(p,inv=false) = let( n = len(p), vertices = inv ? [ for(i=[0:n-1], j=[0:i]) p[i][i-j] ]: [ for(pt=p, q=pt) q ] , tris = concat( [for(i=[1:n-1], j=[1:i]) [ j+(i+1)*(i)/2, j-1+(i-1)*(i)/2, j-1+(i+1)*(i)/2 ] ], n <= 2 ? [] : [for(i=[1:n-2], j=[1:i]) [ j+(i+1)*(i+2)/2, j+(i+1)*(i)/2, j-1+(i+1)*(i)/2 ] ]) ) [ vertices, tris ]; module line(p,closed=false,dots=false,w=0.1) if (dots) for(i=[0:len(p)-1]) translate(p[i]) sphere(4*w); else for(i=[0:len(p)-(closed? 1:2)]) hull(){ translate(p[i]) sphere(w); translate(p[(i+1)%len(p)]) sphere(w); } // draw the mesh of a triangular array of points module tri_grid(p, w=0.05) { n = len(p); for(i=[0:n-2]) for(j=[1:n-i-1]) line([p[n-i-1][j], p[n-i-1][j-1]], w=w); for(j=[0:n-2]) for(i=[0:n-j-2]) line([p[n-i-1][j], p[n-i-2][j]], w=w); for(k=[0:n-2]) for(j=[1:n-k-1]) line([p[j+k][j], p[j+k-1][j-1]], w=w); } In your second example (with the obvious C1 failure) it appears that the > bordering triangles can be mapped onto each other by a rotation. I assume > the affine transformation is confined to the plane that contains the > triangles. Yes, they can but mapping the triangle of a patch in the triangle of the other patch. In the code above, I changed one of the patches in order to make this clearer. The two patches now are not the mirror image of each other. In musing a bit about symmetry it has occurred to me that most applications > for this would be shapes that lacked 3 axis symmetry anyway. Most likely > an object would be rounded in a symmetric way in the x-y plane but then in > a > different way in the z direction because the object might be much thinner > in > the z direction, for example. It seems like it makes sense to simply align > the odd axis along the collapsed line of the square in the patch. > I am not sure this makes sense. In the method of rounding a cube by hulling spheres, would you consider a smashed sphere to have that asymmetry? Anyway, the asymmetry of the rectangular patch with a collapsed row is very very mild and should not have any significant effect. It does raise the question about potential advantages of the extrusion approach. > > I agree.
T
TLC123
Thu, Apr 25, 2019 7:44 PM

Trigger warning: Rant ahead!

So this rounded business talk goes round and round.

First its rounded polygons.
Then rounded 3d primitives.
Then it turns into rounded 3d boolean operations.

Some suggest the operations need to be built ins.
Some counter it can all be done in user-space with polyhedrons.

Followed by a long exchange that in essence asks how to replicate well
established B-rep operations like those in Parasolid/Opencascade etc based
systems, but now in open-scad, in user-space. Great fun project and all but
completely insane as a task.

Some suggest various nested Minkowski operations as a side note, always with
some huge buts.

Rinse and repeat every few months.

The argument that time consuming builtin operations breaks fast preview
completely falls apart when the suggested alternative is hundred times
slower user-space polyhedron operations. Implemented with only lists of
list, no mutable data or linked structures and some good old float point
errors as a throwback to the very core issue why precision math CGAL was
chosen for Openscad in the first place.

Addressing every other feature request with "solve it yourself in
user-space" cannot be a sane way forward when those ideas already been
ruminated exhaustively in ever repeating waves.

Maybe a more honest answer is that it is hard, very hard, close to
impossible, to implement rounded modelling in this kind of  preview/render
hybrid system. A system that unfortunately painted itself into a bit of a
corner from the beginning. But then again it is infinitely harder to do all
that in the so called user-space.

If a willing few has them magic skills to solve this in pure openscad then
surely they are the kind that could expand CGAL with similar functions for
far lesser effort.

end rant.

My question to the community is: What level of features is sane to be solved
by users and what
belongs in the developer world?

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

Trigger warning: Rant ahead! So this rounded business talk goes round and round. First its rounded polygons. Then rounded 3d primitives. Then it turns into rounded 3d boolean operations. Some suggest the operations need to be built ins. Some counter it can all be done in user-space with polyhedrons. Followed by a long exchange that in essence asks how to replicate well established B-rep operations like those in Parasolid/Opencascade etc based systems, but now in open-scad, in user-space. Great fun project and all but completely insane as a task. Some suggest various nested Minkowski operations as a side note, always with some huge buts. Rinse and repeat every few months. The argument that time consuming builtin operations breaks fast preview completely falls apart when the suggested alternative is hundred times slower user-space polyhedron operations. Implemented with only lists of list, no mutable data or linked structures and some good old float point errors as a throwback to the very core issue why precision math CGAL was chosen for Openscad in the first place. Addressing every other feature request with "solve it yourself in user-space" cannot be a sane way forward when those ideas already been ruminated exhaustively in ever repeating waves. Maybe a more honest answer is that it is hard, very hard, close to impossible, to implement rounded modelling in this kind of preview/render hybrid system. A system that unfortunately painted itself into a bit of a corner from the beginning. But then again it is infinitely harder to do all that in the so called user-space. If a willing few has them magic skills to solve this in pure openscad then surely they are the kind that could expand CGAL with similar functions for far lesser effort. end rant. My question to the community is: What level of features is sane to be solved by users and what belongs in the developer world? -- Sent from: http://forum.openscad.org/
AW
Anthony Walter
Thu, Apr 25, 2019 8:15 PM

I am the OP of the recent reddit post on this subject:

https://www.reddit.com/r/openscad/comments/bfx897/openscad_rounded_boxes/

Being just a beginner I had no idea how to use the hull() function. A day
later I now I know how to use hull() I can say it definitely solves the
problem of generated rounded solid a non issue. The hull() function also is
very fast and is almost instant when used in render(). So in short, rounded
shapes is easy if you just use the hull() function.

A rounded cube with hull():

module roundCube(w, d, h, radius)
{
hull()
{
translate([w / 2, d / 2, 0]) sphere(radius);
translate([w / 2, d / -2, 0]) sphere(radius);
translate([-w / 2, d / 2, 0]) sphere(radius);
translate([-w / 2, d / -2, 0]) sphere(radius);
translate([w / 2, d / 2, h]) sphere(radius);
translate([w / 2, d / -2, h]) sphere(radius);
translate([-w / 2, d / 2, h]) sphere(radius);
translate([-w / 2, d / -2, h]) sphere(radius);
}
}

Easy peezee and done.

I am the OP of the recent reddit post on this subject: https://www.reddit.com/r/openscad/comments/bfx897/openscad_rounded_boxes/ Being just a beginner I had no idea how to use the hull() function. A day later I now I know how to use hull() I can say it definitely solves the problem of generated rounded solid a non issue. The hull() function also is very fast and is almost instant when used in render(). So in short, rounded shapes is easy if you just use the hull() function. A rounded cube with hull(): module roundCube(w, d, h, radius) { hull() { translate([w / 2, d / 2, 0]) sphere(radius); translate([w / 2, d / -2, 0]) sphere(radius); translate([-w / 2, d / 2, 0]) sphere(radius); translate([-w / 2, d / -2, 0]) sphere(radius); translate([w / 2, d / 2, h]) sphere(radius); translate([w / 2, d / -2, h]) sphere(radius); translate([-w / 2, d / 2, h]) sphere(radius); translate([-w / 2, d / -2, h]) sphere(radius); } } Easy peezee and done.
AC
A. Craig West
Thu, Apr 25, 2019 8:23 PM

Hull only works for convex shapes, though. Minkowsky works for non-convex,
but is much slower

On Thu, 25 Apr 2019, 16:16 Anthony Walter, sysrpl@gmail.com wrote:

I am the OP of the recent reddit post on this subject:

https://www.reddit.com/r/openscad/comments/bfx897/openscad_rounded_boxes/

Being just a beginner I had no idea how to use the hull() function. A day
later I now I know how to use hull() I can say it definitely solves the
problem of generated rounded solid a non issue. The hull() function also is
very fast and is almost instant when used in render(). So in short, rounded
shapes is easy if you just use the hull() function.

A rounded cube with hull():

module roundCube(w, d, h, radius)
{
hull()
{
translate([w / 2, d / 2, 0]) sphere(radius);
translate([w / 2, d / -2, 0]) sphere(radius);
translate([-w / 2, d / 2, 0]) sphere(radius);
translate([-w / 2, d / -2, 0]) sphere(radius);
translate([w / 2, d / 2, h]) sphere(radius);
translate([w / 2, d / -2, h]) sphere(radius);
translate([-w / 2, d / 2, h]) sphere(radius);
translate([-w / 2, d / -2, h]) sphere(radius);
}
}

Easy peezee and done.


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

Hull only works for convex shapes, though. Minkowsky works for non-convex, but is much slower On Thu, 25 Apr 2019, 16:16 Anthony Walter, <sysrpl@gmail.com> wrote: > I am the OP of the recent reddit post on this subject: > > https://www.reddit.com/r/openscad/comments/bfx897/openscad_rounded_boxes/ > > Being just a beginner I had no idea how to use the hull() function. A day > later I now I know how to use hull() I can say it definitely solves the > problem of generated rounded solid a non issue. The hull() function also is > very fast and is almost instant when used in render(). So in short, rounded > shapes is easy if you just use the hull() function. > > A rounded cube with hull(): > > module roundCube(w, d, h, radius) > { > hull() > { > translate([w / 2, d / 2, 0]) sphere(radius); > translate([w / 2, d / -2, 0]) sphere(radius); > translate([-w / 2, d / 2, 0]) sphere(radius); > translate([-w / 2, d / -2, 0]) sphere(radius); > translate([w / 2, d / 2, h]) sphere(radius); > translate([w / 2, d / -2, h]) sphere(radius); > translate([-w / 2, d / 2, h]) sphere(radius); > translate([-w / 2, d / -2, h]) sphere(radius); > } > } > > Easy peezee and done. > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >
TP
Torsten Paul
Thu, Apr 25, 2019 8:55 PM

On 25.04.19 21:44, TLC123 wrote:

My question to the community is: What level of features is sane
to be solved by users and what belongs in the developer world?

This is a very good question. Burying it in this topic after the
rant seems a bit strange though...

Also, I suspect there's no easy and single answer. Maybe that
discussion could be had, but separately. So I won't start now.

ciao,
Torsten.

On 25.04.19 21:44, TLC123 wrote: > My question to the community is: What level of features is sane > to be solved by users and what belongs in the developer world? This is a very good question. Burying it in this topic after the rant seems a bit strange though... Also, I suspect there's no easy and single answer. Maybe that discussion could be had, but separately. So I won't start now. ciao, Torsten.
JB
Jordan Brown
Thu, Apr 25, 2019 11:25 PM

I don't claim to really understand the math, but a Minkowski sum
basically involves moving an object A along the entire perimeter of
another object B, and the result is the entire area swept.  Right?

Is there another operation (Minkowski difference, maybe?) that moves B
around the inside of A, and that doesn't include anything that B can't
reach?  (Do I need to draw a picture to describe what I mean?)

This latter operation would seem like a powerful way to take a shape and
round all of its edges, while preserving its major dimensions.

I don't claim to really understand the math, but a Minkowski sum basically involves moving an object A along the entire perimeter of another object B, and the result is the entire area swept.  Right? Is there another operation (Minkowski difference, maybe?) that moves B around the *inside* of A, and that doesn't include anything that B can't reach?  (Do I need to draw a picture to describe what I mean?) This latter operation would seem like a powerful way to take a shape and round all of its edges, while preserving its major dimensions.
JB
Jordan Brown
Thu, Apr 25, 2019 11:32 PM

On 4/25/2019 4:25 PM, Jordan Brown wrote:

I don't claim to really understand the math, but a Minkowski sum
basically involves moving an object A along the entire perimeter of
another object B, and the result is the entire area swept.  Right?

Is there another operation (Minkowski difference, maybe?) that moves B
around the inside of A, and that doesn't include anything that B
can't reach?  (Do I need to draw a picture to describe what I mean?)

This latter operation would seem like a powerful way to take a shape
and round all of its edges, while preserving its major dimensions.

And is often the case, a few searches and clicks later: 
https://en.wikipedia.org/wiki/Opening_(morphology)

On 4/25/2019 4:25 PM, Jordan Brown wrote: > I don't claim to really understand the math, but a Minkowski sum > basically involves moving an object A along the entire perimeter of > another object B, and the result is the entire area swept.  Right? > > Is there another operation (Minkowski difference, maybe?) that moves B > around the *inside* of A, and that doesn't include anything that B > can't reach?  (Do I need to draw a picture to describe what I mean?) > > This latter operation would seem like a powerful way to take a shape > and round all of its edges, while preserving its major dimensions. And is often the case, a few searches and clicks later:  https://en.wikipedia.org/wiki/Opening_(morphology)
NH
nop head
Fri, Apr 26, 2019 6:51 AM

See  https://github.com/openscad/openscad/issues/1678

Minkwoski difference can be done with Minkowski sum and difference but it
is very slow and uses an enormous amount of memory for values of $fn that
make things smooth.

On Fri, 26 Apr 2019 at 06:25, Jordan Brown openscad@jordan.maileater.net
wrote:

On 4/25/2019 4:25 PM, Jordan Brown wrote:

I don't claim to really understand the math, but a Minkowski sum basically
involves moving an object A along the entire perimeter of another object B,
and the result is the entire area swept.  Right?

Is there another operation (Minkowski difference, maybe?) that moves B
around the inside of A, and that doesn't include anything that B can't
reach?  (Do I need to draw a picture to describe what I mean?)

This latter operation would seem like a powerful way to take a shape and
round all of its edges, while preserving its major dimensions.

And is often the case, a few searches and clicks later:
https://en.wikipedia.org/wiki/Opening_(morphology)


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

See https://github.com/openscad/openscad/issues/1678 Minkwoski difference can be done with Minkowski sum and difference but it is very slow and uses an enormous amount of memory for values of $fn that make things smooth. On Fri, 26 Apr 2019 at 06:25, Jordan Brown <openscad@jordan.maileater.net> wrote: > On 4/25/2019 4:25 PM, Jordan Brown wrote: > > I don't claim to really understand the math, but a Minkowski sum basically > involves moving an object A along the entire perimeter of another object B, > and the result is the entire area swept. Right? > > Is there another operation (Minkowski difference, maybe?) that moves B > around the *inside* of A, and that doesn't include anything that B can't > reach? (Do I need to draw a picture to describe what I mean?) > > This latter operation would seem like a powerful way to take a shape and > round all of its edges, while preserving its major dimensions. > > > And is often the case, a few searches and clicks later: > https://en.wikipedia.org/wiki/Opening_(morphology) > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >
A
adrianv
Fri, Apr 26, 2019 11:16 AM

Even for convex shapes hull has limitations.  Anthony, if you think rounding
is "easy peezee" then first I suggest fixing the module so the rounded cube
is the right size rather than 2*r oversized.  Then I ask how you would make
a rounded pyramid with an arbitrary base polygon and apex that is a
designated size and not oversized.  Next, how would you use the hull method
to make a cylinder with rounded ends?  What if the cylinder's ends are not
normal to its axis?  If that's too easy then suppose I construct a parabola
and extrude it.  How would you round that?

data = [for(x=[-2:.05:2])[x,x*x]];
linear_extrude(height=4)polygon(data);

I'm not saying these things can't be done.  For making a rounded polyhedron
you need to put the spheres in the right place, which is not "easy peezee"
in my opinion when the polyhedron is not a cube.  (Oh, and don't forget that
spheres are actually polyhedra, and undersized.)  And the methods that leap
to mind for the cylinder seem little complex.  For the case of the parabolic
shape I don't see a way of using hull that is easier than just generating
the whole shape directly.

The other problem with using hull is that it assumes that it makes sense to
build up your convex object from a union of convex objects.  What if you
create your convex object through difference() operations?  Then you cannot
round the final object using hull() operations.  If everything has to be
constructed with hull() it limits your options for how you can model stuff.

As acwest notes, non-convex shapes cannot be rounded with hull.  In my
experience, nothing I design ends up being convex.  I've been pondering the
task of making a box where the inside joint between the walls and base is
rounded and the top edge is rounded.  To do this for a general box (with an
arbitrary shaped base) appears to be very difficult.

Regarding run time, hull() can be slow.  In fact, for polyhedra with large
numbers of faces it seems that minkowski() is faster than hull().  I just
did a timing test and the hull of 50 spheres with $fn=32 took 38 seconds to
preview.  I understand that technically what's slow for hull() is not the
hull operation but the unavoidable yet unnecessary union operation between
all the spheres.

It is possible to make a general minkowski rounding function with 3 calls to
minkowski.  But is has the limitation that the shape cannot have any areas
thinner than the roundover radius.  Also there is the question of speed.
Reportedly rounding the union of a cylinder and cube (that don't meet at
right angles) takes 12 hours.  And of course it enforces the same rounding
radius globally on the model, which may not be what you need.

acwest wrote

Hull only works for convex shapes, though. Minkowsky works for non-convex,
but is much slower

On Thu, 25 Apr 2019, 16:16 Anthony Walter, <

sysrpl@

> wrote:

I am the OP of the recent reddit post on this subject:

https://www.reddit.com/r/openscad/comments/bfx897/openscad_rounded_boxes/

Being just a beginner I had no idea how to use the hull() function. A day
later I now I know how to use hull() I can say it definitely solves the
problem of generated rounded solid a non issue. The hull() function also
is
very fast and is almost instant when used in render(). So in short,
rounded
shapes is easy if you just use the hull() function.

A rounded cube with hull():

module roundCube(w, d, h, radius)
{
hull()
{
translate([w / 2, d / 2, 0]) sphere(radius);
translate([w / 2, d / -2, 0]) sphere(radius);
translate([-w / 2, d / 2, 0]) sphere(radius);
translate([-w / 2, d / -2, 0]) sphere(radius);
translate([w / 2, d / 2, h]) sphere(radius);
translate([w / 2, d / -2, h]) sphere(radius);
translate([-w / 2, d / 2, h]) sphere(radius);
translate([-w / 2, d / -2, h]) sphere(radius);
}
}

Easy peezee and done.

Even for convex shapes hull has limitations. Anthony, if you think rounding is "easy peezee" then first I suggest fixing the module so the rounded cube is the right size rather than 2*r oversized. Then I ask how you would make a rounded pyramid with an arbitrary base polygon and apex that is a designated size and not oversized. Next, how would you use the hull method to make a cylinder with rounded ends? What if the cylinder's ends are not normal to its axis? If that's too easy then suppose I construct a parabola and extrude it. How would you round that? data = [for(x=[-2:.05:2])[x,x*x]]; linear_extrude(height=4)polygon(data); I'm not saying these things can't be done. For making a rounded polyhedron you need to put the spheres in the right place, which is not "easy peezee" in my opinion when the polyhedron is not a cube. (Oh, and don't forget that spheres are actually polyhedra, and undersized.) And the methods that leap to mind for the cylinder seem little complex. For the case of the parabolic shape I don't see a way of using hull that is easier than just generating the whole shape directly. The other problem with using hull is that it assumes that it makes sense to build up your convex object from a union of convex objects. What if you create your convex object through difference() operations? Then you cannot round the final object using hull() operations. If everything has to be constructed with hull() it limits your options for how you can model stuff. As acwest notes, non-convex shapes cannot be rounded with hull. In my experience, nothing I design ends up being convex. I've been pondering the task of making a box where the inside joint between the walls and base is rounded and the top edge is rounded. To do this for a general box (with an arbitrary shaped base) appears to be very difficult. Regarding run time, hull() can be slow. In fact, for polyhedra with large numbers of faces it seems that minkowski() is faster than hull(). I just did a timing test and the hull of 50 spheres with $fn=32 took 38 seconds to preview. I understand that technically what's slow for hull() is not the hull operation but the unavoidable yet unnecessary union operation between all the spheres. It is possible to make a general minkowski rounding function with 3 calls to minkowski. But is has the limitation that the shape cannot have any areas thinner than the roundover radius. Also there is the question of speed. Reportedly rounding the union of a cylinder and cube (that don't meet at right angles) takes 12 hours. And of course it enforces the same rounding radius globally on the model, which may not be what you need. acwest wrote > Hull only works for convex shapes, though. Minkowsky works for non-convex, > but is much slower > > On Thu, 25 Apr 2019, 16:16 Anthony Walter, &lt; > sysrpl@ > &gt; wrote: > >> I am the OP of the recent reddit post on this subject: >> >> https://www.reddit.com/r/openscad/comments/bfx897/openscad_rounded_boxes/ >> >> Being just a beginner I had no idea how to use the hull() function. A day >> later I now I know how to use hull() I can say it definitely solves the >> problem of generated rounded solid a non issue. The hull() function also >> is >> very fast and is almost instant when used in render(). So in short, >> rounded >> shapes is easy if you just use the hull() function. >> >> A rounded cube with hull(): >> >> module roundCube(w, d, h, radius) >> { >> hull() >> { >> translate([w / 2, d / 2, 0]) sphere(radius); >> translate([w / 2, d / -2, 0]) sphere(radius); >> translate([-w / 2, d / 2, 0]) sphere(radius); >> translate([-w / 2, d / -2, 0]) sphere(radius); >> translate([w / 2, d / 2, h]) sphere(radius); >> translate([w / 2, d / -2, h]) sphere(radius); >> translate([-w / 2, d / 2, h]) sphere(radius); >> translate([-w / 2, d / -2, h]) sphere(radius); >> } >> } >> >> Easy peezee and done. -- Sent from: http://forum.openscad.org/
NH
nop head
Fri, Apr 26, 2019 11:58 AM

Hull is only slow if it has an implicit union inside it. For example if you
place spheres with a for loop or a common translation or rotation then they
get unioned first and that is very slow with CGAL. If you place each sphere
individually, like the example above, then hull is very fast,

Spheres can be made exact by rotate extruding a semi circle with $fn a
multiple of 4. I redefine sphere myself to be that.

//
// Replicate OpenSCAD logic to calculate number of sides from radius
//
function r2sides(r) = $fn ? $fn : ceil(max(min(360/ $fa, r * 2 * PI / $fs),
5));
//
// Round up number of sides to multiple of 4 to ensure points on all axes
//
function r2sides4n(r) = floor((r2sides(r) + 3) / 4) * 4;
//
// Circle with multiple of 4 vertices
//
module Circle(r, d = undef) {
R = is_undef(d) ? r : d / 2;
circle(R, $fn = r2sides4n(R));
}
//
// Semi circle
//
module semi_circle(r)
intersection() {
Circle(r);

    sq = r + 1;
    translate([-sq, 0])
        square([2 * sq, sq]);
}

//
// Sphere that has vertices on all three axes. Has the advantage of giving
correct dimensions when hulled
//
module sphere(r = 1, d = undef) {
R = is_undef(d) ? r : d / 2;
rotate_extrude($fn = r2sides4n(R))
rotate(-90)
semi_circle(R);
}

[image: spheres.png]

I manage to make everything I need with these techniques but a version of
3D Minkowski that would run before the heat death of the universe and
consume less than an infinite amount of memory would be nice.

On Fri, 26 Apr 2019 at 12:16, adrianv avm4@cornell.edu wrote:

Even for convex shapes hull has limitations.  Anthony, if you think
rounding
is "easy peezee" then first I suggest fixing the module so the rounded cube
is the right size rather than 2*r oversized.  Then I ask how you would make
a rounded pyramid with an arbitrary base polygon and apex that is a
designated size and not oversized.  Next, how would you use the hull method
to make a cylinder with rounded ends?  What if the cylinder's ends are not
normal to its axis?  If that's too easy then suppose I construct a parabola
and extrude it.  How would you round that?

data = [for(x=[-2:.05:2])[x,x*x]];
linear_extrude(height=4)polygon(data);

I'm not saying these things can't be done.  For making a rounded polyhedron
you need to put the spheres in the right place, which is not "easy peezee"
in my opinion when the polyhedron is not a cube.  (Oh, and don't forget
that
spheres are actually polyhedra, and undersized.)  And the methods that leap
to mind for the cylinder seem little complex.  For the case of the
parabolic
shape I don't see a way of using hull that is easier than just generating
the whole shape directly.

The other problem with using hull is that it assumes that it makes sense to
build up your convex object from a union of convex objects.  What if you
create your convex object through difference() operations?  Then you cannot
round the final object using hull() operations.  If everything has to be
constructed with hull() it limits your options for how you can model
stuff.

As acwest notes, non-convex shapes cannot be rounded with hull.  In my
experience, nothing I design ends up being convex.  I've been pondering the
task of making a box where the inside joint between the walls and base is
rounded and the top edge is rounded.  To do this for a general box (with an
arbitrary shaped base) appears to be very difficult.

Regarding run time, hull() can be slow.  In fact, for polyhedra with large
numbers of faces it seems that minkowski() is faster than hull().  I just
did a timing test and the hull of 50 spheres with $fn=32 took 38 seconds to
preview.  I understand that technically what's slow for hull() is not the
hull operation but the unavoidable yet unnecessary union operation between
all the spheres.

It is possible to make a general minkowski rounding function with 3 calls
to
minkowski.  But is has the limitation that the shape cannot have any areas
thinner than the roundover radius.  Also there is the question of speed.
Reportedly rounding the union of a cylinder and cube (that don't meet at
right angles) takes 12 hours.  And of course it enforces the same rounding
radius globally on the model, which may not be what you need.

acwest wrote

Hull only works for convex shapes, though. Minkowsky works for

non-convex,

but is much slower

On Thu, 25 Apr 2019, 16:16 Anthony Walter, <

sysrpl@

> wrote:

I am the OP of the recent reddit post on this subject:

Being just a beginner I had no idea how to use the hull() function. A

day

later I now I know how to use hull() I can say it definitely solves the
problem of generated rounded solid a non issue. The hull() function also
is
very fast and is almost instant when used in render(). So in short,
rounded
shapes is easy if you just use the hull() function.

A rounded cube with hull():

module roundCube(w, d, h, radius)
{
hull()
{
translate([w / 2, d / 2, 0]) sphere(radius);
translate([w / 2, d / -2, 0]) sphere(radius);
translate([-w / 2, d / 2, 0]) sphere(radius);
translate([-w / 2, d / -2, 0]) sphere(radius);
translate([w / 2, d / 2, h]) sphere(radius);
translate([w / 2, d / -2, h]) sphere(radius);
translate([-w / 2, d / 2, h]) sphere(radius);
translate([-w / 2, d / -2, h]) sphere(radius);
}
}

Easy peezee and done.

Hull is only slow if it has an implicit union inside it. For example if you place spheres with a for loop or a common translation or rotation then they get unioned first and that is very slow with CGAL. If you place each sphere individually, like the example above, then hull is very fast, Spheres can be made exact by rotate extruding a semi circle with $fn a multiple of 4. I redefine sphere myself to be that. // // Replicate OpenSCAD logic to calculate number of sides from radius // function r2sides(r) = $fn ? $fn : ceil(max(min(360/ $fa, r * 2 * PI / $fs), 5)); // // Round up number of sides to multiple of 4 to ensure points on all axes // function r2sides4n(r) = floor((r2sides(r) + 3) / 4) * 4; // // Circle with multiple of 4 vertices // module Circle(r, d = undef) { R = is_undef(d) ? r : d / 2; circle(R, $fn = r2sides4n(R)); } // // Semi circle // module semi_circle(r) intersection() { Circle(r); sq = r + 1; translate([-sq, 0]) square([2 * sq, sq]); } // // Sphere that has vertices on all three axes. Has the advantage of giving correct dimensions when hulled // module sphere(r = 1, d = undef) { R = is_undef(d) ? r : d / 2; rotate_extrude($fn = r2sides4n(R)) rotate(-90) semi_circle(R); } [image: spheres.png] I manage to make everything I need with these techniques but a version of 3D Minkowski that would run before the heat death of the universe and consume less than an infinite amount of memory would be nice. On Fri, 26 Apr 2019 at 12:16, adrianv <avm4@cornell.edu> wrote: > Even for convex shapes hull has limitations. Anthony, if you think > rounding > is "easy peezee" then first I suggest fixing the module so the rounded cube > is the right size rather than 2*r oversized. Then I ask how you would make > a rounded pyramid with an arbitrary base polygon and apex that is a > designated size and not oversized. Next, how would you use the hull method > to make a cylinder with rounded ends? What if the cylinder's ends are not > normal to its axis? If that's too easy then suppose I construct a parabola > and extrude it. How would you round that? > > data = [for(x=[-2:.05:2])[x,x*x]]; > linear_extrude(height=4)polygon(data); > > I'm not saying these things can't be done. For making a rounded polyhedron > you need to put the spheres in the right place, which is not "easy peezee" > in my opinion when the polyhedron is not a cube. (Oh, and don't forget > that > spheres are actually polyhedra, and undersized.) And the methods that leap > to mind for the cylinder seem little complex. For the case of the > parabolic > shape I don't see a way of using hull that is easier than just generating > the whole shape directly. > > The other problem with using hull is that it assumes that it makes sense to > build up your convex object from a union of convex objects. What if you > create your convex object through difference() operations? Then you cannot > round the final object using hull() operations. If everything has to be > constructed with hull() it limits your options for how you can model > stuff. > > As acwest notes, non-convex shapes cannot be rounded with hull. In my > experience, nothing I design ends up being convex. I've been pondering the > task of making a box where the inside joint between the walls and base is > rounded and the top edge is rounded. To do this for a general box (with an > arbitrary shaped base) appears to be very difficult. > > Regarding run time, hull() can be slow. In fact, for polyhedra with large > numbers of faces it seems that minkowski() is faster than hull(). I just > did a timing test and the hull of 50 spheres with $fn=32 took 38 seconds to > preview. I understand that technically what's slow for hull() is not the > hull operation but the unavoidable yet unnecessary union operation between > all the spheres. > > It is possible to make a general minkowski rounding function with 3 calls > to > minkowski. But is has the limitation that the shape cannot have any areas > thinner than the roundover radius. Also there is the question of speed. > Reportedly rounding the union of a cylinder and cube (that don't meet at > right angles) takes 12 hours. And of course it enforces the same rounding > radius globally on the model, which may not be what you need. > > > acwest wrote > > Hull only works for convex shapes, though. Minkowsky works for > non-convex, > > but is much slower > > > > On Thu, 25 Apr 2019, 16:16 Anthony Walter, &lt; > > > sysrpl@ > > > &gt; wrote: > > > >> I am the OP of the recent reddit post on this subject: > >> > >> > https://www.reddit.com/r/openscad/comments/bfx897/openscad_rounded_boxes/ > >> > >> Being just a beginner I had no idea how to use the hull() function. A > day > >> later I now I know how to use hull() I can say it definitely solves the > >> problem of generated rounded solid a non issue. The hull() function also > >> is > >> very fast and is almost instant when used in render(). So in short, > >> rounded > >> shapes is easy if you just use the hull() function. > >> > >> A rounded cube with hull(): > >> > >> module roundCube(w, d, h, radius) > >> { > >> hull() > >> { > >> translate([w / 2, d / 2, 0]) sphere(radius); > >> translate([w / 2, d / -2, 0]) sphere(radius); > >> translate([-w / 2, d / 2, 0]) sphere(radius); > >> translate([-w / 2, d / -2, 0]) sphere(radius); > >> translate([w / 2, d / 2, h]) sphere(radius); > >> translate([w / 2, d / -2, h]) sphere(radius); > >> translate([-w / 2, d / 2, h]) sphere(radius); > >> translate([-w / 2, d / -2, h]) sphere(radius); > >> } > >> } > >> > >> Easy peezee and done. > > > > > > -- > Sent from: http://forum.openscad.org/ > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >
A
adrianv
Fri, Apr 26, 2019 12:12 PM

nophead wrote

Hull is only slow if it has an implicit union inside it. For example if
you
place spheres with a for loop or a common translation or rotation then
they
get unioned first and that is very slow with CGAL. If you place each
sphere
individually, like the example above, then hull is very fast,

I had forgotten about that.  It's not a very attractive coding method if you
have a lot of stuff to hull, though.  Also note that I had an error in my
code.  It actually takes 3.5 minutes to compute the hull of the 50 spheres.

Spheres can be made exact by rotate extruding a semi circle with $fn a
multiple of 4. I redefine sphere myself to be that.

That's a nice idea.

Note, however, that it only makes hulls exact for faces parallel to the
coordinate planes.  In my example problem of the pyramid it's going to be
very difficult to figure out the effective radius of the "sphere" in the
direction of each face so that you can position them exactly right to get a
hull that actually has the exact dimensions desired.

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

nophead wrote > Hull is only slow if it has an implicit union inside it. For example if > you > place spheres with a for loop or a common translation or rotation then > they > get unioned first and that is very slow with CGAL. If you place each > sphere > individually, like the example above, then hull is very fast, I had forgotten about that. It's not a very attractive coding method if you have a lot of stuff to hull, though. Also note that I had an error in my code. It actually takes 3.5 minutes to compute the hull of the 50 spheres. > Spheres can be made exact by rotate extruding a semi circle with $fn a > multiple of 4. I redefine sphere myself to be that. That's a nice idea. Note, however, that it only makes hulls exact for faces parallel to the coordinate planes. In my example problem of the pyramid it's going to be very difficult to figure out the effective radius of the "sphere" in the direction of each face so that you can position them exactly right to get a hull that actually has the exact dimensions desired. -- Sent from: http://forum.openscad.org/