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/
NH
nop head
Fri, Apr 26, 2019 12:21 PM

Yes, for a triangular base pyramid you would want $fn a multiple of 3 I
suppose but would exact dimensions matter for such a shape when $fn is high
enough to make it smooth? I find, in generally, that only dimensions
parallel to the axes matter in my designs. They are however function over
form, with no artistic element.

On Fri, 26 Apr 2019 at 13:13, adrianv avm4@cornell.edu wrote:

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/


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

Yes, for a triangular base pyramid you would want $fn a multiple of 3 I suppose but would exact dimensions matter for such a shape when $fn is high enough to make it smooth? I find, in generally, that only dimensions parallel to the axes matter in my designs. They are however function over form, with no artistic element. On Fri, 26 Apr 2019 at 13:13, adrianv <avm4@cornell.edu> wrote: > 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/ > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >
A
adrianv
Fri, Apr 26, 2019 6:49 PM

nophead wrote

Yes, for a triangular base pyramid you would want $fn a multiple of 3 I
suppose but would exact dimensions matter for such a shape when $fn is
high
enough to make it smooth? I find, in generally, that only dimensions
parallel to the axes matter in my designs. They are however function over
form, with no artistic element.

That's only if the pyramid is a tetrahedron with an equilateral base.  I had
suggested a generic pyramid, with arbitrary polygonal base (assume convex)
and abitrary apex position.  It's tough to even figure out where the sphere
centers should be if they are perfect spheres.

I printed models with $fn=8 and had print failures because the base of my
model wasn't coplanar due to the error in sphere dimensions.  I do note
that the base is parallel to the coordinate plane.

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

nophead wrote > Yes, for a triangular base pyramid you would want $fn a multiple of 3 I > suppose but would exact dimensions matter for such a shape when $fn is > high > enough to make it smooth? I find, in generally, that only dimensions > parallel to the axes matter in my designs. They are however function over > form, with no artistic element. That's only if the pyramid is a tetrahedron with an equilateral base. I had suggested a generic pyramid, with arbitrary polygonal base (assume convex) and abitrary apex position. It's tough to even figure out where the sphere centers should be if they are perfect spheres. I printed models with $fn=8 and had print failures because the base of my model wasn't coplanar due to the error in sphere dimensions. I do note that the base is parallel to the coordinate plane. -- Sent from: http://forum.openscad.org/
NH
nop head
Fri, Apr 26, 2019 7:21 PM

Yes the built in sphere is missing the poles, so the base would be lifted a
bit. I would never notice because I never use a full sphere at the base
because it starts too horizontal. I use inverted rotate_extruded teardrops
when I need a rounded base, so that starts at 45 degrees. And I never use
such low values of $fn. For example this handle, which is printed flat side
down.

[image: handle.png]

Not perfectly rounded but comfortable enough to hold and easy to print. It
previews in less than a second and renders in 3 seconds. I had to avoid
implicit union inside the hull to get that speed.

On Fri, 26 Apr 2019 at 19:49, adrianv avm4@cornell.edu wrote:

nophead wrote

Yes, for a triangular base pyramid you would want $fn a multiple of 3 I
suppose but would exact dimensions matter for such a shape when $fn is
high
enough to make it smooth? I find, in generally, that only dimensions
parallel to the axes matter in my designs. They are however function over
form, with no artistic element.

That's only if the pyramid is a tetrahedron with an equilateral base.  I
had
suggested a generic pyramid, with arbitrary polygonal base (assume convex)
and abitrary apex position.  It's tough to even figure out where the sphere
centers should be if they are perfect spheres.

I printed models with $fn=8 and had print failures because the base of my
model wasn't coplanar due to the error in sphere dimensions.  I do note
that the base is parallel to the coordinate plane.

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


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

Yes the built in sphere is missing the poles, so the base would be lifted a bit. I would never notice because I never use a full sphere at the base because it starts too horizontal. I use inverted rotate_extruded teardrops when I need a rounded base, so that starts at 45 degrees. And I never use such low values of $fn. For example this handle, which is printed flat side down. [image: handle.png] Not perfectly rounded but comfortable enough to hold and easy to print. It previews in less than a second and renders in 3 seconds. I had to avoid implicit union inside the hull to get that speed. On Fri, 26 Apr 2019 at 19:49, adrianv <avm4@cornell.edu> wrote: > nophead wrote > > Yes, for a triangular base pyramid you would want $fn a multiple of 3 I > > suppose but would exact dimensions matter for such a shape when $fn is > > high > > enough to make it smooth? I find, in generally, that only dimensions > > parallel to the axes matter in my designs. They are however function over > > form, with no artistic element. > > That's only if the pyramid is a tetrahedron with an equilateral base. I > had > suggested a generic pyramid, with arbitrary polygonal base (assume convex) > and abitrary apex position. It's tough to even figure out where the sphere > centers should be if they are perfect spheres. > > I printed models with $fn=8 and had print failures because the base of my > model wasn't coplanar due to the error in sphere dimensions. I do note > that the base is parallel to the coordinate plane. > > > > > -- > 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 7:39 PM

I wasn't trying to print a sphere, but I had used minkowski to generate part
of the base so that part was offset by the sphere radius, but other parts of
the base were generated directly with cube().  The minkowski generated part
didn't end up where I expected due to the sphere offset.  I had $fn small
during the design phase since minkowski is slow.  I later raised $fn to 20,
but by then I was doing a cos(180/$fn) adjustment so I don't know if it
would have printed correctly or not....  My radius was only 2, so some
people might claim $fn=20 was overkill.  The model takes ~15 minutes.  (I
always wrap minkowksi in render())

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

I wasn't trying to print a sphere, but I had used minkowski to generate part of the base so that part was offset by the sphere radius, but other parts of the base were generated directly with cube(). The minkowski generated part didn't end up where I expected due to the sphere offset. I had $fn small during the design phase since minkowski is slow. I later raised $fn to 20, but by then I was doing a cos(180/$fn) adjustment so I don't know if it would have printed correctly or not.... My radius was only 2, so some people might claim $fn=20 was overkill. The model takes ~15 minutes. (I always wrap minkowksi in render()) -- Sent from: http://forum.openscad.org/
CA
Carsten Arnholm
Fri, Apr 26, 2019 7:45 PM

On 25.04.2019 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?

Good rant. I agree the efforts in developing user-space solutions in
OpenSCAD are daunting to all but a few, partly because of the
declarative language, where the order of things don't matter as in other
languages and where you cannot reassign variables. etc.

Also, the inherent slowness of CGAL seems to drive some of the advanced
efforts in user space, but the limitations of the language makes it
quite difficult to make progress in my opinion. These efforts are
commendable, but they seem to mainly try to work around limitations of
CGAL speed instead of using its strengths. Again, in my subjective opinion.

So I think that if the core is fast and the language available to the
user is rich, it means more features can be developed in user space. A
fundamental requirement is that that the core functionality runs fast
enough for non-trivial problems.

The last couple of years I have been developing an independent tool that
addresses these issues. The tool is called AngelCAD and it has recently
been released as open source, more information & downloads at
https://arnholm.github.io/angelcad-docs/

The philosophy in AngelCAD is to use a fast boolean engine (Carve)
combined with a rich scripting language (AngelScript), so perhaps it
will enable development of user space libraries

An example of rounding with AngelCAD (runs < 0.5 sec with rounding).
https://gist.github.com/arnholm/248d9a14e92b05ab8942d5f9a6611851

Carsten Arnholm

On 25.04.2019 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? Good rant. I agree the efforts in developing user-space solutions in OpenSCAD are daunting to all but a few, partly because of the declarative language, where the order of things don't matter as in other languages and where you cannot reassign variables. etc. Also, the inherent slowness of CGAL seems to drive some of the advanced efforts in user space, but the limitations of the language makes it quite difficult to make progress in my opinion. These efforts are commendable, but they seem to mainly try to work around limitations of CGAL speed instead of using its strengths. Again, in my subjective opinion. So I think that if the core is fast and the language available to the user is rich, it means more features can be developed in user space. A fundamental requirement is that that the core functionality runs fast enough for non-trivial problems. The last couple of years I have been developing an independent tool that addresses these issues. The tool is called AngelCAD and it has recently been released as open source, more information & downloads at https://arnholm.github.io/angelcad-docs/ The philosophy in AngelCAD is to use a fast boolean engine (Carve) combined with a rich scripting language (AngelScript), so perhaps it will enable development of user space libraries An example of rounding with AngelCAD (runs < 0.5 sec with rounding). https://gist.github.com/arnholm/248d9a14e92b05ab8942d5f9a6611851 Carsten Arnholm
NH
nop head
Fri, Apr 26, 2019 9:59 PM

Nice, but I have no problem with the declarative functional style of
OpenSCAD  . I prefer that type of language when describing objects rather
than procedural. The huge problem is the speed and memory requirements of
CGAL. Can it be replaced by Carve in OpenSCAD?

On Fri, 26 Apr 2019 at 20:46, Carsten Arnholm arnholm@arnholm.org wrote:

On 25.04.2019 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?

Good rant. I agree the efforts in developing user-space solutions in
OpenSCAD are daunting to all but a few, partly because of the
declarative language, where the order of things don't matter as in other
languages and where you cannot reassign variables. etc.

Also, the inherent slowness of CGAL seems to drive some of the advanced
efforts in user space, but the limitations of the language makes it
quite difficult to make progress in my opinion. These efforts are
commendable, but they seem to mainly try to work around limitations of
CGAL speed instead of using its strengths. Again, in my subjective opinion.

So I think that if the core is fast and the language available to the
user is rich, it means more features can be developed in user space. A
fundamental requirement is that that the core functionality runs fast
enough for non-trivial problems.

The last couple of years I have been developing an independent tool that
addresses these issues. The tool is called AngelCAD and it has recently
been released as open source, more information & downloads at
https://arnholm.github.io/angelcad-docs/

The philosophy in AngelCAD is to use a fast boolean engine (Carve)
combined with a rich scripting language (AngelScript), so perhaps it
will enable development of user space libraries

An example of rounding with AngelCAD (runs < 0.5 sec with rounding).
https://gist.github.com/arnholm/248d9a14e92b05ab8942d5f9a6611851

Carsten Arnholm


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

Nice, but I have no problem with the declarative functional style of OpenSCAD . I prefer that type of language when describing objects rather than procedural. The huge problem is the speed and memory requirements of CGAL. Can it be replaced by Carve in OpenSCAD? On Fri, 26 Apr 2019 at 20:46, Carsten Arnholm <arnholm@arnholm.org> wrote: > On 25.04.2019 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? > > > Good rant. I agree the efforts in developing user-space solutions in > OpenSCAD are daunting to all but a few, partly because of the > declarative language, where the order of things don't matter as in other > languages and where you cannot reassign variables. etc. > > Also, the inherent slowness of CGAL seems to drive some of the advanced > efforts in user space, but the limitations of the language makes it > quite difficult to make progress in my opinion. These efforts are > commendable, but they seem to mainly try to work around limitations of > CGAL speed instead of using its strengths. Again, in my subjective opinion. > > So I think that if the core is fast and the language available to the > user is rich, it means more features can be developed in user space. A > fundamental requirement is that that the core functionality runs fast > enough for non-trivial problems. > > The last couple of years I have been developing an independent tool that > addresses these issues. The tool is called AngelCAD and it has recently > been released as open source, more information & downloads at > https://arnholm.github.io/angelcad-docs/ > > The philosophy in AngelCAD is to use a fast boolean engine (Carve) > combined with a rich scripting language (AngelScript), so perhaps it > will enable development of user space libraries > > An example of rounding with AngelCAD (runs < 0.5 sec with rounding). > https://gist.github.com/arnholm/248d9a14e92b05ab8942d5f9a6611851 > > Carsten Arnholm > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >
A
arnholm@arnholm.org
Sat, Apr 27, 2019 5:38 AM

On 2019-04-26 23:59, nop head wrote:

Nice, but I have no problem with the declarative functional style of
OpenSCAD  . I prefer that type of language when describing objects
rather than procedural.

What is the reason for this preference other than having invested time
and effort into it? Is there in your opinion something fundamental that
makes it easier to describe objects this way? I can't see what it would
be. Maybe some examples can illustrate.

The huge problem is the speed and memory
requirements of CGAL. Can it be replaced by Carve in OpenSCAD?

The features of AngelCAD illustrates that the answer is that it probably
can. Using Carve in AngelCAD has a much smaller footprint in memory and
time spent, but I can't know for sure whether this is only because of
CGAL vs. Carve, or whether it reflects how the two libraries are being
used in the host applications (point to note: Carve is used only in
xcsg, AngelCAD is the scripting front end visible to users).

Carsten Arnholm

On 2019-04-26 23:59, nop head wrote: > Nice, but I have no problem with the declarative functional style of > OpenSCAD . I prefer that type of language when describing objects > rather than procedural. What is the reason for this preference other than having invested time and effort into it? Is there in your opinion something fundamental that makes it easier to describe objects this way? I can't see what it would be. Maybe some examples can illustrate. > The huge problem is the speed and memory > requirements of CGAL. Can it be replaced by Carve in OpenSCAD? The features of AngelCAD illustrates that the answer is that it probably can. Using Carve in AngelCAD has a much smaller footprint in memory and time spent, but I can't know for sure whether this is only because of CGAL vs. Carve, or whether it reflects how the two libraries are being used in the host applications (point to note: Carve is used only in xcsg, AngelCAD is the scripting front end visible to users). Carsten Arnholm
NH
nop head
Sat, Apr 27, 2019 8:13 AM

I find a declarative language more natural for describing static geometry.
Variables do not need to change because it is a description, not an
algorithm. It's like a make file or an HTML page, both are declarative
languages. Yes you can embed script in HTML but that is only necessary to
make it interactive or to read a database. A static page of text and
graphics is just a description of a tree of objects, like OpenSCAD.

Having variables that don't change makes code more readable and less error
prone. That is why moving everything to const in C++ is encouraged. And is
more like maths, which is appropriate for describing geometry. a = a + 1 is
nonsense in maths.

I don't struggle to code anything I need in OpenSCAD but avoiding CGAL as
much as possible is tedious and makes code less readable. If it was about
1000 times faster and used 1000 times less memory I could code directly in
3D rather than decomposing everything into unions of extruded 2D. And
rounding in 3D with minkowski would be practical.

On Sat, 27 Apr 2019 at 06:39, arnholm@arnholm.org wrote:

On 2019-04-26 23:59, nop head wrote:

Nice, but I have no problem with the declarative functional style of
OpenSCAD  . I prefer that type of language when describing objects
rather than procedural.

What is the reason for this preference other than having invested time
and effort into it? Is there in your opinion something fundamental that
makes it easier to describe objects this way? I can't see what it would
be. Maybe some examples can illustrate.

The huge problem is the speed and memory
requirements of CGAL. Can it be replaced by Carve in OpenSCAD?

The features of AngelCAD illustrates that the answer is that it probably
can. Using Carve in AngelCAD has a much smaller footprint in memory and
time spent, but I can't know for sure whether this is only because of
CGAL vs. Carve, or whether it reflects how the two libraries are being
used in the host applications (point to note: Carve is used only in
xcsg, AngelCAD is the scripting front end visible to users).

Carsten Arnholm


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

I find a declarative language more natural for describing static geometry. Variables do not need to change because it is a description, not an algorithm. It's like a make file or an HTML page, both are declarative languages. Yes you can embed script in HTML but that is only necessary to make it interactive or to read a database. A static page of text and graphics is just a description of a tree of objects, like OpenSCAD. Having variables that don't change makes code more readable and less error prone. That is why moving everything to const in C++ is encouraged. And is more like maths, which is appropriate for describing geometry. a = a + 1 is nonsense in maths. I don't struggle to code anything I need in OpenSCAD but avoiding CGAL as much as possible is tedious and makes code less readable. If it was about 1000 times faster and used 1000 times less memory I could code directly in 3D rather than decomposing everything into unions of extruded 2D. And rounding in 3D with minkowski would be practical. On Sat, 27 Apr 2019 at 06:39, <arnholm@arnholm.org> wrote: > On 2019-04-26 23:59, nop head wrote: > > Nice, but I have no problem with the declarative functional style of > > OpenSCAD . I prefer that type of language when describing objects > > rather than procedural. > > What is the reason for this preference other than having invested time > and effort into it? Is there in your opinion something fundamental that > makes it easier to describe objects this way? I can't see what it would > be. Maybe some examples can illustrate. > > > The huge problem is the speed and memory > > requirements of CGAL. Can it be replaced by Carve in OpenSCAD? > > The features of AngelCAD illustrates that the answer is that it probably > can. Using Carve in AngelCAD has a much smaller footprint in memory and > time spent, but I can't know for sure whether this is only because of > CGAL vs. Carve, or whether it reflects how the two libraries are being > used in the host applications (point to note: Carve is used only in > xcsg, AngelCAD is the scripting front end visible to users). > > Carsten Arnholm > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >
NH
nop head
Sat, Apr 27, 2019 8:27 AM

BTW, I don't think your pyramid has the correct dimensions, as Adrianv
eluded to, it is not trivial to place the spheres for a non rectangular or
irregular shape. However, I don't see why exact dimensions would be
important to such shapes.

On Sat, 27 Apr 2019 at 09:13, nop head nop.head@gmail.com wrote:

I find a declarative language more natural for describing static geometry.
Variables do not need to change because it is a description, not an
algorithm. It's like a make file or an HTML page, both are declarative
languages. Yes you can embed script in HTML but that is only necessary to
make it interactive or to read a database. A static page of text and
graphics is just a description of a tree of objects, like OpenSCAD.

Having variables that don't change makes code more readable and less error
prone. That is why moving everything to const in C++ is encouraged. And is
more like maths, which is appropriate for describing geometry. a = a + 1 is
nonsense in maths.

I don't struggle to code anything I need in OpenSCAD but avoiding CGAL as
much as possible is tedious and makes code less readable. If it was about
1000 times faster and used 1000 times less memory I could code directly in
3D rather than decomposing everything into unions of extruded 2D. And
rounding in 3D with minkowski would be practical.

On Sat, 27 Apr 2019 at 06:39, arnholm@arnholm.org wrote:

On 2019-04-26 23:59, nop head wrote:

Nice, but I have no problem with the declarative functional style of
OpenSCAD  . I prefer that type of language when describing objects
rather than procedural.

What is the reason for this preference other than having invested time
and effort into it? Is there in your opinion something fundamental that
makes it easier to describe objects this way? I can't see what it would
be. Maybe some examples can illustrate.

The huge problem is the speed and memory
requirements of CGAL. Can it be replaced by Carve in OpenSCAD?

The features of AngelCAD illustrates that the answer is that it probably
can. Using Carve in AngelCAD has a much smaller footprint in memory and
time spent, but I can't know for sure whether this is only because of
CGAL vs. Carve, or whether it reflects how the two libraries are being
used in the host applications (point to note: Carve is used only in
xcsg, AngelCAD is the scripting front end visible to users).

Carsten Arnholm


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

BTW, I don't think your pyramid has the correct dimensions, as Adrianv eluded to, it is not trivial to place the spheres for a non rectangular or irregular shape. However, I don't see why exact dimensions would be important to such shapes. On Sat, 27 Apr 2019 at 09:13, nop head <nop.head@gmail.com> wrote: > I find a declarative language more natural for describing static geometry. > Variables do not need to change because it is a description, not an > algorithm. It's like a make file or an HTML page, both are declarative > languages. Yes you can embed script in HTML but that is only necessary to > make it interactive or to read a database. A static page of text and > graphics is just a description of a tree of objects, like OpenSCAD. > > Having variables that don't change makes code more readable and less error > prone. That is why moving everything to const in C++ is encouraged. And is > more like maths, which is appropriate for describing geometry. a = a + 1 is > nonsense in maths. > > I don't struggle to code anything I need in OpenSCAD but avoiding CGAL as > much as possible is tedious and makes code less readable. If it was about > 1000 times faster and used 1000 times less memory I could code directly in > 3D rather than decomposing everything into unions of extruded 2D. And > rounding in 3D with minkowski would be practical. > > On Sat, 27 Apr 2019 at 06:39, <arnholm@arnholm.org> wrote: > >> On 2019-04-26 23:59, nop head wrote: >> > Nice, but I have no problem with the declarative functional style of >> > OpenSCAD . I prefer that type of language when describing objects >> > rather than procedural. >> >> What is the reason for this preference other than having invested time >> and effort into it? Is there in your opinion something fundamental that >> makes it easier to describe objects this way? I can't see what it would >> be. Maybe some examples can illustrate. >> >> > The huge problem is the speed and memory >> > requirements of CGAL. Can it be replaced by Carve in OpenSCAD? >> >> The features of AngelCAD illustrates that the answer is that it probably >> can. Using Carve in AngelCAD has a much smaller footprint in memory and >> time spent, but I can't know for sure whether this is only because of >> CGAL vs. Carve, or whether it reflects how the two libraries are being >> used in the host applications (point to note: Carve is used only in >> xcsg, AngelCAD is the scripting front end visible to users). >> >> Carsten Arnholm >> >> _______________________________________________ >> OpenSCAD mailing list >> Discuss@lists.openscad.org >> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >> >
CA
Carsten Arnholm
Sat, Apr 27, 2019 11:36 AM

On 27.04.2019 10:13, nop head wrote:

I find a declarative language more natural for describing static
geometry. Variables do not need to change because it is a description,
not an algorithm.

These are personal preferences, which is fine. In OpenSCAD users are
describing series of operations using parameters, i.e. describing what I
consider algorithms to generate models, they don't provide explicit
descriptions of the finished product. But this is semantics and not a
big deal in my book.

In some cases you have to use convoluted recursive procedures to build
datastructures in OpenSCAD, those are algorithms as well. Nothing wrong
with recursion, you can use it in AngelCAD to, but there it isn't the
only option on the table.

Having variables that don't change makes code more readable and less
error prone. That is why moving everything to const in C++ is
encouraged.

That is not really what constness in C++ (or AngelCAD) is about. What
makes readable code is debatable. For example, if you do this in OpenSCAD

radius = 1000;
radius = 500;
sphere(radius);

Is it supposed to be legal, and if so what is the correct result? Is the
result consistent with the statement that variables don't change?

If you do instead

radius = 500;
radius = 1000;
sphere(radius);

you get a different result, but considering the idea that the order of
things are not supposed to matter in the OpenSCAD language, the result
seems counterintuitive to me.

In this trivial case it is easy to spot that something is odd, but if it
is part of a larger section of code it is indeed error prone. With error
prone I mean it doesn't match the user expectation, given the language
rules of supposed constness and independence of sequence.

In summary, whatever the rules and syntax of a language, there are
plenty options to write unreadable and confusing code in any language
and OpenSCAD is no exception in this regard.

I don't struggle to code anything I need in OpenSCAD but avoiding CGAL
as much as possible is tedious and makes code less readable. If it was
about 1000 times faster and used 1000 times less memory I could code
directly in 3D rather than decomposing everything into unions of
extruded 2D. And rounding in 3D with minkowski would be practical.

This agrees with my first point earlier. Because of the slowness of CGAL
and/or how it is applied, you end up working around the core feature of
OpenSCAD.

Carsten Arnholm

On 27.04.2019 10:13, nop head wrote: > I find a declarative language more natural for describing static > geometry. Variables do not need to change because it is a description, > not an algorithm. These are personal preferences, which is fine. In OpenSCAD users are describing series of operations using parameters, i.e. describing what I consider algorithms to generate models, they don't provide explicit descriptions of the finished product. But this is semantics and not a big deal in my book. In some cases you have to use convoluted recursive procedures to build datastructures in OpenSCAD, those are algorithms as well. Nothing wrong with recursion, you can use it in AngelCAD to, but there it isn't the only option on the table. > Having variables that don't change makes code more readable and less > error prone. That is why moving everything to const in C++ is > encouraged. That is not really what constness in C++ (or AngelCAD) is about. What makes readable code is debatable. For example, if you do this in OpenSCAD radius = 1000; radius = 500; sphere(radius); Is it supposed to be legal, and if so what is the correct result? Is the result consistent with the statement that variables don't change? If you do instead radius = 500; radius = 1000; sphere(radius); you get a different result, but considering the idea that the order of things are not supposed to matter in the OpenSCAD language, the result seems counterintuitive to me. In this trivial case it is easy to spot that something is odd, but if it is part of a larger section of code it is indeed error prone. With error prone I mean it doesn't match the user expectation, given the language rules of supposed constness and independence of sequence. In summary, whatever the rules and syntax of a language, there are plenty options to write unreadable and confusing code in any language and OpenSCAD is no exception in this regard. > I don't struggle to code anything I need in OpenSCAD but avoiding CGAL > as much as possible is tedious and makes code less readable. If it was > about 1000 times faster and used 1000 times less memory I could code > directly in 3D rather than decomposing everything into unions of > extruded 2D. And rounding in 3D with minkowski would be practical. This agrees with my first point earlier. Because of the slowness of CGAL and/or how it is applied, you end up working around the core feature of OpenSCAD. Carsten Arnholm
CA
Carsten Arnholm
Sat, Apr 27, 2019 11:49 AM

On 27.04.2019 10:27, nop head wrote:

BTW, I don't think your pyramid has the correct dimensions, as Adrianv
eluded to, it is not trivial to place the spheres for a non rectangular
or irregular shape. However, I don't see why exact dimensions would be
important to such shapes.

It depends on what one considers 'correct'. Depending on the definition
of 'correct' for this case, I agree that placing the spheres can be
non-trivial.

I loosely designed it using the philosophy you explained earlier: "I
find, in generally, that only dimensions parallel to the axes matter in
my designs."

So, the pyramid was made to give reasonable dimensions on the main axes.
Of course, one could write more elaborate schemes giving different
results, that's the beauty of systems such as OpenSCAD or AngelCAD where
the user has endless possibilities to customize.

Carsten Arnholm

On 27.04.2019 10:27, nop head wrote: > BTW, I don't think your pyramid has the correct dimensions, as Adrianv > eluded to, it is not trivial to place the spheres for a non rectangular > or irregular shape. However, I don't see why exact dimensions would be > important to such shapes. It depends on what one considers 'correct'. Depending on the definition of 'correct' for this case, I agree that placing the spheres can be non-trivial. I loosely designed it using the philosophy you explained earlier: "I find, in generally, that only dimensions parallel to the axes matter in my designs." So, the pyramid was made to give reasonable dimensions on the main axes. Of course, one could write more elaborate schemes giving different results, that's the beauty of systems such as OpenSCAD or AngelCAD where the user has endless possibilities to customize. Carsten Arnholm
SD
Steven Dick
Sat, Apr 27, 2019 12:14 PM

(warning: rerant on the rant)

On Thu, Apr 25, 2019 at 3:45 PM TLC123 torleif.ceder@gmail.com 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?

I find all these things you mention intellectually interesting, and I
find minkowski interesting and useful.

However, at the end of the day, all I want to do is round off the
sharp corners on the outside (and inside corners!) of my model so I
don't have to file them off in post processing.

Minkowski drives me crazy because it is extremely slow, AND because I
have to change all the dimensions of my model to keep it dimensionally
accurate.  I just want to file off the corner, not add an extra layer
on the outside of my model.

All the OpenSCAD tutorials show doing this with hulls (work work for
me, model is concave), or lots of complex subtractive geometry (it was
hard for me to make this the first time, and you want me to do it
again backwards?), these are just ugly options.  Makes me want to go
back to solidworks where I could just select the edge and be done.

Are we making a cad program here or a pretty mathematical abstraction
with no practical application?

(warning: rerant on the rant) On Thu, Apr 25, 2019 at 3:45 PM TLC123 <torleif.ceder@gmail.com> 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? I find all these things you mention intellectually interesting, and I find minkowski interesting and useful. However, at the end of the day, all I want to do is round off the sharp corners on the outside (and inside corners!) of my model so I don't have to file them off in post processing. Minkowski drives me crazy because it is extremely slow, AND because I have to change all the dimensions of my model to keep it dimensionally accurate. I just want to file off the corner, not add an extra layer on the outside of my model. All the OpenSCAD tutorials show doing this with hulls (work work for me, model is concave), or lots of complex subtractive geometry (it was hard for me to make this the first time, and you want me to do it again backwards?), these are just ugly options. Makes me want to go back to solidworks where I could just select the edge and be done. Are we making a cad program here or a pretty mathematical abstraction with no practical application?
NH
nop head
Sat, Apr 27, 2019 12:32 PM

When you say this object is the difference between a cube and cylinder I
see that more of a description than an algorithm. The actual algorithm to
do that in user space is very difficult. It takes CGAL seconds to do it
when the cylinder is smooth.

Defining variables twice in the same scope now gives a warning, so if those
are removed it is left with its intended use of overriding defaults with
the command line, or overriding defaults supplied by a library.

Forcing variables to be constants means you know they represent one value
like they would in a maths text and they can't be accidentally changed like
they can in procedural languages and where you potentially have to scan the
entire program to know what the value might be. It means you need to make
up new names for new values and that makes code more readable. For example
in a procedural language you could have a box_width to represent the inside
dimensions of a box and later add the wall thickness and have it represent
the outside dimensions. Somebody actually asked how to do that on this
list. In a declarative language you are forced to give the inside and
outside dimensions different names and that is good.

Yes it is my personal preference but modern languages are moving towards
constant variables because it is safer and better for concurrency and
efficiency. As part of a C compiler all your expressions are rewritten to
have a new variable each time a variable is changed before it is then
allocated to registers and memory.

The CGAL slowness it definitely due to CGAL, not how it is used in
OpenSCAD. I think it uses infinite precision rationals and as soon as we
have rotations and circles most coordinates are irrational. It also doesn't
short circuit facets that are unchanged in a union or difference.

Adrianv likes to define shapes where the vertices before rounding are
specified, even though they don't exist in the final model. So the spheres
of the pyramid need to be placed tangential to all three faces of the
corner, so that the faces of the pyramid are in the same position they
would be if the corners where not rounded. This is what you would get with
Minkowski rounding of a pointed pyramid without any calculation if it ran
fast enough to erode inwards and then offset outwards, but that needs two
Minkowskis and a difference, or three Minkowskis and two differences for
concave corners and is impractically slow with any real world object. So
instead people have to subtract dimensions or place spheres and use hull,
and this is where it gets complicated. All because CGAL is very slow, not
because OpenSCAD can't easily round 3D shapes mathematically.

On Sat, 27 Apr 2019 at 12:36, Carsten Arnholm arnholm@arnholm.org wrote:

On 27.04.2019 10:13, nop head wrote:

I find a declarative language more natural for describing static
geometry. Variables do not need to change because it is a description,
not an algorithm.

These are personal preferences, which is fine. In OpenSCAD users are
describing series of operations using parameters, i.e. describing what I
consider algorithms to generate models, they don't provide explicit
descriptions of the finished product. But this is semantics and not a
big deal in my book.

In some cases you have to use convoluted recursive procedures to build
datastructures in OpenSCAD, those are algorithms as well. Nothing wrong
with recursion, you can use it in AngelCAD to, but there it isn't the
only option on the table.

Having variables that don't change makes code more readable and less
error prone. That is why moving everything to const in C++ is
encouraged.

That is not really what constness in C++ (or AngelCAD) is about. What
makes readable code is debatable. For example, if you do this in OpenSCAD

radius = 1000;
radius = 500;
sphere(radius);

Is it supposed to be legal, and if so what is the correct result? Is the
result consistent with the statement that variables don't change?

If you do instead

radius = 500;
radius = 1000;
sphere(radius);

you get a different result, but considering the idea that the order of
things are not supposed to matter in the OpenSCAD language, the result
seems counterintuitive to me.

In this trivial case it is easy to spot that something is odd, but if it
is part of a larger section of code it is indeed error prone. With error
prone I mean it doesn't match the user expectation, given the language
rules of supposed constness and independence of sequence.

In summary, whatever the rules and syntax of a language, there are
plenty options to write unreadable and confusing code in any language
and OpenSCAD is no exception in this regard.

I don't struggle to code anything I need in OpenSCAD but avoiding CGAL
as much as possible is tedious and makes code less readable. If it was
about 1000 times faster and used 1000 times less memory I could code
directly in 3D rather than decomposing everything into unions of
extruded 2D. And rounding in 3D with minkowski would be practical.

This agrees with my first point earlier. Because of the slowness of CGAL
and/or how it is applied, you end up working around the core feature of
OpenSCAD.

Carsten Arnholm


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

When you say this object is the difference between a cube and cylinder I see that more of a description than an algorithm. The actual algorithm to do that in user space is very difficult. It takes CGAL seconds to do it when the cylinder is smooth. Defining variables twice in the same scope now gives a warning, so if those are removed it is left with its intended use of overriding defaults with the command line, or overriding defaults supplied by a library. Forcing variables to be constants means you know they represent one value like they would in a maths text and they can't be accidentally changed like they can in procedural languages and where you potentially have to scan the entire program to know what the value might be. It means you need to make up new names for new values and that makes code more readable. For example in a procedural language you could have a box_width to represent the inside dimensions of a box and later add the wall thickness and have it represent the outside dimensions. Somebody actually asked how to do that on this list. In a declarative language you are forced to give the inside and outside dimensions different names and that is good. Yes it is my personal preference but modern languages are moving towards constant variables because it is safer and better for concurrency and efficiency. As part of a C compiler all your expressions are rewritten to have a new variable each time a variable is changed before it is then allocated to registers and memory. The CGAL slowness it definitely due to CGAL, not how it is used in OpenSCAD. I think it uses infinite precision rationals and as soon as we have rotations and circles most coordinates are irrational. It also doesn't short circuit facets that are unchanged in a union or difference. Adrianv likes to define shapes where the vertices before rounding are specified, even though they don't exist in the final model. So the spheres of the pyramid need to be placed tangential to all three faces of the corner, so that the faces of the pyramid are in the same position they would be if the corners where not rounded. This is what you would get with Minkowski rounding of a pointed pyramid without any calculation if it ran fast enough to erode inwards and then offset outwards, but that needs two Minkowskis and a difference, or three Minkowskis and two differences for concave corners and is impractically slow with any real world object. So instead people have to subtract dimensions or place spheres and use hull, and this is where it gets complicated. All because CGAL is very slow, not because OpenSCAD can't easily round 3D shapes mathematically. On Sat, 27 Apr 2019 at 12:36, Carsten Arnholm <arnholm@arnholm.org> wrote: > On 27.04.2019 10:13, nop head wrote: > > I find a declarative language more natural for describing static > > geometry. Variables do not need to change because it is a description, > > not an algorithm. > > These are personal preferences, which is fine. In OpenSCAD users are > describing series of operations using parameters, i.e. describing what I > consider algorithms to generate models, they don't provide explicit > descriptions of the finished product. But this is semantics and not a > big deal in my book. > > In some cases you have to use convoluted recursive procedures to build > datastructures in OpenSCAD, those are algorithms as well. Nothing wrong > with recursion, you can use it in AngelCAD to, but there it isn't the > only option on the table. > > > Having variables that don't change makes code more readable and less > > error prone. That is why moving everything to const in C++ is > > encouraged. > > That is not really what constness in C++ (or AngelCAD) is about. What > makes readable code is debatable. For example, if you do this in OpenSCAD > > radius = 1000; > radius = 500; > sphere(radius); > > Is it supposed to be legal, and if so what is the correct result? Is the > result consistent with the statement that variables don't change? > > If you do instead > > radius = 500; > radius = 1000; > sphere(radius); > > you get a different result, but considering the idea that the order of > things are not supposed to matter in the OpenSCAD language, the result > seems counterintuitive to me. > > In this trivial case it is easy to spot that something is odd, but if it > is part of a larger section of code it is indeed error prone. With error > prone I mean it doesn't match the user expectation, given the language > rules of supposed constness and independence of sequence. > > In summary, whatever the rules and syntax of a language, there are > plenty options to write unreadable and confusing code in any language > and OpenSCAD is no exception in this regard. > > > I don't struggle to code anything I need in OpenSCAD but avoiding CGAL > > as much as possible is tedious and makes code less readable. If it was > > about 1000 times faster and used 1000 times less memory I could code > > directly in 3D rather than decomposing everything into unions of > > extruded 2D. And rounding in 3D with minkowski would be practical. > > This agrees with my first point earlier. Because of the slowness of CGAL > and/or how it is applied, you end up working around the core feature of > OpenSCAD. > > Carsten Arnholm > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >
A
adrianv
Sat, Apr 27, 2019 1:33 PM

I don't know that the distinction between algorithm and description is very
clear cut.  Certainly saying an object is a difference of a cube and a
cylinder is an algorithm.  You have talked recently about how you redesigned
your OpenSCAD to be faster using 2d code with extrusions.  I am assuming
that the output didn't change.  So what did?  You changed to a different
algorithm for producing the same output.  An algorithm is, after all, a set
of steps for producing a result.

I think that if you are defining parameters to a model, like the length of
your model, or the width of a part, than immutable variables make perfect
sense.  But if you are trying to write a function to compute something
(perhaps the location for where to place those spheres for a hull operation)
then the immutable variables are a nuisance and they force one to write more
cryptic code.  You have to use recursion instead of a simple loop.  You have
to write chained ternary operators where every possibility is listed in one
statement, where a set of "if" assignment and reassignments would be more
clear.  You have to generate a bunch of extra variables, which might waste
memory if the variables are large.  Since you can't change "a" after
assigning it you instead make "atemp1" and "atemp2" and "atemp3" and then
combine them to make "a" at the end.

I just tried to do a rounding operation using 3 minkowski calls to see just
how impractical it is.  I think it might be OK in some situations to wait an
hour for the minkowski if it was done as a final rounding step and made the
model design dramatically easier.  (If my model takes 10 hours to print is
it so bad to have to wait an hour for this?)  However, I got

ERROR: CGAL error in CGAL_Nef_polyhedron3(): CGAL ERROR: assertion
violation! Expr: e->incident_sface() != SFace_const_handle() File:
/usr/include/CGAL/Nef_S2/SM_const_decorator.h Line: 326

It does seem that if minkowski were 1000 times faster it would really change
the practical options for how to do rounding.  You could round individual
components with 3 minkowski calls and union them together as desired.  As
noted above, it is frustrating with minkowski that it makes the model
bigger.  I have worked around this several times by designing zero
thickness models that are then expanded with minkowski to the final
thickness.  I've run minkowski and then done a difference to remove extra
thickness that was added.  It's a nuisance.  If minkowski is simpler when
one object is a sphere I wonder if a "round" primitive that rounds its
children could be significantly faster.

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

I don't know that the distinction between algorithm and description is very clear cut. Certainly saying an object is a difference of a cube and a cylinder is an algorithm. You have talked recently about how you redesigned your OpenSCAD to be faster using 2d code with extrusions. I am assuming that the output didn't change. So what did? You changed to a different algorithm for producing the same output. An algorithm is, after all, a set of steps for producing a result. I think that if you are defining parameters to a model, like the length of your model, or the width of a part, than immutable variables make perfect sense. But if you are trying to write a function to compute something (perhaps the location for where to place those spheres for a hull operation) then the immutable variables are a nuisance and they force one to write more cryptic code. You have to use recursion instead of a simple loop. You have to write chained ternary operators where every possibility is listed in one statement, where a set of "if" assignment and reassignments would be more clear. You have to generate a bunch of extra variables, which might waste memory if the variables are large. Since you can't change "a" after assigning it you instead make "atemp1" and "atemp2" and "atemp3" and then combine them to make "a" at the end. I just tried to do a rounding operation using 3 minkowski calls to see just how impractical it is. I think it might be OK in some situations to wait an hour for the minkowski if it was done as a final rounding step and made the model design dramatically easier. (If my model takes 10 hours to print is it so bad to have to wait an hour for this?) However, I got ERROR: CGAL error in CGAL_Nef_polyhedron3(): CGAL ERROR: assertion violation! Expr: e->incident_sface() != SFace_const_handle() File: /usr/include/CGAL/Nef_S2/SM_const_decorator.h Line: 326 It does seem that if minkowski were 1000 times faster it would really change the practical options for how to do rounding. You could round individual components with 3 minkowski calls and union them together as desired. As noted above, it is frustrating with minkowski that it makes the model bigger. I have worked around this several times by designing zero thickness models that are then expanded with minkowski to the final thickness. I've run minkowski and then done a difference to remove extra thickness that was added. It's a nuisance. If minkowski is simpler when one object is a sphere I wonder if a "round" primitive that rounds its children could be significantly faster. -- Sent from: http://forum.openscad.org/
RW
Rogier Wolff
Sat, Apr 27, 2019 1:44 PM

On Sat, Apr 27, 2019 at 09:13:22AM +0100, nop head wrote:

And is more like maths, which is appropriate for describing
geometry. a = a + 1 is nonsense in maths.

It's a bit of a notation issue.

That "a = a + 1" looks a bit like an (maths) equation, but it is not.

In languages like bash and pascal you can see the difference:

the left "a" is a reference to the memory location we call A. The
right one is a reference to the value in that location. In shell programs
the latter is "$a" and the first is "a".

In pascal the assignment is written als := instead of =, to make the
distinction from the = in maths.

But in fact even when you don't write it down that way, these
distinctions happen in (almost) all languages even when not explicitly
evident from the notation.

For example: If in C you write "a+1 = a" which is mathematically the
same as a=a+1, you get the complaint: "not an lvalue" about the
assginment target that is now "a+1".

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 Sat, Apr 27, 2019 at 09:13:22AM +0100, nop head wrote: > And is more like maths, which is appropriate for describing > geometry. a = a + 1 is nonsense in maths. It's a bit of a notation issue. That "a = a + 1" looks a bit like an (maths) equation, but it is not. In languages like bash and pascal you can see the difference: the left "a" is a reference to the memory location we call A. The right one is a reference to the value in that location. In shell programs the latter is "$a" and the first is "a". In pascal the assignment is written als := instead of =, to make the distinction from the = in maths. But in fact even when you don't write it down that way, these distinctions happen in (almost) all languages even when not explicitly evident from the notation. For example: If in C you write "a+1 = a" which is mathematically the same as a=a+1, you get the complaint: "not an lvalue" about the assginment target that is now "a+1". 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
Sat, Apr 27, 2019 6:04 PM

Certainly saying an object is a difference of a cube and a cylinder is an
algorithm.

I don't think we will ever agree. I see that as a description of geometry,
rather than a procedure. Openscad is free to render the scene in any order
it chooses. Wikipedia says "In computer science
https://en.wikipedia.org/wiki/Computer_science, declarative programming is
a programming paradigm https://en.wikipedia.org/wiki/Programming_paradigm—a
style of building the structure and elements of computer programs—that
expresses the logic of a computation
https://en.wikipedia.org/wiki/Computation without describing its control
flow https://en.wikipedia.org/wiki/Control_flow."

I have been a professional programmer for about 30 years and mostly wrote
procedural code. I also designed my own declarative language for describing
things like build systems, OS configurations, or state charts and rendering
make files or C++, etc. That also had variables that only have one value,
although they could have defaults that were overridden, so a bit like
OpenSCAD in that respect.  It also built a tree of objects like OpenSCAD
does and then rendered them. The difference being it produced text rather
than graphics and didn't use C syntax. So OpenSCAD works the way I think.

But if you are trying to write a function to compute something (perhaps the

location for where to place those spheres for a hull operation) then the
immutable variables are a nuisance and they force one to write more cryptic
code.

I don't see that at all. I have very few functions that need mutable
variables and I don't find recursion cryptic. It is more like a
mathematical description and a loop is more like a procedure.

You have to write chained ternary operators where every possibility is

listed in one statement, where a set of "if" assignment and reassignments
would be more clear.

The ternary statement can be formatted almost the same as if else. It is
only convention that if else is on multiple lines and ? : is on one line.

You have to generate a bunch of extra variables, which might waste memory

if the variables are large.  Since you can't change "a" after assigning it
you instead make "atemp1" and "atemp2" and "atemp3" and then combine them
to make "a" at the end.

The memory used by the script is negligible compared to CGAL. I haven't got
anything with cryptic names like atemp1-3. If I break up expressions I give
them meaningful names but since expressions can occupy multiple lines I
don't split them up unless there are  sub-expressions I can factor out to
avoid repetition or give a meaningful name to to make the code clearer.

I have been experimenting with Minkowski rounding of this simple shape.

[image: image.png]

To preserve the original dimensions I use my version of sphere with poles
and equator and I inflate, erode by twice as much and inflate again to
round both the concave and convex corners. This took 45 minutes with $fn =
24. Curiously it stopped LibraOffice starting until it finished rendering.
I think time increases exponentially with $fn.

4 6
8 39
12 120
16 500
20 814
24 2745

[image: image.png]

Minkowski of a convex shape should be as fast as hull because all it needs
to do is take the hull of the the vertices of one shape offset by each of
the vertices of the other shape. For a concave shape it needs to decompose
it into convex shapes, Minkowski each in turn and union the resulting
hulls. The trouble is even union with lots of vertices is very slow with
CGAL. And when you erode inwards the shape is always going to be concave.

On Sat, 27 Apr 2019 at 14:44, Rogier Wolff R.E.Wolff@bitwizard.nl wrote:

On Sat, Apr 27, 2019 at 09:13:22AM +0100, nop head wrote:

And is more like maths, which is appropriate for describing
geometry. a = a + 1 is nonsense in maths.

It's a bit of a notation issue.

That "a = a + 1" looks a bit like an (maths) equation, but it is not.

In languages like bash and pascal you can see the difference:

the left "a" is a reference to the memory location we call A. The
right one is a reference to the value in that location. In shell programs
the latter is "$a" and the first is "a".

In pascal the assignment is written als := instead of =, to make the
distinction from the = in maths.

But in fact even when you don't write it down that way, these
distinctions happen in (almost) all languages even when not explicitly
evident from the notation.

For example: If in C you write "a+1 = a" which is mathematically the
same as a=a+1, you get the complaint: "not an lvalue" about the
assginment target that is now "a+1".

     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

> > Certainly saying an object is a difference of a cube and a cylinder is an > algorithm. I don't think we will ever agree. I see that as a description of geometry, rather than a procedure. Openscad is free to render the scene in any order it chooses. Wikipedia says "In computer science <https://en.wikipedia.org/wiki/Computer_science>, *declarative programming* is a programming paradigm <https://en.wikipedia.org/wiki/Programming_paradigm>—a style of building the structure and elements of computer programs—that expresses the logic of a computation <https://en.wikipedia.org/wiki/Computation> without describing its control flow <https://en.wikipedia.org/wiki/Control_flow>." I have been a professional programmer for about 30 years and mostly wrote procedural code. I also designed my own declarative language for describing things like build systems, OS configurations, or state charts and rendering make files or C++, etc. That also had variables that only have one value, although they could have defaults that were overridden, so a bit like OpenSCAD in that respect. It also built a tree of objects like OpenSCAD does and then rendered them. The difference being it produced text rather than graphics and didn't use C syntax. So OpenSCAD works the way I think. But if you are trying to write a function to compute something (perhaps the > location for where to place those spheres for a hull operation) then the > immutable variables are a nuisance and they force one to write more cryptic > code. I don't see that at all. I have very few functions that need mutable variables and I don't find recursion cryptic. It is more like a mathematical description and a loop is more like a procedure. You have to write chained ternary operators where every possibility is > listed in one statement, where a set of "if" assignment and reassignments > would be more clear. The ternary statement can be formatted almost the same as if else. It is only convention that if else is on multiple lines and ? : is on one line. You have to generate a bunch of extra variables, which might waste memory > if the variables are large. Since you can't change "a" after assigning it > you instead make "atemp1" and "atemp2" and "atemp3" and then combine them > to make "a" at the end. The memory used by the script is negligible compared to CGAL. I haven't got anything with cryptic names like atemp1-3. If I break up expressions I give them meaningful names but since expressions can occupy multiple lines I don't split them up unless there are sub-expressions I can factor out to avoid repetition or give a meaningful name to to make the code clearer. I have been experimenting with Minkowski rounding of this simple shape. [image: image.png] To preserve the original dimensions I use my version of sphere with poles and equator and I inflate, erode by twice as much and inflate again to round both the concave and convex corners. This took 45 minutes with $fn = 24. Curiously it stopped LibraOffice starting until it finished rendering. I think time increases exponentially with $fn. 4 6 8 39 12 120 16 500 20 814 24 2745 [image: image.png] Minkowski of a convex shape should be as fast as hull because all it needs to do is take the hull of the the vertices of one shape offset by each of the vertices of the other shape. For a concave shape it needs to decompose it into convex shapes, Minkowski each in turn and union the resulting hulls. The trouble is even union with lots of vertices is very slow with CGAL. And when you erode inwards the shape is always going to be concave. On Sat, 27 Apr 2019 at 14:44, Rogier Wolff <R.E.Wolff@bitwizard.nl> wrote: > On Sat, Apr 27, 2019 at 09:13:22AM +0100, nop head wrote: > > > And is more like maths, which is appropriate for describing > > geometry. a = a + 1 is nonsense in maths. > > It's a bit of a notation issue. > > That "a = a + 1" looks a bit like an (maths) equation, but it is not. > > In languages like bash and pascal you can see the difference: > > the left "a" is a reference to the memory location we call A. The > right one is a reference to the value in that location. In shell programs > the latter is "$a" and the first is "a". > > In pascal the assignment is written als := instead of =, to make the > distinction from the = in maths. > > But in fact even when you don't write it down that way, these > distinctions happen in (almost) all languages even when not explicitly > evident from the notation. > > For example: If in C you write "a+1 = a" which is mathematically the > same as a=a+1, you get the complaint: "not an lvalue" about the > assginment target that is now "a+1". > > 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 >
L
lar3ry@sasktel.net
Sat, Apr 27, 2019 9:09 PM

On 27 Apr 2019 at 9:13, nop head wrote:
a = a + 1 is nonsense in maths.

And I am extremely grateful that programming <> maths.
It's shorthand for let a become equal to a+1. Would hate to have to write that out all the time.

--
Magic trumps science for most people,
and wishful thinking drives a lot of decision-making.
- Joe Haldeman

On 27 Apr 2019 at 9:13, nop head wrote: a = a + 1 is nonsense in maths. And I am extremely grateful that programming <> maths. It's shorthand for let a become equal to a+1. Would hate to have to write that out all the time. -- Magic trumps science for most people, and wishful thinking drives a lot of decision-making. - Joe Haldeman
NH
nop head
Sat, Apr 27, 2019 9:21 PM

It isn't the notation it the fact that in maths you don't let x mean one
thing and then on the next line make it mean some else. x means the same
thing throughout the text. You can have y = x + 1, but not x = x + 1. You
can have sigma with subscripts that make n range from 1 to something but
that is like a for loop, which OpenScad has. There are lots of programming
languages where you you can't mutate variables. It seems that most people
on this list just don't get it.

On Sat, 27 Apr 2019 at 22:10, lar3ry@sasktel.net wrote:

On 27 Apr 2019 at 9:13, nop head wrote:
a = a + 1 is nonsense in maths.

And I am extremely grateful that programming <> maths.
It's shorthand for let a become equal to a+1. Would hate to have to write
that out all the time.

--
Magic trumps science for most people,
and wishful thinking drives a lot of decision-making.
- Joe Haldeman


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

It isn't the notation it the fact that in maths you don't let x mean one thing and then on the next line make it mean some else. x means the same thing throughout the text. You can have y = x + 1, but not x = x + 1. You can have sigma with subscripts that make n range from 1 to something but that is like a for loop, which OpenScad has. There are lots of programming languages where you you can't mutate variables. It seems that most people on this list just don't get it. On Sat, 27 Apr 2019 at 22:10, <lar3ry@sasktel.net> wrote: > On 27 Apr 2019 at 9:13, nop head wrote: > a = a + 1 is nonsense in maths. > > And I am extremely grateful that programming <> maths. > It's shorthand for let a become equal to a+1. Would hate to have to write > that out all the time. > > > > -- > Magic trumps science for most people, > and wishful thinking drives a lot of decision-making. > - Joe Haldeman > > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >
A
adrianv
Sat, Apr 27, 2019 10:51 PM

nophead wrote

Certainly saying an object is a difference of a cube and a cylinder is an
algorithm.

I don't think we will ever agree. I see that as a description of geometry,
rather than a procedure. Openscad is free to render the scene in any order
it chooses. Wikipedia says "In computer science
<https://en.wikipedia.org/wiki/Computer_science>, declarative
programming
is
a programming paradigm
<https://en.wikipedia.org/wiki/Programming_paradigm>—a
style of building the structure and elements of computer programs—that
expresses the logic of a computation
<https://en.wikipedia.org/wiki/Computation> without describing its
control
flow <https://en.wikipedia.org/wiki/Control_flow>."

That seems to describe OpenSCAD.  But what does that have to do with whether
OpenSCAD files are algorithms?  The word algorithm is pretty broad, and it
seems pretty clear that declarative programming is still giving algorithms.

But if you are trying to write a function to compute something (perhaps
the

location for where to place those spheres for a hull operation) then the
immutable variables are a nuisance and they force one to write more
cryptic
code.

I don't see that at all. I have very few functions that need mutable
variables and I don't find recursion cryptic. It is more like a
mathematical description and a loop is more like a procedure.

Writing code into the required form to get tail-recursion in my experience
tends to increase code complexity and make the code more cryptic.  I'm not
saying recursion is inherently cryptic, but I think a loop is generally
easier to understand.  What if I have an algorithm that requires more than
one pass over the data to produce its output?  That may not have an obvious
solution through simple recursion.

You have to write chained ternary operators where every possibility is

listed in one statement, where a set of "if" assignment and reassignments
would be more clear.

The ternary statement can be formatted almost the same as if else. It is
only convention that if else is on multiple lines and ? : is on one line.

The problem is not the ternary operator itself---that's just notation---but
the fact that you have to assign the variable with a single chain of
ternary operators.  I ran into a complication recently where I was trying to
determine the parameters to construct and object from user inputs.  I needed
to compute parameters h and r from the user inputs, but some user inputs
make it natural to compute r first and compute h from r and others have the
reverse characteristic.  In a language where I can have multiple assignments
and if statements I could have divided up the cases and computed each one in
the most natural way.  Instead I had to derive more complex formulas for
certain cases so that I could compute one of the variables first from any
user input.

This is the sort of situation I'm talking about.

I've been thinking about a routine to make a box with rounded edges and
interior corners and the major challenge is that when I shrink the boundary,
the number of vertices may change, which makes it hard to assign polyhedron
faces.  I think this would be much easier to track and handle if variables
could change.

You have to generate a bunch of extra variables, which might waste memory
if the variables are large.  Since you can't change "a" after assigning
it
you instead make "atemp1" and "atemp2" and "atemp3" and then combine them
to make "a" at the end.

The memory used by the script is negligible compared to CGAL. I haven't
got
anything with cryptic names like atemp1-3. If I break up expressions I
give
them meaningful names but since expressions can occupy multiple lines I
don't split them up unless there are  sub-expressions I can factor out to
avoid repetition or give a meaningful name to to make the code clearer.

So in the case where if a is set then r=f(a), h=g(r,a) and if b is set then
h=F(b), r=G(h,b), how would you write this?  I mean, I suppose you can do
this

r_or_h = !is_undef(a) ? f(a) : F(b),
r = !is_undef(a) ? r_or_h : G(r_or_h,b),
h = !is_undef(a) ? F(r_or_h,a) : r_or_h;

Is there some alternative, because I think that's effective at obscuring a
simple underlying relationship.

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

nophead wrote >> >> Certainly saying an object is a difference of a cube and a cylinder is an >> algorithm. > > I don't think we will ever agree. I see that as a description of geometry, > rather than a procedure. Openscad is free to render the scene in any order > it chooses. Wikipedia says "In computer science > &lt;https://en.wikipedia.org/wiki/Computer_science&gt;, *declarative > programming* is > a programming paradigm > &lt;https://en.wikipedia.org/wiki/Programming_paradigm&gt;—a > style of building the structure and elements of computer programs—that > expresses the logic of a computation > &lt;https://en.wikipedia.org/wiki/Computation&gt; without describing its > control > flow &lt;https://en.wikipedia.org/wiki/Control_flow&gt;." That seems to describe OpenSCAD. But what does that have to do with whether OpenSCAD files are algorithms? The word algorithm is pretty broad, and it seems pretty clear that declarative programming is still giving algorithms. > But if you are trying to write a function to compute something (perhaps > the >> location for where to place those spheres for a hull operation) then the >> immutable variables are a nuisance and they force one to write more >> cryptic >> code. > > > I don't see that at all. I have very few functions that need mutable > variables and I don't find recursion cryptic. It is more like a > mathematical description and a loop is more like a procedure. Writing code into the required form to get tail-recursion in my experience tends to increase code complexity and make the code more cryptic. I'm not saying recursion is inherently cryptic, but I think a loop is generally easier to understand. What if I have an algorithm that requires more than one pass over the data to produce its output? That may not have an obvious solution through simple recursion. > You have to write chained ternary operators where every possibility is >> listed in one statement, where a set of "if" assignment and reassignments >> would be more clear. > > > The ternary statement can be formatted almost the same as if else. It is > only convention that if else is on multiple lines and ? : is on one line. The problem is not the ternary operator itself---that's just notation---but the fact that you have to assign the variable with a *single* chain of ternary operators. I ran into a complication recently where I was trying to determine the parameters to construct and object from user inputs. I needed to compute parameters h and r from the user inputs, but some user inputs make it natural to compute r first and compute h from r and others have the reverse characteristic. In a language where I can have multiple assignments and if statements I could have divided up the cases and computed each one in the most natural way. Instead I had to derive more complex formulas for certain cases so that I could compute one of the variables first from any user input. This is the sort of situation I'm talking about. I've been thinking about a routine to make a box with rounded edges and interior corners and the major challenge is that when I shrink the boundary, the number of vertices may change, which makes it hard to assign polyhedron faces. I think this would be much easier to track and handle if variables could change. >> You have to generate a bunch of extra variables, which might waste memory >> if the variables are large. Since you can't change "a" after assigning >> it >> you instead make "atemp1" and "atemp2" and "atemp3" and then combine them >> to make "a" at the end. > > > The memory used by the script is negligible compared to CGAL. I haven't > got > anything with cryptic names like atemp1-3. If I break up expressions I > give > them meaningful names but since expressions can occupy multiple lines I > don't split them up unless there are sub-expressions I can factor out to > avoid repetition or give a meaningful name to to make the code clearer. So in the case where if a is set then r=f(a), h=g(r,a) and if b is set then h=F(b), r=G(h,b), how would you write this? I mean, I suppose you can do this r_or_h = !is_undef(a) ? f(a) : F(b), r = !is_undef(a) ? r_or_h : G(r_or_h,b), h = !is_undef(a) ? F(r_or_h,a) : r_or_h; Is there some alternative, because I think that's effective at obscuring a simple underlying relationship. -- Sent from: http://forum.openscad.org/
L
lar3ry@sasktel.net
Sun, Apr 28, 2019 5:09 AM

On 27 Apr 2019 at 22:21, nop head wrote:

It isn't the notation it the fact that in maths you don't let x mean one thing and then on the next line
make it mean some else.

Again reinforcing my happiness in using a program instead of math.

There are lots of programming languages where you
can't mutate variables.

And yet they are still called variables. Fascinating.

--
Magic trumps science for most people,
and wishful thinking drives a lot of decision-making.
- Joe Haldeman

On 27 Apr 2019 at 22:21, nop head wrote: > It isn't the notation it the fact that in maths you don't let x mean one thing and then on the next line > make it mean some else. Again reinforcing my happiness in using a program instead of math. > There are lots of programming languages where you > can't mutate variables. And yet they are still called variables. Fascinating. -- Magic trumps science for most people, and wishful thinking drives a lot of decision-making. - Joe Haldeman
NH
nop head
Sun, Apr 28, 2019 8:05 AM

Yes they are still called variable because they can take any value at run
time but can only be assigned once. See
https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html

This is how I would code Adrian's problem, although I haven't needed such a
construct myself yet.

r_h = is_undef(a) ? let(h = F(b), r = G(h, b)) [r, h]
: let(r = f(a), h = g(r, a)) [r, h];

r = r_h[0];
h = r_h[1];

Or a slightly more compact version but I think less readable:

r_h = is_undef(a) ? let(h = F(b)) [G(h, b), h]
: let(r = f(a)) [r, g(r, a)];

r = r_h[0];
h = r_h[1];

On Sun, 28 Apr 2019 at 06:09, lar3ry@sasktel.net wrote:

On 27 Apr 2019 at 22:21, nop head wrote:

It isn't the notation it the fact that in maths you don't let x mean one

thing and then on the next line

make it mean some else.

Again reinforcing my happiness in using a program instead of math.

There are lots of programming languages where you
can't mutate variables.

And yet they are still called variables. Fascinating.

--
Magic trumps science for most people,
and wishful thinking drives a lot of decision-making.
- Joe Haldeman


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

Yes they are still called variable because they can take any value at run time but can only be assigned once. See https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html This is how I would code Adrian's problem, although I haven't needed such a construct myself yet. r_h = is_undef(a) ? let(h = F(b), r = G(h, b)) [r, h] : let(r = f(a), h = g(r, a)) [r, h]; r = r_h[0]; h = r_h[1]; Or a slightly more compact version but I think less readable: r_h = is_undef(a) ? let(h = F(b)) [G(h, b), h] : let(r = f(a)) [r, g(r, a)]; r = r_h[0]; h = r_h[1]; On Sun, 28 Apr 2019 at 06:09, <lar3ry@sasktel.net> wrote: > On 27 Apr 2019 at 22:21, nop head wrote: > > It isn't the notation it the fact that in maths you don't let x mean one > thing and then on the next line > > make it mean some else. > > Again reinforcing my happiness in using a program instead of math. > > > There are lots of programming languages where you > > can't mutate variables. > > And yet they are still called variables. Fascinating. > > -- > Magic trumps science for most people, > and wishful thinking drives a lot of decision-making. > - Joe Haldeman > > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >
A
adrianv
Fri, May 3, 2019 9:58 AM

I noticed that (at least) two people felt like the coding problem I noted was
sufficiently interesting that they tried to implement it.  There is no other
language I know where this would even be an interesting problem---it would
just be trivial.  The fact that more than one person thought my coding
problem was a sufficient challenge that it was worth doing I think
demonstrates the issue with the language.

But that's not why I'm posting.  I'm posting because I finally completed my
rounded_extrude module which made this possible:

box = [[0,0], [0,50], [255,50], [255,0]];
rbox = roundcorners(box, curve="smooth", type="cut", all=4);

difference(){
rounded_extrude(rbox, height=50, r1=2, r2=1, steps = 22, edge1="teardrop",
self_intersection=false);
translate([0,0,2])
rounded_extrude(pathoffset(rbox, r=-2, closed=true), height=48, r1=4,
r2=-1,steps=22,extra2=1,self_intersection=false);
}

So I have a rounded box with a teardrop edge at the base, a rounded top
edge, and a more rounded interior bottom edge.

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

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

I noticed that (at least) two people felt like the coding problem I noted was sufficiently interesting that they tried to implement it. There is no other language I know where this would even be an interesting problem---it would just be trivial. The fact that more than one person thought my coding problem was a sufficient challenge that it was worth doing I think demonstrates the issue with the language. But that's not why I'm posting. I'm posting because I finally completed my rounded_extrude module which made this possible: box = [[0,0], [0,50], [255,50], [255,0]]; rbox = roundcorners(box, curve="smooth", type="cut", all=4); difference(){ rounded_extrude(rbox, height=50, r1=2, r2=1, steps = 22, edge1="teardrop", self_intersection=false); translate([0,0,2]) rounded_extrude(pathoffset(rbox, r=-2, closed=true), height=48, r1=4, r2=-1,steps=22,extra2=1,self_intersection=false); } So I have a rounded box with a teardrop edge at the base, a rounded top edge, and a more rounded interior bottom edge. <http://forum.openscad.org/file/t2477/fbox1.png> -- Sent from: http://forum.openscad.org/
A
arnholm@arnholm.org
Fri, May 3, 2019 11:04 AM

On 2019-05-03 11:58, adrianv wrote:

So I have a rounded box with a teardrop edge at the base, a rounded top
edge, and a more rounded interior bottom edge.

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

That's very, very nice (and clever)! But what is a "teardrop edge"
precisely?

Carsten Arnholm

On 2019-05-03 11:58, adrianv wrote: > So I have a rounded box with a teardrop edge at the base, a rounded top > edge, and a more rounded interior bottom edge. > > <http://forum.openscad.org/file/t2477/fbox1.png> That's very, very nice (and clever)! But what is a "teardrop edge" precisely? Carsten Arnholm
NH
nop head
Fri, May 3, 2019 11:10 AM

I use an inverted truncated rotate_extruded teardrop on the bottom edges
of my rounded objects so they don't need support when printing. I assume
that is what a "teardrop edge" is.

[image: handle.png]

On Fri, 3 May 2019 at 12:05, arnholm@arnholm.org wrote:

On 2019-05-03 11:58, adrianv wrote:

So I have a rounded box with a teardrop edge at the base, a rounded top
edge, and a more rounded interior bottom edge.

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

That's very, very nice (and clever)! But what is a "teardrop edge"
precisely?

Carsten Arnholm


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

I use an inverted truncated rotate_extruded teardrop on the bottom edges of my rounded objects so they don't need support when printing. I assume that is what a "teardrop edge" is. [image: handle.png] On Fri, 3 May 2019 at 12:05, <arnholm@arnholm.org> wrote: > On 2019-05-03 11:58, adrianv wrote: > > So I have a rounded box with a teardrop edge at the base, a rounded top > > edge, and a more rounded interior bottom edge. > > > > <http://forum.openscad.org/file/t2477/fbox1.png> > > That's very, very nice (and clever)! But what is a "teardrop edge" > precisely? > > Carsten Arnholm > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >
WA
William Adams
Fri, May 3, 2019 1:53 PM

I've been working through this sort of thing myself, and have been working
up a series of basic modules which do rounded edged (and optionally
bottomed) pockets so as to model projects for a hobby CNC.

The problem of course is working up a reasonable definition of the shapes
in terms of parameters --- I believe the field which covers this sort of
thing is topology?

Does anyone know of any good texts on this which might be approachable to a
layman?

William

On Fri, May 3, 2019 at 7:11 AM nop head nop.head@gmail.com wrote:

I use an inverted truncated rotate_extruded teardrop on the bottom edges
of my rounded objects so they don't need support when printing. I assume
that is what a "teardrop edge" is.

[image: handle.png]

On Fri, 3 May 2019 at 12:05, arnholm@arnholm.org wrote:

On 2019-05-03 11:58, adrianv wrote:

So I have a rounded box with a teardrop edge at the base, a rounded top
edge, and a more rounded interior bottom edge.

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

That's very, very nice (and clever)! But what is a "teardrop edge"
precisely?

Carsten Arnholm


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

I've been working through this sort of thing myself, and have been working up a series of basic modules which do rounded edged (and optionally bottomed) pockets so as to model projects for a hobby CNC. The problem of course is working up a reasonable definition of the shapes in terms of parameters --- I believe the field which covers this sort of thing is topology? Does anyone know of any good texts on this which might be approachable to a layman? William On Fri, May 3, 2019 at 7:11 AM nop head <nop.head@gmail.com> wrote: > I use an inverted truncated rotate_extruded teardrop on the bottom edges > of my rounded objects so they don't need support when printing. I assume > that is what a "teardrop edge" is. > > [image: handle.png] > > On Fri, 3 May 2019 at 12:05, <arnholm@arnholm.org> wrote: > >> On 2019-05-03 11:58, adrianv wrote: >> > So I have a rounded box with a teardrop edge at the base, a rounded top >> > edge, and a more rounded interior bottom edge. >> > >> > <http://forum.openscad.org/file/t2477/fbox1.png> >> >> That's very, very nice (and clever)! But what is a "teardrop edge" >> precisely? >> >> Carsten Arnholm >> >> _______________________________________________ >> 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 >
NH
nop head
Fri, May 3, 2019 2:42 PM

I don't think topology is what you mean. For example a doughnut and a
teacup with a handle are topologically the same.

On Fri, 3 May 2019 at 14:54, William Adams will.adams@frycomm.com wrote:

I've been working through this sort of thing myself, and have been working
up a series of basic modules which do rounded edged (and optionally
bottomed) pockets so as to model projects for a hobby CNC.

The problem of course is working up a reasonable definition of the shapes
in terms of parameters --- I believe the field which covers this sort of
thing is topology?

Does anyone know of any good texts on this which might be approachable to
a layman?

William

On Fri, May 3, 2019 at 7:11 AM nop head nop.head@gmail.com wrote:

I use an inverted truncated rotate_extruded teardrop on the bottom edges
of my rounded objects so they don't need support when printing. I assume
that is what a "teardrop edge" is.

[image: handle.png]

On Fri, 3 May 2019 at 12:05, arnholm@arnholm.org wrote:

On 2019-05-03 11:58, adrianv wrote:

So I have a rounded box with a teardrop edge at the base, a rounded top
edge, and a more rounded interior bottom edge.

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

That's very, very nice (and clever)! But what is a "teardrop edge"
precisely?

Carsten Arnholm


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

I don't think topology is what you mean. For example a doughnut and a teacup with a handle are topologically the same. On Fri, 3 May 2019 at 14:54, William Adams <will.adams@frycomm.com> wrote: > I've been working through this sort of thing myself, and have been working > up a series of basic modules which do rounded edged (and optionally > bottomed) pockets so as to model projects for a hobby CNC. > > The problem of course is working up a reasonable definition of the shapes > in terms of parameters --- I believe the field which covers this sort of > thing is topology? > > Does anyone know of any good texts on this which might be approachable to > a layman? > > William > > > On Fri, May 3, 2019 at 7:11 AM nop head <nop.head@gmail.com> wrote: > >> I use an inverted truncated rotate_extruded teardrop on the bottom edges >> of my rounded objects so they don't need support when printing. I assume >> that is what a "teardrop edge" is. >> >> [image: handle.png] >> >> On Fri, 3 May 2019 at 12:05, <arnholm@arnholm.org> wrote: >> >>> On 2019-05-03 11:58, adrianv wrote: >>> > So I have a rounded box with a teardrop edge at the base, a rounded top >>> > edge, and a more rounded interior bottom edge. >>> > >>> > <http://forum.openscad.org/file/t2477/fbox1.png> >>> >>> That's very, very nice (and clever)! But what is a "teardrop edge" >>> precisely? >>> >>> Carsten Arnholm >>> >>> _______________________________________________ >>> 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 >
WA
William Adams
Fri, May 3, 2019 3:03 PM

Okay. Discussion of a list of two-dimensional shapes,
mathematical/programmatic techniques for dividing shapes into regions, and
the possible shapes which one can use in such deconstruction.

Suggested text/terminology, esp. a book suited to a layman.

Eventually the project may work up to 3 dimensional shapes, but for now,
trying to limit it to stacks of two-dimensional shapes cut into a
three-dimensional stock.

William

On Fri, May 3, 2019 at 10:43 AM nop head nop.head@gmail.com wrote:

I don't think topology is what you mean. For example a doughnut and a
teacup with a handle are topologically the same.

On Fri, 3 May 2019 at 14:54, William Adams will.adams@frycomm.com wrote:

I've been working through this sort of thing myself, and have been
working up a series of basic modules which do rounded edged (and optionally
bottomed) pockets so as to model projects for a hobby CNC.

The problem of course is working up a reasonable definition of the shapes
in terms of parameters --- I believe the field which covers this sort of
thing is topology?

Does anyone know of any good texts on this which might be approachable to
a layman?

William

On Fri, May 3, 2019 at 7:11 AM nop head nop.head@gmail.com wrote:

I use an inverted truncated rotate_extruded teardrop on the bottom
edges of my rounded objects so they don't need support when printing. I
assume that is what a "teardrop edge" is.

[image: handle.png]

On Fri, 3 May 2019 at 12:05, arnholm@arnholm.org wrote:

On 2019-05-03 11:58, adrianv wrote:

So I have a rounded box with a teardrop edge at the base, a rounded

top

edge, and a more rounded interior bottom edge.

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

That's very, very nice (and clever)! But what is a "teardrop edge"
precisely?

Carsten Arnholm


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

Okay. Discussion of a list of two-dimensional shapes, mathematical/programmatic techniques for dividing shapes into regions, and the possible shapes which one can use in such deconstruction. Suggested text/terminology, esp. a book suited to a layman. Eventually the project may work up to 3 dimensional shapes, but for now, trying to limit it to stacks of two-dimensional shapes cut into a three-dimensional stock. William On Fri, May 3, 2019 at 10:43 AM nop head <nop.head@gmail.com> wrote: > I don't think topology is what you mean. For example a doughnut and a > teacup with a handle are topologically the same. > > On Fri, 3 May 2019 at 14:54, William Adams <will.adams@frycomm.com> wrote: > >> I've been working through this sort of thing myself, and have been >> working up a series of basic modules which do rounded edged (and optionally >> bottomed) pockets so as to model projects for a hobby CNC. >> >> The problem of course is working up a reasonable definition of the shapes >> in terms of parameters --- I believe the field which covers this sort of >> thing is topology? >> >> Does anyone know of any good texts on this which might be approachable to >> a layman? >> >> William >> >> >> On Fri, May 3, 2019 at 7:11 AM nop head <nop.head@gmail.com> wrote: >> >>> I use an inverted truncated rotate_extruded teardrop on the bottom >>> edges of my rounded objects so they don't need support when printing. I >>> assume that is what a "teardrop edge" is. >>> >>> [image: handle.png] >>> >>> On Fri, 3 May 2019 at 12:05, <arnholm@arnholm.org> wrote: >>> >>>> On 2019-05-03 11:58, adrianv wrote: >>>> > So I have a rounded box with a teardrop edge at the base, a rounded >>>> top >>>> > edge, and a more rounded interior bottom edge. >>>> > >>>> > <http://forum.openscad.org/file/t2477/fbox1.png> >>>> >>>> That's very, very nice (and clever)! But what is a "teardrop edge" >>>> precisely? >>>> >>>> Carsten Arnholm >>>> >>>> _______________________________________________ >>>> 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 >> > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >
NH
nop head
Fri, May 3, 2019 3:31 PM

I think the correct term is Constructional Solid Geometry
https://en.wikipedia.org/wiki/Constructive_solid_geometry  You might find
books on that but they are probably more about theory than actually how to
make specific shapes with it.

On Fri, 3 May 2019 at 16:03, William Adams will.adams@frycomm.com wrote:

Okay. Discussion of a list of two-dimensional shapes,
mathematical/programmatic techniques for dividing shapes into regions, and
the possible shapes which one can use in such deconstruction.

Suggested text/terminology, esp. a book suited to a layman.

Eventually the project may work up to 3 dimensional shapes, but for now,
trying to limit it to stacks of two-dimensional shapes cut into a
three-dimensional stock.

William

On Fri, May 3, 2019 at 10:43 AM nop head nop.head@gmail.com wrote:

I don't think topology is what you mean. For example a doughnut and a
teacup with a handle are topologically the same.

On Fri, 3 May 2019 at 14:54, William Adams will.adams@frycomm.com
wrote:

I've been working through this sort of thing myself, and have been
working up a series of basic modules which do rounded edged (and optionally
bottomed) pockets so as to model projects for a hobby CNC.

The problem of course is working up a reasonable definition of the
shapes in terms of parameters --- I believe the field which covers this
sort of thing is topology?

Does anyone know of any good texts on this which might be approachable
to a layman?

William

On Fri, May 3, 2019 at 7:11 AM nop head nop.head@gmail.com wrote:

I use an inverted truncated rotate_extruded teardrop on the bottom
edges of my rounded objects so they don't need support when printing. I
assume that is what a "teardrop edge" is.

[image: handle.png]

On Fri, 3 May 2019 at 12:05, arnholm@arnholm.org wrote:

On 2019-05-03 11:58, adrianv wrote:

So I have a rounded box with a teardrop edge at the base, a rounded

top

edge, and a more rounded interior bottom edge.

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

That's very, very nice (and clever)! But what is a "teardrop edge"
precisely?

Carsten Arnholm


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

I think the correct term is Constructional Solid Geometry https://en.wikipedia.org/wiki/Constructive_solid_geometry You might find books on that but they are probably more about theory than actually how to make specific shapes with it. On Fri, 3 May 2019 at 16:03, William Adams <will.adams@frycomm.com> wrote: > Okay. Discussion of a list of two-dimensional shapes, > mathematical/programmatic techniques for dividing shapes into regions, and > the possible shapes which one can use in such deconstruction. > > Suggested text/terminology, esp. a book suited to a layman. > > Eventually the project may work up to 3 dimensional shapes, but for now, > trying to limit it to stacks of two-dimensional shapes cut into a > three-dimensional stock. > > William > > On Fri, May 3, 2019 at 10:43 AM nop head <nop.head@gmail.com> wrote: > >> I don't think topology is what you mean. For example a doughnut and a >> teacup with a handle are topologically the same. >> >> On Fri, 3 May 2019 at 14:54, William Adams <will.adams@frycomm.com> >> wrote: >> >>> I've been working through this sort of thing myself, and have been >>> working up a series of basic modules which do rounded edged (and optionally >>> bottomed) pockets so as to model projects for a hobby CNC. >>> >>> The problem of course is working up a reasonable definition of the >>> shapes in terms of parameters --- I believe the field which covers this >>> sort of thing is topology? >>> >>> Does anyone know of any good texts on this which might be approachable >>> to a layman? >>> >>> William >>> >>> >>> On Fri, May 3, 2019 at 7:11 AM nop head <nop.head@gmail.com> wrote: >>> >>>> I use an inverted truncated rotate_extruded teardrop on the bottom >>>> edges of my rounded objects so they don't need support when printing. I >>>> assume that is what a "teardrop edge" is. >>>> >>>> [image: handle.png] >>>> >>>> On Fri, 3 May 2019 at 12:05, <arnholm@arnholm.org> wrote: >>>> >>>>> On 2019-05-03 11:58, adrianv wrote: >>>>> > So I have a rounded box with a teardrop edge at the base, a rounded >>>>> top >>>>> > edge, and a more rounded interior bottom edge. >>>>> > >>>>> > <http://forum.openscad.org/file/t2477/fbox1.png> >>>>> >>>>> That's very, very nice (and clever)! But what is a "teardrop edge" >>>>> precisely? >>>>> >>>>> Carsten Arnholm >>>>> >>>>> _______________________________________________ >>>>> 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 >>> >> _______________________________________________ >> 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 >
A
adrianv
Fri, May 3, 2019 3:32 PM

Yes, what I meant by "teardrop" is an edge which combines 45 degrees of a
circular arc with a bevel at 45 deg so that the edge can be 3d printed
without support---with the bevel down there are no unsupported areas at
lower than a 45 deg angle.

William Adams-2 wrote

Okay. Discussion of a list of two-dimensional shapes,
mathematical/programmatic techniques for dividing shapes into regions, and
the possible shapes which one can use in such deconstruction.

I really don't understand your question.  When people talk of dividing 2d
shapes into regions they usually mean triangulating the shape.  But it
sounds like you mean something else.  Maybe you should give a specific
example?

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

Yes, what I meant by "teardrop" is an edge which combines 45 degrees of a circular arc with a bevel at 45 deg so that the edge can be 3d printed without support---with the bevel down there are no unsupported areas at lower than a 45 deg angle. William Adams-2 wrote > Okay. Discussion of a list of two-dimensional shapes, > mathematical/programmatic techniques for dividing shapes into regions, and > the possible shapes which one can use in such deconstruction. I really don't understand your question. When people talk of dividing 2d shapes into regions they usually mean triangulating the shape. But it sounds like you mean something else. Maybe you should give a specific example? -- Sent from: http://forum.openscad.org/
WA
William Adams
Fri, May 3, 2019 3:33 PM

Okay, a quick survey of an encyclopedia / dictionary yielded:

  • 0
    ** circle
    ** oval/ellipse (requires some sort of non-arc curve)
    *** egg-shaped (requires some sort of non-arc curve)
    ** annulus (one circle within another forming a ring)
    ** superellipse (see astroid below)
  • 1
    ** cone with rounded end (arc)
  • 2
    ** semicircle/circular segment (arc and a straight line)
    ** lens/vesical piscis (two convex curves)
    ** lune/crescent (one convex one concave curve)
    ** heart (two curves)
    ** tomoe (comma shape) --- requires non arc curves
  • 3
    ** triangle
    *** equilateral
    *** isosceles
    *** scalene
    ** sector (two straight edges, one convex arc)
    ** two straight edges, one concave arc
    ** Deltoid curve (three concave arcs)
    ** Reuleaux triangle (three convex arcs)
    ** Arbelos (one convex, two concave arcs)
  • 4
    ** square
    ** rectangle
    ** parallelogram
    ** rhombus
    ** trapezoid/trapezium
    ** kite
    ** astroid (four concave arcs)
    ** salinon (four semicircles)

any obvious corrections or additions?

Other suggestions?

William

On Fri, May 3, 2019 at 11:03 AM William Adams will.adams@frycomm.com
wrote:

Okay. Discussion of a list of two-dimensional shapes,
mathematical/programmatic techniques for dividing shapes into regions, and
the possible shapes which one can use in such deconstruction.

Suggested text/terminology, esp. a book suited to a layman.

Eventually the project may work up to 3 dimensional shapes, but for now,
trying to limit it to stacks of two-dimensional shapes cut into a
three-dimensional stock.

William

On Fri, May 3, 2019 at 10:43 AM nop head nop.head@gmail.com wrote:

I don't think topology is what you mean. For example a doughnut and a
teacup with a handle are topologically the same.

On Fri, 3 May 2019 at 14:54, William Adams will.adams@frycomm.com
wrote:

I've been working through this sort of thing myself, and have been
working up a series of basic modules which do rounded edged (and optionally
bottomed) pockets so as to model projects for a hobby CNC.

The problem of course is working up a reasonable definition of the
shapes in terms of parameters --- I believe the field which covers this
sort of thing is topology?

Does anyone know of any good texts on this which might be approachable
to a layman?

William

On Fri, May 3, 2019 at 7:11 AM nop head nop.head@gmail.com wrote:

I use an inverted truncated rotate_extruded teardrop on the bottom
edges of my rounded objects so they don't need support when printing. I
assume that is what a "teardrop edge" is.

[image: handle.png]

On Fri, 3 May 2019 at 12:05, arnholm@arnholm.org wrote:

On 2019-05-03 11:58, adrianv wrote:

So I have a rounded box with a teardrop edge at the base, a rounded

top

edge, and a more rounded interior bottom edge.

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

That's very, very nice (and clever)! But what is a "teardrop edge"
precisely?

Carsten Arnholm


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

Okay, a quick survey of an encyclopedia / dictionary yielded: * 0 ** circle ** oval/ellipse (requires some sort of non-arc curve) *** egg-shaped (requires some sort of non-arc curve) ** annulus (one circle within another forming a ring) ** superellipse (see astroid below) * 1 ** cone with rounded end (arc) * 2 ** semicircle/circular segment (arc and a straight line) ** lens/vesical piscis (two convex curves) ** lune/crescent (one convex one concave curve) ** heart (two curves) ** tomoe (comma shape) --- requires non arc curves * 3 ** triangle *** equilateral *** isosceles *** scalene ** sector (two straight edges, one convex arc) ** two straight edges, one concave arc ** Deltoid curve (three concave arcs) ** Reuleaux triangle (three convex arcs) ** Arbelos (one convex, two concave arcs) * 4 ** square ** rectangle ** parallelogram ** rhombus ** trapezoid/trapezium ** kite ** astroid (four concave arcs) ** salinon (four semicircles) any obvious corrections or additions? Other suggestions? William On Fri, May 3, 2019 at 11:03 AM William Adams <will.adams@frycomm.com> wrote: > Okay. Discussion of a list of two-dimensional shapes, > mathematical/programmatic techniques for dividing shapes into regions, and > the possible shapes which one can use in such deconstruction. > > Suggested text/terminology, esp. a book suited to a layman. > > Eventually the project may work up to 3 dimensional shapes, but for now, > trying to limit it to stacks of two-dimensional shapes cut into a > three-dimensional stock. > > William > > On Fri, May 3, 2019 at 10:43 AM nop head <nop.head@gmail.com> wrote: > >> I don't think topology is what you mean. For example a doughnut and a >> teacup with a handle are topologically the same. >> >> On Fri, 3 May 2019 at 14:54, William Adams <will.adams@frycomm.com> >> wrote: >> >>> I've been working through this sort of thing myself, and have been >>> working up a series of basic modules which do rounded edged (and optionally >>> bottomed) pockets so as to model projects for a hobby CNC. >>> >>> The problem of course is working up a reasonable definition of the >>> shapes in terms of parameters --- I believe the field which covers this >>> sort of thing is topology? >>> >>> Does anyone know of any good texts on this which might be approachable >>> to a layman? >>> >>> William >>> >>> >>> On Fri, May 3, 2019 at 7:11 AM nop head <nop.head@gmail.com> wrote: >>> >>>> I use an inverted truncated rotate_extruded teardrop on the bottom >>>> edges of my rounded objects so they don't need support when printing. I >>>> assume that is what a "teardrop edge" is. >>>> >>>> [image: handle.png] >>>> >>>> On Fri, 3 May 2019 at 12:05, <arnholm@arnholm.org> wrote: >>>> >>>>> On 2019-05-03 11:58, adrianv wrote: >>>>> > So I have a rounded box with a teardrop edge at the base, a rounded >>>>> top >>>>> > edge, and a more rounded interior bottom edge. >>>>> > >>>>> > <http://forum.openscad.org/file/t2477/fbox1.png> >>>>> >>>>> That's very, very nice (and clever)! But what is a "teardrop edge" >>>>> precisely? >>>>> >>>>> Carsten Arnholm >>>>> >>>>> _______________________________________________ >>>>> 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 >>> >> _______________________________________________ >> OpenSCAD mailing list >> Discuss@lists.openscad.org >> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >> >
WA
William Adams
Fri, May 3, 2019 3:54 PM

I'm hoping to eventually work up a general algorithm for subdividing an
arbitrary shape/area so that it can then be cut out using macros/modules
which I'll be defining in OpenSCAD (so as to have a 3D preview of a
project) and in some other programming languages as well (METAPOST seems
possible, Javascript/TPL (Tool Path Language) another, Python, or LiveCode
distant possibilities.

Basically I want to be able to have rounded ends on the dividers in:

https://community.carbide3d.com/t/fitted-box-design-generator-underway/13437/2

[image: cncboxfitted_3x3_round_divider.png]

instead of the sharp points.

William

On Fri, May 3, 2019 at 11:32 AM adrianv avm4@cornell.edu wrote:

Yes, what I meant by "teardrop" is an edge which combines 45 degrees of a
circular arc with a bevel at 45 deg so that the edge can be 3d printed
without support---with the bevel down there are no unsupported areas at
lower than a 45 deg angle.

William Adams-2 wrote

Okay. Discussion of a list of two-dimensional shapes,
mathematical/programmatic techniques for dividing shapes into regions,

and

the possible shapes which one can use in such deconstruction.

I really don't understand your question.  When people talk of dividing 2d
shapes into regions they usually mean triangulating the shape.  But it
sounds like you mean something else.  Maybe you should give a specific
example?

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


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

I'm hoping to eventually work up a general algorithm for subdividing an arbitrary shape/area so that it can then be cut out using macros/modules which I'll be defining in OpenSCAD (so as to have a 3D preview of a project) and in some other programming languages as well (METAPOST seems possible, Javascript/TPL (Tool Path Language) another, Python, or LiveCode distant possibilities. Basically I want to be able to have rounded ends on the dividers in: https://community.carbide3d.com/t/fitted-box-design-generator-underway/13437/2 [image: cncboxfitted_3x3_round_divider.png] instead of the sharp points. William On Fri, May 3, 2019 at 11:32 AM adrianv <avm4@cornell.edu> wrote: > Yes, what I meant by "teardrop" is an edge which combines 45 degrees of a > circular arc with a bevel at 45 deg so that the edge can be 3d printed > without support---with the bevel down there are no unsupported areas at > lower than a 45 deg angle. > > > William Adams-2 wrote > > Okay. Discussion of a list of two-dimensional shapes, > > mathematical/programmatic techniques for dividing shapes into regions, > and > > the possible shapes which one can use in such deconstruction. > > I really don't understand your question. When people talk of dividing 2d > shapes into regions they usually mean triangulating the shape. But it > sounds like you mean something else. Maybe you should give a specific > example? > > > > > -- > 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
Fri, May 3, 2019 4:07 PM

I would make the shape by a cylinder and two linear extrudes stacked on top
of each other. To round the divider I would use offset(r) offset(-2 * r)
offset(r). That leaves the dimension the same but rounds both internal an
external corners.

On Fri, 3 May 2019 at 16:55, William Adams will.adams@frycomm.com wrote:

I'm hoping to eventually work up a general algorithm for subdividing an
arbitrary shape/area so that it can then be cut out using macros/modules
which I'll be defining in OpenSCAD (so as to have a 3D preview of a
project) and in some other programming languages as well (METAPOST seems
possible, Javascript/TPL (Tool Path Language) another, Python, or LiveCode
distant possibilities.

Basically I want to be able to have rounded ends on the dividers in:

https://community.carbide3d.com/t/fitted-box-design-generator-underway/13437/2

[image: cncboxfitted_3x3_round_divider.png]

instead of the sharp points.

William

On Fri, May 3, 2019 at 11:32 AM adrianv avm4@cornell.edu wrote:

Yes, what I meant by "teardrop" is an edge which combines 45 degrees of a
circular arc with a bevel at 45 deg so that the edge can be 3d printed
without support---with the bevel down there are no unsupported areas at
lower than a 45 deg angle.

William Adams-2 wrote

Okay. Discussion of a list of two-dimensional shapes,
mathematical/programmatic techniques for dividing shapes into regions,

and

the possible shapes which one can use in such deconstruction.

I really don't understand your question.  When people talk of dividing 2d
shapes into regions they usually mean triangulating the shape.  But it
sounds like you mean something else.  Maybe you should give a specific
example?

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


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

I would make the shape by a cylinder and two linear extrudes stacked on top of each other. To round the divider I would use offset(r) offset(-2 * r) offset(r). That leaves the dimension the same but rounds both internal an external corners. On Fri, 3 May 2019 at 16:55, William Adams <will.adams@frycomm.com> wrote: > I'm hoping to eventually work up a general algorithm for subdividing an > arbitrary shape/area so that it can then be cut out using macros/modules > which I'll be defining in OpenSCAD (so as to have a 3D preview of a > project) and in some other programming languages as well (METAPOST seems > possible, Javascript/TPL (Tool Path Language) another, Python, or LiveCode > distant possibilities. > > Basically I want to be able to have rounded ends on the dividers in: > > > https://community.carbide3d.com/t/fitted-box-design-generator-underway/13437/2 > > [image: cncboxfitted_3x3_round_divider.png] > > instead of the sharp points. > > William > > > > On Fri, May 3, 2019 at 11:32 AM adrianv <avm4@cornell.edu> wrote: > >> Yes, what I meant by "teardrop" is an edge which combines 45 degrees of a >> circular arc with a bevel at 45 deg so that the edge can be 3d printed >> without support---with the bevel down there are no unsupported areas at >> lower than a 45 deg angle. >> >> >> William Adams-2 wrote >> > Okay. Discussion of a list of two-dimensional shapes, >> > mathematical/programmatic techniques for dividing shapes into regions, >> and >> > the possible shapes which one can use in such deconstruction. >> >> I really don't understand your question. When people talk of dividing 2d >> shapes into regions they usually mean triangulating the shape. But it >> sounds like you mean something else. Maybe you should give a specific >> example? >> >> >> >> >> -- >> 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 >
WA
William Adams
Fri, May 3, 2019 4:12 PM

Thanks! I've got a module which I'm calling which checks for endmill shape
and either puts a ball-nose on it or not (debating on adding support for V
shapes as well).

On Fri, May 3, 2019 at 12:08 PM nop head nop.head@gmail.com wrote:

I would make the shape by a cylinder and two linear extrudes stacked on
top of each other. To round the divider I would use offset(r) offset(-2 *
r) offset(r). That leaves the dimension the same but rounds both internal
an external corners.

On Fri, 3 May 2019 at 16:55, William Adams will.adams@frycomm.com wrote:

I'm hoping to eventually work up a general algorithm for subdividing an
arbitrary shape/area so that it can then be cut out using macros/modules
which I'll be defining in OpenSCAD (so as to have a 3D preview of a
project) and in some other programming languages as well (METAPOST seems
possible, Javascript/TPL (Tool Path Language) another, Python, or LiveCode
distant possibilities.

Basically I want to be able to have rounded ends on the dividers in:

https://community.carbide3d.com/t/fitted-box-design-generator-underway/13437/2

[image: cncboxfitted_3x3_round_divider.png]

instead of the sharp points.

William

On Fri, May 3, 2019 at 11:32 AM adrianv avm4@cornell.edu wrote:

Yes, what I meant by "teardrop" is an edge which combines 45 degrees of a
circular arc with a bevel at 45 deg so that the edge can be 3d printed
without support---with the bevel down there are no unsupported areas at
lower than a 45 deg angle.

William Adams-2 wrote

Okay. Discussion of a list of two-dimensional shapes,
mathematical/programmatic techniques for dividing shapes into regions,

and

the possible shapes which one can use in such deconstruction.

I really don't understand your question.  When people talk of dividing 2d
shapes into regions they usually mean triangulating the shape.  But it
sounds like you mean something else.  Maybe you should give a specific
example?

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


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

Thanks! I've got a module which I'm calling which checks for endmill shape and either puts a ball-nose on it or not (debating on adding support for V shapes as well). On Fri, May 3, 2019 at 12:08 PM nop head <nop.head@gmail.com> wrote: > I would make the shape by a cylinder and two linear extrudes stacked on > top of each other. To round the divider I would use offset(r) offset(-2 * > r) offset(r). That leaves the dimension the same but rounds both internal > an external corners. > > On Fri, 3 May 2019 at 16:55, William Adams <will.adams@frycomm.com> wrote: > >> I'm hoping to eventually work up a general algorithm for subdividing an >> arbitrary shape/area so that it can then be cut out using macros/modules >> which I'll be defining in OpenSCAD (so as to have a 3D preview of a >> project) and in some other programming languages as well (METAPOST seems >> possible, Javascript/TPL (Tool Path Language) another, Python, or LiveCode >> distant possibilities. >> >> Basically I want to be able to have rounded ends on the dividers in: >> >> >> https://community.carbide3d.com/t/fitted-box-design-generator-underway/13437/2 >> >> [image: cncboxfitted_3x3_round_divider.png] >> >> instead of the sharp points. >> >> William >> >> >> >> On Fri, May 3, 2019 at 11:32 AM adrianv <avm4@cornell.edu> wrote: >> >>> Yes, what I meant by "teardrop" is an edge which combines 45 degrees of a >>> circular arc with a bevel at 45 deg so that the edge can be 3d printed >>> without support---with the bevel down there are no unsupported areas at >>> lower than a 45 deg angle. >>> >>> >>> William Adams-2 wrote >>> > Okay. Discussion of a list of two-dimensional shapes, >>> > mathematical/programmatic techniques for dividing shapes into regions, >>> and >>> > the possible shapes which one can use in such deconstruction. >>> >>> I really don't understand your question. When people talk of dividing 2d >>> shapes into regions they usually mean triangulating the shape. But it >>> sounds like you mean something else. Maybe you should give a specific >>> example? >>> >>> >>> >>> >>> -- >>> 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
RayBellis
Fri, May 3, 2019 4:19 PM

adrianv wrote

I really don't understand your question.  When people talk of dividing 2d
shapes into regions they usually mean triangulating the shape.  But it
sounds like you mean something else.  Maybe you should give a specific
example?

For example, given a rectangular outline of a box, I might like to split
that box into two compartments, and then I might want to further split one
of those compartments into three compartments (but sliced in the opposite
direction).

I actually did write a module for doing this (for rectangular boxes and
subdivisions).  It needs dusting off, though.

Ray

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

adrianv wrote > I really don't understand your question. When people talk of dividing 2d > shapes into regions they usually mean triangulating the shape. But it > sounds like you mean something else. Maybe you should give a specific > example? For example, given a rectangular outline of a box, I might like to split that box into two compartments, and then I might want to further split one of those compartments into three compartments (but sliced in the opposite direction). I actually did write a module for doing this (for rectangular boxes and subdivisions). It needs dusting off, though. Ray -- Sent from: http://forum.openscad.org/
WA
William Adams
Fri, May 3, 2019 4:50 PM

That's exactly what I've been working up --- I got rectangles done, now I'm
starting in on circles, next will be regular polygons, then we'll see if we
can do ovals and other shapes.

William

On Fri, May 3, 2019 at 12:20 PM RayBellis openscad@ray.bellis.me.uk wrote:

adrianv wrote

I really don't understand your question.  When people talk of dividing 2d
shapes into regions they usually mean triangulating the shape.  But it
sounds like you mean something else.  Maybe you should give a specific
example?

For example, given a rectangular outline of a box, I might like to split
that box into two compartments, and then I might want to further split one
of those compartments into three compartments (but sliced in the opposite
direction).

I actually did write a module for doing this (for rectangular boxes and
subdivisions).  It needs dusting off, though.

Ray

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


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

That's exactly what I've been working up --- I got rectangles done, now I'm starting in on circles, next will be regular polygons, then we'll see if we can do ovals and other shapes. William On Fri, May 3, 2019 at 12:20 PM RayBellis <openscad@ray.bellis.me.uk> wrote: > adrianv wrote > > I really don't understand your question. When people talk of dividing 2d > > shapes into regions they usually mean triangulating the shape. But it > > sounds like you mean something else. Maybe you should give a specific > > example? > > For example, given a rectangular outline of a box, I might like to split > that box into two compartments, and then I might want to further split one > of those compartments into three compartments (but sliced in the opposite > direction). > > I actually did write a module for doing this (for rectangular boxes and > subdivisions). It needs dusting off, though. > > Ray > > > > -- > Sent from: http://forum.openscad.org/ > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >
AC
A. Craig West
Fri, May 3, 2019 4:59 PM

I spent a LOT of time writing code to do this, and triangulation of
polygons. Dues to implementation issues I ended up implementing a
convexifyPolygon function which turns an arbitrary non-self-intersecting
polygon into a list of convex polygons, and a triangulariseConvexPolygon
which triangulates the convex polygons. To implement those I needed various
splitting and clipping functions

On Fri, 3 May 2019, 12:50 William Adams, will.adams@frycomm.com wrote:

That's exactly what I've been working up --- I got rectangles done, now
I'm starting in on circles, next will be regular polygons, then we'll see
if we can do ovals and other shapes.

William

On Fri, May 3, 2019 at 12:20 PM RayBellis openscad@ray.bellis.me.uk
wrote:

adrianv wrote

I really don't understand your question.  When people talk of dividing

2d

shapes into regions they usually mean triangulating the shape.  But it
sounds like you mean something else.  Maybe you should give a specific
example?

For example, given a rectangular outline of a box, I might like to split
that box into two compartments, and then I might want to further split one
of those compartments into three compartments (but sliced in the opposite
direction).

I actually did write a module for doing this (for rectangular boxes and
subdivisions).  It needs dusting off, though.

Ray

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


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

I spent a LOT of time writing code to do this, and triangulation of polygons. Dues to implementation issues I ended up implementing a convexifyPolygon function which turns an arbitrary non-self-intersecting polygon into a list of convex polygons, and a triangulariseConvexPolygon which triangulates the convex polygons. To implement those I needed various splitting and clipping functions On Fri, 3 May 2019, 12:50 William Adams, <will.adams@frycomm.com> wrote: > That's exactly what I've been working up --- I got rectangles done, now > I'm starting in on circles, next will be regular polygons, then we'll see > if we can do ovals and other shapes. > > William > > On Fri, May 3, 2019 at 12:20 PM RayBellis <openscad@ray.bellis.me.uk> > wrote: > >> adrianv wrote >> > I really don't understand your question. When people talk of dividing >> 2d >> > shapes into regions they usually mean triangulating the shape. But it >> > sounds like you mean something else. Maybe you should give a specific >> > example? >> >> For example, given a rectangular outline of a box, I might like to split >> that box into two compartments, and then I might want to further split one >> of those compartments into three compartments (but sliced in the opposite >> direction). >> >> I actually did write a module for doing this (for rectangular boxes and >> subdivisions). It needs dusting off, though. >> >> Ray >> >> >> >> -- >> 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 >
A
adrianv
Fri, May 3, 2019 5:07 PM

You just want to round the junctions?  I think you can do that for an
arbitrary 2d shape using offset(), with something like this (which was
previously mentioned many posts ago on this thread):

module round2d(or, ir)
{
offset(or) offset(-ir-or) offset(delta=ir) children();
}

As long as your walls aren't too thin relative to the curvature you want
(which looks small in your examples) I think that the above will actually do
the job of rounding any box you want to make.

round2d(or=.4, ir=1){
difference(){
square([20,20],center=true);
square([18,18],center=true);
}
translate([10,0,0])
difference(){
circle(d=20);
circle(d=18);
}
}

If you set or>-0.5 then you get in trouble because the walls vanish.  But if
you round the outside shape first (before cutting out the middle) you can
resolve this problem.

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

I'm not sure what you mean about the "algorithm for subdividing" part of
your project, though.

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

You just want to round the junctions? I think you can do that for an arbitrary 2d shape using offset(), with something like this (which was previously mentioned many posts ago on this thread): module round2d(or, ir) { offset(or) offset(-ir-or) offset(delta=ir) children(); } As long as your walls aren't too thin relative to the curvature you want (which looks small in your examples) I think that the above will actually do the job of rounding any box you want to make. round2d(or=.4, ir=1){ difference(){ square([20,20],center=true); square([18,18],center=true); } translate([10,0,0]) difference(){ circle(d=20); circle(d=18); } } If you set or>-0.5 then you get in trouble because the walls vanish. But if you round the outside shape first (before cutting out the middle) you can resolve this problem. <http://forum.openscad.org/file/t2477/roundedthing.png> I'm not sure what you mean about the "algorithm for subdividing" part of your project, though. -- Sent from: http://forum.openscad.org/
A
adrianv
Fri, May 3, 2019 10:24 PM

Can you be more specific about what you are trying to do?  You want to divide
a circle up into compartments with circular arcs?  I mean, it seems like the
basic task of dividing a region into smaller regions with paths is mainly
difficult due to the interface part of the problem: how do you specify what
you want to create?

William Adams-2 wrote

That's exactly what I've been working up --- I got rectangles done, now
I'm
starting in on circles, next will be regular polygons, then we'll see if
we
can do ovals and other shapes.

William

On Fri, May 3, 2019 at 12:20 PM RayBellis <

openscad@.me

> wrote:

adrianv wrote

I really don't understand your question.  When people talk of dividing

2d

shapes into regions they usually mean triangulating the shape.  But it
sounds like you mean something else.  Maybe you should give a specific
example?

For example, given a rectangular outline of a box, I might like to split
that box into two compartments, and then I might want to further split
one
of those compartments into three compartments (but sliced in the opposite
direction).

I actually did write a module for doing this (for rectangular boxes and
subdivisions).  It needs dusting off, though.

Ray

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


OpenSCAD mailing list

Discuss@.openscad

Discuss@.openscad

Can you be more specific about what you are trying to do? You want to divide a circle up into compartments with circular arcs? I mean, it seems like the basic task of dividing a region into smaller regions with paths is mainly difficult due to the interface part of the problem: how do you specify what you want to create? William Adams-2 wrote > That's exactly what I've been working up --- I got rectangles done, now > I'm > starting in on circles, next will be regular polygons, then we'll see if > we > can do ovals and other shapes. > > William > > On Fri, May 3, 2019 at 12:20 PM RayBellis &lt; > openscad@.me > &gt; wrote: > >> adrianv wrote >> > I really don't understand your question. When people talk of dividing >> 2d >> > shapes into regions they usually mean triangulating the shape. But it >> > sounds like you mean something else. Maybe you should give a specific >> > example? >> >> For example, given a rectangular outline of a box, I might like to split >> that box into two compartments, and then I might want to further split >> one >> of those compartments into three compartments (but sliced in the opposite >> direction). >> >> I actually did write a module for doing this (for rectangular boxes and >> subdivisions). It needs dusting off, though. >> >> Ray >> >> >> >> -- >> Sent from: http://forum.openscad.org/ >> >> _______________________________________________ >> OpenSCAD mailing list >> > Discuss@.openscad >> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >> > > _______________________________________________ > OpenSCAD mailing list > Discuss@.openscad > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org -- Sent from: http://forum.openscad.org/
A
adrianv
Fri, May 3, 2019 10:56 PM

Here's another example of a rounded box, this time with a more complex shape.
Note how the rounded edges of the tips vanish in the roundover at the
bottom.  (One of the challenges here is that the number of vertices is not
the same in each layer.)

http://forum.openscad.org/file/t2477/fstarbox1.png
http://forum.openscad.org/file/t2477/fstarbox2.png

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

Here's another example of a rounded box, this time with a more complex shape. Note how the rounded edges of the tips vanish in the roundover at the bottom. (One of the challenges here is that the number of vertices is not the same in each layer.) <http://forum.openscad.org/file/t2477/fstarbox1.png> <http://forum.openscad.org/file/t2477/fstarbox2.png> -- Sent from: http://forum.openscad.org/
RP
Ronaldo Persiano
Sun, May 19, 2019 10:48 PM

I would like to come back to our discussion of more than 1 month ago.

Em sáb, 6 de abr de 2019 às 17:01, Ronaldo Persiano rcmpersiano@gmail.com
escreveu:

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!

It was clear, I suppose, that there is no C1 triangular Bezier patch
(tripatch) that meets the conditions we were looking for to round the
corner of a cube. And we were looking for a C2 patch joint! Meanwhile, I
have studied the conditions for a G2 tripatch joint, that is, conditions
that assures a geometric continuity of first and second derivatives
instead of parametric continuity. In a G1 joint between two patches they
must have the same tangent plane at each joint point. A similar weaker
condition is demanded for G2 patch joints. Geometric conditions are in
general weaker than the parametric ones.

I will not present here the development and theoretical support of the G2
tripatch I have found. This development is a bit technical so I will just
show one solution for a tripatch with a G2 joint to round corners where
exactly 3 edges meet. It is intended to be considered for modeling
evaluation.

Fixing the 2 possible form factors, the control points of the standard 5th
degree tripatch is:

Q = [  [[0,1,1]],
[[0,1,0.68],[0,0.68,1]],
[[0,1,0.24],[0,0.6,0.6],[0,0.24,1]],
[[0.24,1,0],[0,0.6,0],[0,0,0.6],[0.24,0,1]],
[[0.68,1,0],[0.6,0.6,0],[0.6,0,0],[0.6,0,0.6],[0.68,0,1]],
[[1,1,0],[1,0.68,0],[1,0.24,0],[1,0,0.24],[1,0,0.68],[1,0,1]]
];

By standard, I mean it should be affine transformed to meet the corner
position, edge directions and rounding extension. So, to round a given
corner with coordinates P0 and edge directions d1, d2 and d3 with an
extension r, the CPs of the rounded corner are computed by:

v1  = rd1/norm(d1);
v2  = r
d2/norm(d2);
v3  = r*d3/norm(d3);
T  = [ v1, v2, v3 ];

CP  = [for(cpi=Q) [for(cpij=cpi) P0 + cpij*T ] ] ;

This tripatch is G2 and it meets the condition of geometric continuity of
first and second derivatives. Here is an image of that tripatch meeting its
mirror transform for a corner at the origin and edges along the axis.

[image: G2corner.PNG]

In the image, the joint curve is represented in yellow.

Thanks to the standard tripatch, we could round all the corners of some
polyhedra other than cubes. Here is an example of its application to a
tetrahedron, a dodecahedron and a slanted dodecahedron.

[image: G2polyhedra.PNG]

In the computation of the standard control points, two form factors may be
arbitrated by the caller, one of them being the form factor of the 4th
degree curve which is the joint curve of the patches. The computation
implies the solution of a linear system of 6 equations for each pair of
form factors. The logic behind that computation is, as I said, a bit
technical. I may disclose the code that does the computation if someone is
interested in but be aware that, although it is fully commented, it is not
easily understandable without the technical fundamentals.

I would like to come back to our discussion of more than 1 month ago. Em sáb, 6 de abr de 2019 às 17:01, Ronaldo Persiano <rcmpersiano@gmail.com> escreveu: > 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! > It was clear, I suppose, that there is no C1 triangular Bezier patch (tripatch) that meets the conditions we were looking for to round the corner of a cube. And we were looking for a C2 patch joint! Meanwhile, I have studied the conditions for a G2 tripatch joint, that is, conditions that assures a *geometric* continuity of first and second derivatives instead of parametric continuity. In a G1 joint between two patches they must have the same tangent plane at each joint point. A similar weaker condition is demanded for G2 patch joints. Geometric conditions are in general weaker than the parametric ones. I will not present here the development and theoretical support of the G2 tripatch I have found. This development is a bit technical so I will just show one solution for a tripatch with a G2 joint to round corners where exactly 3 edges meet. It is intended to be considered for modeling evaluation. Fixing the 2 possible form factors, the control points of the standard 5th degree tripatch is: Q = [ [[0,1,1]], [[0,1,0.68],[0,0.68,1]], [[0,1,0.24],[0,0.6,0.6],[0,0.24,1]], [[0.24,1,0],[0,0.6,0],[0,0,0.6],[0.24,0,1]], [[0.68,1,0],[0.6,0.6,0],[0.6,0,0],[0.6,0,0.6],[0.68,0,1]], [[1,1,0],[1,0.68,0],[1,0.24,0],[1,0,0.24],[1,0,0.68],[1,0,1]] ]; By standard, I mean it should be affine transformed to meet the corner position, edge directions and rounding extension. So, to round a given corner with coordinates P0 and edge directions d1, d2 and d3 with an extension r, the CPs of the rounded corner are computed by: v1 = r*d1/norm(d1); v2 = r*d2/norm(d2); v3 = r*d3/norm(d3); T = [ v1, v2, v3 ]; CP = [for(cpi=Q) [for(cpij=cpi) P0 + cpij*T ] ] ; This tripatch is G2 and it meets the condition of geometric continuity of first and second derivatives. Here is an image of that tripatch meeting its mirror transform for a corner at the origin and edges along the axis. [image: G2corner.PNG] In the image, the joint curve is represented in yellow. Thanks to the standard tripatch, we could round all the corners of some polyhedra other than cubes. Here is an example of its application to a tetrahedron, a dodecahedron and a slanted dodecahedron. [image: G2polyhedra.PNG] In the computation of the standard control points, two form factors may be arbitrated by the caller, one of them being the form factor of the 4th degree curve which is the joint curve of the patches. The computation implies the solution of a linear system of 6 equations for each pair of form factors. The logic behind that computation is, as I said, a bit technical. I may disclose the code that does the computation if someone is interested in but be aware that, although it is fully commented, it is not easily understandable without the technical fundamentals.
A
adrianv
Tue, May 28, 2019 3:17 AM

That is very interesting.  Here is a comparison of a cube made from a hull of
triangular patches and a cube made from a hull of (degenerate) rectangular
patches.  http://forum.openscad.org/file/t2477/cubes.png

It sort of looks like there's something funny going on at the boundary of
the tripatch, but I suppose it must be just a rendering artifact.  I am
printing some test cubes to see if I can tell the difference.

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

That is very interesting. Here is a comparison of a cube made from a hull of triangular patches and a cube made from a hull of (degenerate) rectangular patches. <http://forum.openscad.org/file/t2477/cubes.png> It sort of looks like there's something funny going on at the boundary of the tripatch, but I suppose it must be just a rendering artifact. I am printing some test cubes to see if I can tell the difference. -- Sent from: http://forum.openscad.org/
A
adrianv
Tue, May 28, 2019 10:42 PM

Does the boundary of your tripatch have an order 4 bezier representation?  It
sounds like you constructed the match to match up with such a curve?  What
are the order 4 control points for the patch you posted?

My FDM printed models are inconclusive because the shape of the roundovers
is not similar enough.  The case I did with spheres does seem worse, despite
the limited resolution of my layer thickness---I printed with 0.15mm layers.
I might try another test with 0.05 layers after a better effort to match the
shape of the roundovers.  But ultimately there's a problem that the limited
z resolution makes this less important.  I suppose someone with SLS or some
other higher resolution output device would notice the difference more
clearly.

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

Does the boundary of your tripatch have an order 4 bezier representation? It sounds like you constructed the match to match up with such a curve? What are the order 4 control points for the patch you posted? My FDM printed models are inconclusive because the shape of the roundovers is not similar enough. The case I did with spheres does seem worse, despite the limited resolution of my layer thickness---I printed with 0.15mm layers. I might try another test with 0.05 layers after a better effort to match the shape of the roundovers. But ultimately there's a problem that the limited z resolution makes this less important. I suppose someone with SLS or some other higher resolution output device would notice the difference more clearly. -- Sent from: http://forum.openscad.org/
A
adrianv
Tue, May 28, 2019 11:33 PM

I was studying my 3d printed models some more and noticed that the highlights
on the roundover from the right direction appear to have a corner, which
raises questions about the curvature continuity.  Another observation is
that the behavior of those highlights is visually odd, as compared to the
highlights from the degenerate rectangular patch, where the highlights don't
do anything strange.

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

I was studying my 3d printed models some more and noticed that the highlights on the roundover from the right direction appear to have a corner, which raises questions about the curvature continuity. Another observation is that the behavior of those highlights is visually odd, as compared to the highlights from the degenerate rectangular patch, where the highlights don't do anything strange. -- Sent from: http://forum.openscad.org/
RP
Ronaldo Persiano
Wed, May 29, 2019 1:04 AM

Thank you for your interest in the solution I proposed.

adrianv avm4@cornell.edu wrote:

Does the boundary of your tripatch have an order 4 bezier representation?
It
sounds like you constructed the match to match up with such a curve?  What
are the order 4 control points for the patch you posted?

Yes, the border of the standard 5th degree tripatch is indeed 4th degree
Bezier curve like the ones we considered for 2D cases with curvature
continuity. Its degree was elevated to 5 in order to have more freedom in
the internal control points of the patch. The control points of the 3
border curves of the standard 5th degree tripatch are:

[[1, 1, 0], [1, 0.6, 0], [1, 0, 0], [1, 0, 0.6], [1, 0, 1]]

[[0, 1, 1], [0, 1, 0.6], [0, 1, 0], [0.6, 1, 0], [1, 1, 0]]

[[1, 0, 1], [0.6, 0, 1], [0, 0, 1], [0, 0.6, 1], [0, 1, 1]]

They correspond to 4th degree curves with a form factor of r0=0.4.
Another possible form factor appeared in the development of the tripatch.
Its effect is restricted to the interior of the patch and do not affect its
border. That form factor were arbitrated to be 1 in the standard 5th degree
tripatch I proposed before.

My FDM printed models are inconclusive because the shape of the roundovers
is not similar enough.  The case I did with spheres does seem worse,
despite
the limited resolution of my layer thickness---I printed with 0.15mm
layers.
I might try another test with 0.05 layers after a better effort to match
the
shape of the roundovers.  But ultimately there's a problem that the limited
z resolution makes this less important.  I suppose someone with SLS or some
other higher resolution output device would notice the difference more
clearly.

It seems to me that to compare the standard tripatch with the degenerated
rectangular one, this last one should be generated with the same form
factor 0.4. Otherwise, the corner border curves (and the edge roundover)
may be very different.

Thank you for your interest in the solution I proposed. adrianv <avm4@cornell.edu> wrote: > Does the boundary of your tripatch have an order 4 bezier representation? > It > sounds like you constructed the match to match up with such a curve? What > are the order 4 control points for the patch you posted? > Yes, the border of the standard 5th degree tripatch is indeed 4th degree Bezier curve like the ones we considered for 2D cases with curvature continuity. Its degree was elevated to 5 in order to have more freedom in the internal control points of the patch. The control points of the 3 border curves of the standard 5th degree tripatch are: [[1, 1, 0], [1, 0.6, 0], [1, 0, 0], [1, 0, 0.6], [1, 0, 1]] [[0, 1, 1], [0, 1, 0.6], [0, 1, 0], [0.6, 1, 0], [1, 1, 0]] [[1, 0, 1], [0.6, 0, 1], [0, 0, 1], [0, 0.6, 1], [0, 1, 1]] They correspond to 4th degree curves with a form factor of r0=0.4. Another possible form factor appeared in the development of the tripatch. Its effect is restricted to the interior of the patch and do not affect its border. That form factor were arbitrated to be 1 in the standard 5th degree tripatch I proposed before. > My FDM printed models are inconclusive because the shape of the roundovers > is not similar enough. The case I did with spheres does seem worse, > despite > the limited resolution of my layer thickness---I printed with 0.15mm > layers. > I might try another test with 0.05 layers after a better effort to match > the > shape of the roundovers. But ultimately there's a problem that the limited > z resolution makes this less important. I suppose someone with SLS or some > other higher resolution output device would notice the difference more > clearly. > It seems to me that to compare the standard tripatch with the degenerated rectangular one, this last one should be generated with the same form factor 0.4. Otherwise, the corner border curves (and the edge roundover) may be very different.
RP
Ronaldo Persiano
Wed, May 29, 2019 1:29 AM

adrianv avm4@cornell.edu wrote:

I was studying my 3d printed models some more and noticed that the
highlights
on the roundover from the right direction appear to have a corner, which
raises questions about the curvature continuity.

What do you mean here by "right direction"?

Another observation is
that the behavior of those highlights is visually odd, as compared to the
highlights from the degenerate rectangular patch, where the highlights
don't
do anything strange.

If you give me the form factor value you are using in your degenerate
rectangular roundover , I could generate a standard 5th degree tripatch
that meets the same form factor. Besides the form factor itself, it would
be nice to have the patch border control points to check against mine patch.

adrianv <avm4@cornell.edu> wrote: > I was studying my 3d printed models some more and noticed that the > highlights > on the roundover from the right direction appear to have a corner, which > raises questions about the curvature continuity. What do you mean here by "right direction"? > Another observation is > that the behavior of those highlights is visually odd, as compared to the > highlights from the degenerate rectangular patch, where the highlights > don't > do anything strange. > If you give me the form factor value you are using in your degenerate rectangular roundover , I could generate a standard 5th degree tripatch that meets the same form factor. Besides the form factor itself, it would be nice to have the patch border control points to check against mine patch.
A
adrianv
Wed, May 29, 2019 1:34 AM

Ronaldo wrote

It seems to me that to compare the standard tripatch with the degenerated
rectangular one, this last one should be generated with the same form
factor 0.4. Otherwise, the corner border curves (and the edge roundover)
may be very different.

I agree, hence the inconclusive nature of the test.

However, I am definitely bothered by the funky highlights.  In the pictures
the tripatch is on the left, degenerate rectangle in the middle, and
circular roundover on the right.  The highlights look odd, which in an of
itself is a negative characteristic of the printed model.  It's probably the
most noticeable characteristic of the curves.  It seems like the tripatch
has some sort of bulge compared to the other ones.

http://forum.openscad.org/file/t2477/hilights.jpg
http://forum.openscad.org/file/t2477/highlights2.jpg

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

Ronaldo wrote > It seems to me that to compare the standard tripatch with the degenerated > rectangular one, this last one should be generated with the same form > factor 0.4. Otherwise, the corner border curves (and the edge roundover) > may be very different. I agree, hence the inconclusive nature of the test. However, I am definitely bothered by the funky highlights. In the pictures the tripatch is on the left, degenerate rectangle in the middle, and circular roundover on the right. The highlights look odd, which in an of itself is a negative characteristic of the printed model. It's probably the most noticeable characteristic of the curves. It seems like the tripatch has some sort of bulge compared to the other ones. <http://forum.openscad.org/file/t2477/hilights.jpg> <http://forum.openscad.org/file/t2477/highlights2.jpg> -- Sent from: http://forum.openscad.org/
A
adrianv
Wed, May 29, 2019 1:46 AM

Ronaldo wrote

adrianv <

avm4@

> wrote:

I was studying my 3d printed models some more and noticed that the
highlights
on the roundover from the right direction appear to have a corner, which
raises questions about the curvature continuity.

What do you mean here by "right direction"?

To use more precise language:  There exists a direction from which the
highlight line on the model appears to have a corner (highlight has a
discontinuity in its derivative).  This is visible in the photo I posted in
my other message.

If you give me the form factor value you are using in your degenerate
rectangular roundover , I could generate a standard 5th degree tripatch
that meets the same form factor. Besides the form factor itself, it would
be nice to have the patch border control points to check against mine
patch.

I generated my patch like this:

Q = cornerPatchCP([0,0,0],1.5, 0.3);

using the cornerPatchCP that you previously posted.  I was comparing this
patch to the patch you originally posted, so the length of d disagrees, I
think.  I can change the patch, but for print test a larger curve is better.

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

Ronaldo wrote > adrianv &lt; > avm4@ > &gt; wrote: > >> I was studying my 3d printed models some more and noticed that the >> highlights >> on the roundover from the right direction appear to have a corner, which >> raises questions about the curvature continuity. > > > What do you mean here by "right direction"? To use more precise language: There exists a direction from which the highlight line on the model appears to have a corner (highlight has a discontinuity in its derivative). This is visible in the photo I posted in my other message. > If you give me the form factor value you are using in your degenerate > rectangular roundover , I could generate a standard 5th degree tripatch > that meets the same form factor. Besides the form factor itself, it would > be nice to have the patch border control points to check against mine > patch. I generated my patch like this: Q = cornerPatchCP([0,0,0],1.5, 0.3); using the cornerPatchCP that you previously posted. I was comparing this patch to the patch you originally posted, so the length of d disagrees, I think. I can change the patch, but for print test a larger curve is better. -- Sent from: http://forum.openscad.org/
RP
Ronaldo Persiano
Wed, May 29, 2019 2:45 AM

adrianv avm4@cornell.edu wrote:

To use more precise language:  There exists a direction from which the
highlight line on the model appears to have a corner (highlight has a
discontinuity in its derivative).  This is visible in the photo I posted
in
my other message.

I understand it now. In fact, the images suggest something odd in the
border of the tripatch. See bellow.

I generated my patch like this:

Q = cornerPatchCP([0,0,0],1.5, 0.3);

using the cornerPatchCP that you previously posted.  I was comparing this
patch to the patch you originally posted, so the length of d disagrees, I
think.  I can change the patch, but for print test a larger curve is
better.

The standard patch has a unitary "radius". To get a bigger roundover to
print, just scale it up.
The value 1.5 of the second argument in cornerPatchCP correspond to scale
up the standard patch by 1.5.
To match the form factor of the border curves of  cornerPatchCP([0,0,0],1,
0.3) you may use the following standard patch CPs:

[[0, 1, 1]]

[[0, 1, 0.76], [0, 0.76, 1]]

[[0, 1, 0.28], [0, 0.7, 0.7], [0, 0.28, 1]]

[[0.28, 1, 0], [0, 0.55, 0], [0, 0, 0.55], [0.28, 0, 1]]

[[0.76, 1, 0], [0.7, 0.7, 0], [0.55, 0, 0], [0.7, 0, 0.7], [0.76, 0, 1]]

[[1, 1, 0], [1, 0.76, 0], [1, 0.28, 0], [1, 0, 0.28], [1, 0, 0.76], [1, 0,
1]]

That patch may be somewhat bulged when compared with a sphere, for
instance.

The best approximation I got of a sphere surface with a G2 tripatch has the
following CPs:

[[0, 1, 0.904], [0, 0.904, 1]]

[[0, 1, 0.352], [0, 0.88, 0.88], [0, 0.352, 1]]

[[0.352, 1, 0], [0, 0.52, 0], [0, 0, 0.52], [0.352, 0, 1]]

[[0.904, 1, 0], [0.88, 0.88, 0], [0.52, 0, 0], [0.88, 0, 0.88], [0.904, 0,
1]]

[[1, 1, 0], [1, 0.904, 0], [1, 0.352, 0], [1, 0, 0.352], [1, 0, 0.904], [1,
0, 1]]

whose border curves should match the border curves of cornerPatchCP([0,0,0],1,
0.12).

The second form factor I mentioned before does not affect the patch border
but controls the bulge of the patch. When we decrease its value, but
keeping the border curves fixed, the patch curvature varies very fast,
although continuously, near the patch border which may appear as a
discontinuity. Which means that the 3rd derivative near the border is
higher. Perhaps, that is the cause of the highlight behavior we observe in
your images. The last patch above seems to be a reasonable compromise.

adrianv <avm4@cornell.edu> wrote: > To use more precise language: There exists a direction from which the > highlight line on the model appears to have a corner (highlight has a > discontinuity in its derivative). This is visible in the photo I posted > in > my other message. I understand it now. In fact, the images suggest something odd in the border of the tripatch. See bellow. I generated my patch like this: > > Q = cornerPatchCP([0,0,0],1.5, 0.3); > > using the cornerPatchCP that you previously posted. I was comparing this > patch to the patch you originally posted, so the length of d disagrees, I > think. I can change the patch, but for print test a larger curve is > better. > The standard patch has a unitary "radius". To get a bigger roundover to print, just scale it up. The value 1.5 of the second argument in cornerPatchCP correspond to scale up the standard patch by 1.5. To match the form factor of the border curves of cornerPatchCP([0,0,0],1, 0.3) you may use the following standard patch CPs: [[0, 1, 1]] [[0, 1, 0.76], [0, 0.76, 1]] [[0, 1, 0.28], [0, 0.7, 0.7], [0, 0.28, 1]] [[0.28, 1, 0], [0, 0.55, 0], [0, 0, 0.55], [0.28, 0, 1]] [[0.76, 1, 0], [0.7, 0.7, 0], [0.55, 0, 0], [0.7, 0, 0.7], [0.76, 0, 1]] [[1, 1, 0], [1, 0.76, 0], [1, 0.28, 0], [1, 0, 0.28], [1, 0, 0.76], [1, 0, 1]] That patch may be somewhat bulged when compared with a sphere, for instance. The best approximation I got of a sphere surface with a G2 tripatch has the following CPs: [[0, 1, 0.904], [0, 0.904, 1]] [[0, 1, 0.352], [0, 0.88, 0.88], [0, 0.352, 1]] [[0.352, 1, 0], [0, 0.52, 0], [0, 0, 0.52], [0.352, 0, 1]] [[0.904, 1, 0], [0.88, 0.88, 0], [0.52, 0, 0], [0.88, 0, 0.88], [0.904, 0, 1]] [[1, 1, 0], [1, 0.904, 0], [1, 0.352, 0], [1, 0, 0.352], [1, 0, 0.904], [1, 0, 1]] whose border curves should match the border curves of cornerPatchCP([0,0,0],1, 0.12). The second form factor I mentioned before does not affect the patch border but controls the bulge of the patch. When we decrease its value, but keeping the border curves fixed, the patch curvature varies very fast, although continuously, near the patch border which may appear as a discontinuity. Which means that the 3rd derivative near the border is higher. Perhaps, that is the cause of the highlight behavior we observe in your images. The last patch above seems to be a reasonable compromise.
RP
Ronaldo Persiano
Wed, May 29, 2019 6:48 PM

I have bad news. The patches I have stated as G2 are just G1. I have found
a bug in my checkG2 function. I am sorry.

I have bad news. The patches I have stated as G2 are just G1. I have found a bug in my checkG2 function. I am sorry.
A
adrianv
Wed, May 29, 2019 9:08 PM

Does this mean you think a G2 patch does not exist?  Or just that it requires
different constraints?

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

Does this mean you think a G2 patch does not exist? Or just that it requires different constraints? -- Sent from: http://forum.openscad.org/
RP
Ronaldo Persiano
Thu, May 30, 2019 10:29 AM

It means there is no degree 5 G2 tripatch that meet the constraints. I am
still working on higher degrees.

Em qua, 29 de mai de 2019 às 22:08, adrianv avm4@cornell.edu escreveu:

Does this mean you think a G2 patch does not exist?  Or just that it
requires
different constraints?

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


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

It means there is no degree 5 G2 tripatch that meet the constraints. I am still working on higher degrees. Em qua, 29 de mai de 2019 às 22:08, adrianv <avm4@cornell.edu> escreveu: > Does this mean you think a G2 patch does not exist? Or just that it > requires > different constraints? > > > > > -- > 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
Sun, Mar 8, 2020 4:28 PM

I returned to the question of making continuous curvature rounded corners.
It seemed to me that the method Rinaldo showed using using a degenerate
square bezier patch of order 4 was the method that was known to be correct.
I am wondering about what exactly the general requirements are for making
this continuous curvature.  It seemed plausible that the edges of the patch
need to be orthogonal to the three edges and then it needs to meet the
requirement of having the form [p0, p0+k*(p1-p0),p1,p2+k*(p1-p2)] for every
column and row across the patch.

I implemented this using the code below where k1 and k2 are the curvature
parameter that can be different in the two directions.

function fillrow(row,k) =
[
row[0],
lerp(row[1],row[0],k),
row[1],
lerp(row[1],row[2],k),
row[2]
];

function lerp(a,b,u) =
is_num(u)? (1-u)a + ub :
[for (v = u) lerp(a,b,v)];

function bpts(plist,k1,k2) =
let(  k2 = is_undef(k2) ? k1: k2 )
fillrow([for(row=plist) fillrow(row,k1)], k2);

where bpts takes as input a 3x3 list of points giving the corner point, the
corners of the patch, and the centers of the patch along each edge.

Using this method I have created some examples that seem valid such as this
pentagonal prism:

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

and this L-shaped prism:

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

Now if I change the width of curvature of the top layer then I get this
pentagonal prism that I think seems also OK:

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

And here I can change the curvature parameter of the top compared to the
sides to get something like this one:

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

But if I change the curvature size for just one vertical edge, I'm not sure
the result is continuous curvature any more.  The top face is not no longer
a regular pentagon:

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

Another case is if I use pentagons of different scales, making a trucated
pyramid.  It looks like curvature is probably not continuous.

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

If I translate the top pentagon I get a result that is clearly bad:

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

And likewise if I skew the top pentagonal face in the z direction it seems
something is also wrong:

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

But it seems like all of these cases should have solutions.  Am I right
about that?  What are the general conditions that need to be satisfied for
putting C2 corners on a general prism object?

Note: if anybody wants to see the full code I'm happy to post it, but it
depends on BOSL2.

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

I returned to the question of making continuous curvature rounded corners. It seemed to me that the method Rinaldo showed using using a degenerate square bezier patch of order 4 was the method that was known to be correct. I am wondering about what exactly the general requirements are for making this continuous curvature. It seemed plausible that the edges of the patch need to be orthogonal to the three edges and then it needs to meet the requirement of having the form [p0, p0+k*(p1-p0),p1,p2+k*(p1-p2)] for every column and row across the patch. I implemented this using the code below where k1 and k2 are the curvature parameter that can be different in the two directions. function fillrow(row,k) = [ row[0], lerp(row[1],row[0],k), row[1], lerp(row[1],row[2],k), row[2] ]; function lerp(a,b,u) = is_num(u)? (1-u)*a + u*b : [for (v = u) lerp(a,b,v)]; function bpts(plist,k1,k2) = let( k2 = is_undef(k2) ? k1: k2 ) fillrow([for(row=plist) fillrow(row,k1)], k2); where bpts takes as input a 3x3 list of points giving the corner point, the corners of the patch, and the centers of the patch along each edge. Using this method I have created some examples that seem valid such as this pentagonal prism: <http://forum.openscad.org/file/t2477/pentagon1.png> and this L-shaped prism: <http://forum.openscad.org/file/t2477/Lprism.png> Now if I change the width of curvature of the top layer then I get this pentagonal prism that I think seems also OK: <http://forum.openscad.org/file/t2477/pentagon1a.png> And here I can change the curvature parameter of the top compared to the sides to get something like this one: <http://forum.openscad.org/file/t2477/pentagon2.png> But if I change the curvature size for just one vertical edge, I'm not sure the result is continuous curvature any more. The top face is not no longer a regular pentagon: <http://forum.openscad.org/file/t2477/pentagon3.png> Another case is if I use pentagons of different scales, making a trucated pyramid. It looks like curvature is probably not continuous. <http://forum.openscad.org/file/t2477/pentagon4.png> If I translate the top pentagon I get a result that is clearly bad: <http://forum.openscad.org/file/t2477/pentagon5.png> And likewise if I skew the top pentagonal face in the z direction it seems something is also wrong: <http://forum.openscad.org/file/t2477/pentagon6.png> But it seems like all of these cases should have solutions. Am I right about that? What are the general conditions that need to be satisfied for putting C2 corners on a general prism object? Note: if anybody wants to see the full code I'm happy to post it, but it depends on BOSL2. -- Sent from: http://forum.openscad.org/
RP
Ronaldo Persiano
Mon, Mar 9, 2020 8:56 PM

Very interesting line of research, Adrian. I had to review our previous
messages to answer some of your questions.

I would say that all your examples where the rounded edges have a
(non-circular) cylindrical shape satisfy the curvature continuity. Those
cases where the rounded edges have a conical shape are not even tangent
continuous. When the edges are cylindrical its transversal derivatives
(along the edge direction) have all the same value as happens with the
corner patch . That is not any longer true when the edges are conical.

Note that the corner patch is a degenerate quad patch so the value of one
of the parameters k will affect the shape of two patch borders but the
other will affect just one because the other border is collapsed to a
point. That is a consequence of the patch symmetry to just one plane and
not three. However, the second derivative at any point on the patch border
is zero for all values of k0 and k1 in [0,1].

Very interesting line of research, Adrian. I had to review our previous messages to answer some of your questions. I would say that all your examples where the rounded edges have a (non-circular) cylindrical shape satisfy the curvature continuity. Those cases where the rounded edges have a conical shape are not even tangent continuous. When the edges are cylindrical its transversal derivatives (along the edge direction) have all the same value as happens with the corner patch . That is not any longer true when the edges are conical. Note that the corner patch is a degenerate quad patch so the value of one of the parameters k will affect the shape of two patch borders but the other will affect just one because the other border is collapsed to a point. That is a consequence of the patch symmetry to just one plane and not three. However, the second derivative at any point on the patch border is zero for all values of k0 and k1 in [0,1].
A
adrianv
Tue, Mar 10, 2020 1:12 AM

I realized my main error.  I was constructing my corner patches so that they
were orthogonal to the edges.  But the requirement is instead that the patch
edges are parallel to the edges.  It's the same when the edges form 90 deg
corners, but different in the various other cases.  So things are looking
better, I think.  I believe that the requirement for C2 is that the first 3
of the five bezier points are collinear with the segment being rounded.  I
added to my code a check to confirm this property and hopefully therefore
identify cases where it has failed.

One case of failure is if I attempt to set a curvature size for a single
vertical edge.  The problem is that this setting affects the location of the
corner vertex (on the top of the surface) and leads to an inconsistency
there.  However, it appears OK to change the k parameter for a single
vertical edge:

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

It looks a little funny, which weakens my confidence but it meets the
collinearity condition.

The pyramid version now looks like this, and passes the collinearity tests:

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

When I skew the top I also pass the collinearity tests and get this result:

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

I also tried translating the top.  The result looks OK, but it is failing my
collinearity test.  I am trying to figure out what's going on (whether my
collinearity test is somehow broken, or what the reason for the failure is).

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

It seems to me that this technique should work for any solid created from
two n-gons with n coplanar quadrilateral faces between them.  I was trying
to figure out if I start with a coplanar polygon P, then under what
circumstances will the transformation T result in T(P) meeting these
requirements.

Regarding the k parameters, I believe I have the flexibility to set the k
parameter to a different value for each vertical edge, and then I can set
one value for the top and one value for the bottom, which will affect all of
the segments of the top and bottom face.

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

I realized my main error. I was constructing my corner patches so that they were orthogonal to the edges. But the requirement is instead that the patch edges are parallel to the edges. It's the same when the edges form 90 deg corners, but different in the various other cases. So things are looking better, I think. I believe that the requirement for C2 is that the first 3 of the five bezier points are collinear with the segment being rounded. I added to my code a check to confirm this property and hopefully therefore identify cases where it has failed. One case of failure is if I attempt to set a curvature size for a single vertical edge. The problem is that this setting affects the location of the corner vertex (on the top of the surface) and leads to an inconsistency there. However, it appears OK to change the k parameter for a single vertical edge: <http://forum.openscad.org/file/t2477/newpent1.png> It looks a little funny, which weakens my confidence but it meets the collinearity condition. The pyramid version now looks like this, and passes the collinearity tests: <http://forum.openscad.org/file/t2477/newpent2.png> When I skew the top I also pass the collinearity tests and get this result: <http://forum.openscad.org/file/t2477/newpent3.png> I also tried translating the top. The result looks OK, but it is failing my collinearity test. I am trying to figure out what's going on (whether my collinearity test is somehow broken, or what the reason for the failure is). <http://forum.openscad.org/file/t2477/newpent4.png> It seems to me that this technique should work for any solid created from two n-gons with n coplanar quadrilateral faces between them. I was trying to figure out if I start with a coplanar polygon P, then under what circumstances will the transformation T result in T(P) meeting these requirements. Regarding the k parameters, I believe I have the flexibility to set the k parameter to a different value for each vertical edge, and then I can set one value for the top and one value for the bottom, which will affect all of the segments of the top and bottom face. -- Sent from: http://forum.openscad.org/
R
Ronaldo
Tue, Mar 10, 2020 6:59 PM

Yes, the collinearity condition you checked is what supports the zero
transversal curvature at the patch borders. The patch was designed with that
in mind. You can see it by drawing the patch control point mesh.

Patches&meshes.PNG
http://forum.openscad.org/file/t1275/Patches%26meshes.PNG

One case of failure is if I attempt to set a curvature size for a single
vertical edge.  The problem is that this setting affects the location of
the
corner vertex (on the top of the surface) and leads to an inconsistency
there.

What kind of inconsistency? The three vertices of the patch should be
independent of the values of k1 and k2. In your bpts() function they depend
only on the input plist. If the plist is consistent at every polyhedron
vertex I would expect no inconsistency on the top of the surface. Here is an
example of a skewed rhombus extrusion where just one edge has a k1=0.2 and
k2= 0.8 and the others have both equal to 0.2:

SkewdRhombusExtrusion.PNG
http://forum.openscad.org/file/t1275/SkewdRhombusExtrusion.PNG

I also tried translating the top.  The result looks OK, but it is failing
my
collinearity test.  I am trying to figure out what's going on (whether my
collinearity test is somehow broken, or what the reason for the failure
is).

I would say that it should have some bug in your code for that case. Here
are the CP of the corner patch of the distinct upper corner of the previous
image:

CornerCP.PNG http://forum.openscad.org/file/t1275/CornerCP.PNG

It may help to note that a Bezier patch is an affine function of its control
points. That means the affine transform of a patch equals the patch of the
affine transform of its control points. Therefore, all patches with a given
pair of k1 and k2 are affine transforms of a unitary patch like that:

function ubpts(k1,k2) =
let(  k2 = is_undef(k2) ? k1: k2 )
let( dx = [1,0,0], dy = [0,1,0], dz=[0,0,1] )
let( plist= [ [dx+dz, dz, dy+dz], [dx, [0,0,0], dy],[dx+dy, dx+dy, dx+dy]
] )
fillrow([for(row=plist) fillrow(row,k1)], k2);

As a consequence, you may evaluate points in the unitary patch for each pair
(k1,k2) and do an affine transform of those points to each specific corner
of the polyhedron.

Regarding the k parameters, I believe I have the flexibility to set the k
parameter to a different value for each vertical edge, and then I can set
one value for the top and one value for the bottom, which will affect all
of
the segments of the top and bottom face.

In a more general setting, you can assign a different k value for each edge
of the polyhedron (convex or not) provided that the (exactly) three incoming
edges at each vertex have at most two different k values.

It seems to me that this technique should work for any solid created from
two n-gons with n coplanar quadrilateral faces between them.  I was trying
to figure out if I start with a coplanar polygon P, then under what
circumstances will the transformation T result in T(P) meeting these
requirements.

Not only. The polyhedron faces may have any number of vertices. For
instance, you could do it with a tetrahedron using equal values of k at the
top vertex and two values of k at the base vertices. As I said before, the
only conditions are: exactly 3 edges meet at a corner and no more then 2
values of k are used by the edges meeting at a vertex.

Although its flexibility, it would be hard to specify such a varying edge
roundness. We can imagine that the input to such a function is the polyset
of the polyhedron, its [verts,faces] representation, with an output in the
same format. But it is hard to check that a polyset represents a valid
polyhedron (even harder to check if it has self-intersections) because there
is a lack of topological information in that representation. To build the
rounded polyhedron you need essentially the table of the adjacent vertices
to each vertex and that table requires a procedure that grows very fast with
the number of vertices (O(n2) ?). I have implemented that and it is useful
for at most something around a hundred vertices which would be acceptable to
a (itself expensive) rounding process.

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

Yes, the collinearity condition you checked is what supports the zero transversal curvature at the patch borders. The patch was designed with that in mind. You can see it by drawing the patch control point mesh. Patches&meshes.PNG <http://forum.openscad.org/file/t1275/Patches%26meshes.PNG> > One case of failure is if I attempt to set a curvature size for a single > vertical edge. The problem is that this setting affects the location of > the > corner vertex (on the top of the surface) and leads to an inconsistency > there. What kind of inconsistency? The three vertices of the patch should be independent of the values of k1 and k2. In your bpts() function they depend only on the input plist. If the plist is consistent at every polyhedron vertex I would expect no inconsistency on the top of the surface. Here is an example of a skewed rhombus extrusion where just one edge has a k1=0.2 and k2= 0.8 and the others have both equal to 0.2: SkewdRhombusExtrusion.PNG <http://forum.openscad.org/file/t1275/SkewdRhombusExtrusion.PNG> > I also tried translating the top. The result looks OK, but it is failing > my > collinearity test. I am trying to figure out what's going on (whether my > collinearity test is somehow broken, or what the reason for the failure > is). I would say that it should have some bug in your code for that case. Here are the CP of the corner patch of the distinct upper corner of the previous image: CornerCP.PNG <http://forum.openscad.org/file/t1275/CornerCP.PNG> It may help to note that a Bezier patch is an affine function of its control points. That means the affine transform of a patch equals the patch of the affine transform of its control points. Therefore, all patches with a given pair of k1 and k2 are affine transforms of a unitary patch like that: function ubpts(k1,k2) = let( k2 = is_undef(k2) ? k1: k2 ) let( dx = [1,0,0], dy = [0,1,0], dz=[0,0,1] ) let( plist= [ [dx+dz, dz, dy+dz], [dx, [0,0,0], dy],[dx+dy, dx+dy, dx+dy] ] ) fillrow([for(row=plist) fillrow(row,k1)], k2); As a consequence, you may evaluate points in the unitary patch for each pair (k1,k2) and do an affine transform of those points to each specific corner of the polyhedron. > Regarding the k parameters, I believe I have the flexibility to set the k > parameter to a different value for each vertical edge, and then I can set > one value for the top and one value for the bottom, which will affect all > of > the segments of the top and bottom face. In a more general setting, you can assign a different k value for each edge of the polyhedron (convex or not) provided that the (exactly) three incoming edges at each vertex have at most two different k values. > It seems to me that this technique should work for any solid created from > two n-gons with n coplanar quadrilateral faces between them. I was trying > to figure out if I start with a coplanar polygon P, then under what > circumstances will the transformation T result in T(P) meeting these > requirements. Not only. The polyhedron faces may have any number of vertices. For instance, you could do it with a tetrahedron using equal values of k at the top vertex and two values of k at the base vertices. As I said before, the only conditions are: exactly 3 edges meet at a corner and no more then 2 values of k are used by the edges meeting at a vertex. Although its flexibility, it would be hard to specify such a varying edge roundness. We can imagine that the input to such a function is the polyset of the polyhedron, its [verts,faces] representation, with an output in the same format. But it is hard to check that a polyset represents a valid polyhedron (even harder to check if it has self-intersections) because there is a lack of topological information in that representation. To build the rounded polyhedron you need essentially the table of the adjacent vertices to each vertex and that table requires a procedure that grows very fast with the number of vertices (O(n2) ?). I have implemented that and it is useful for at most something around a hundred vertices which would be acceptable to a (itself expensive) rounding process. -- Sent from: http://forum.openscad.org/
A
adrianv
Tue, Mar 10, 2020 9:53 PM

As I pondered a little more what was going on I realized that the chain of
assumptions leaves the "top" part of the patch (around the degenerate
corner) completely defined, and possibly with different k values than used
elsewhere.  The parameters weren't as free as I was thinking.  This follows
from enforcing collinearity.

Restricting to the case of prism-like polyhedra for simplicity, consider the
following requirements:  I want to specify a rounding scale and k for each
vertical edge (possibly different).  Rounding will be symmetric at each such
edge.  At the top and bottom I also specify a rounding scale and k.

What does this require?  If at a given edge the desired edge rounding is r_e
and the top rounding is r_t then this determines the position of the bottom
corners of the patch.  You need to move in the orthogonal direction away
from the edge by distance r_t, which means r_t/sin(theta) where theta is the
angle of the side face at the corner.  This means the distance you move is
different in the two directions if the faces have a different angle.  The
distance down from the corner is determined by the angle the edge makes with
the plane of the top face according to a similar formula.    Once these
points are established you can fill in all the lower half points in the
patch using the two k values, one for the vertical direction and another for
the horizontal direction.

So what about the remaining points in the patch?  Well, there is where
things get complicated.  Because everything that remains is already forced.
This was not obvious to me.  To find the corner point at the top you need to
take the intersection of the lines from the next and previous corners.  And
the k value is not free for this top section.  It must be chosen in a
similar fashion as an intersection of lines defined by points already
chosen.  It will not match the two chosen k values in general.  So for the
case of the translated top that was my problem.  And similarly if I the
roundover size varies then the location of these point intersections shift
around and you cannot determine the position without reference to the two
adjacent points in the top face.

Now this all said, there is a completely different way of specifying the
rounding that has some merit and would probably be the only way to handle
rounding of a generic polyhedron whose vertices all have degree 3.  Instead
of specifying the rounding based on edges, specify it based on faces.  This
method is much cleaner mathematically.  For a given face, pick a rounding
length and k value.  Find the plane that is shifted inward by that distance.
Repeat for all faces of the polyhedron.  The intersection of points of all
the resulting planes defines all of the patches in a manner which will
obviously be collinear.      This means that a given edge will have
asymmetric rounding, with one value on one side and a (possibly) different
value on the other side.

I'm not sure I believe that the patches that result, especially from the
first procedure, are in fact an affine transformation of the master patch,
given the need to choose special k values for the top part.  There is
another case I think you may have overlooked, which is the concave corner
case.  The patch for this case is non-degenerate, and also has to be defined
with reference to the adjacent points.

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

As I pondered a little more what was going on I realized that the chain of assumptions leaves the "top" part of the patch (around the degenerate corner) completely defined, and possibly with different k values than used elsewhere. The parameters weren't as free as I was thinking. This follows from enforcing collinearity. Restricting to the case of prism-like polyhedra for simplicity, consider the following requirements: I want to specify a rounding scale and k for each vertical edge (possibly different). Rounding will be symmetric at each such edge. At the top and bottom I also specify a rounding scale and k. What does this require? If at a given edge the desired edge rounding is r_e and the top rounding is r_t then this determines the position of the bottom corners of the patch. You need to move in the orthogonal direction away from the edge by distance r_t, which means r_t/sin(theta) where theta is the angle of the side face at the corner. This means the distance you move is different in the two directions if the faces have a different angle. The distance down from the corner is determined by the angle the edge makes with the plane of the top face according to a similar formula. Once these points are established you can fill in all the lower half points in the patch using the two k values, one for the vertical direction and another for the horizontal direction. So what about the remaining points in the patch? Well, there is where things get complicated. Because everything that remains is already forced. This was not obvious to me. To find the corner point at the top you need to take the intersection of the lines from the next and previous corners. And the k value is not free for this top section. It must be chosen in a similar fashion as an intersection of lines defined by points already chosen. It will *not* match the two chosen k values in general. So for the case of the translated top that was my problem. And similarly if I the roundover size varies then the location of these point intersections shift around and you cannot determine the position without reference to the two adjacent points in the top face. Now this all said, there is a completely different way of specifying the rounding that has some merit and would probably be the only way to handle rounding of a generic polyhedron whose vertices all have degree 3. Instead of specifying the rounding based on edges, specify it based on faces. This method is much cleaner mathematically. For a given face, pick a rounding length and k value. Find the plane that is shifted inward by that distance. Repeat for all faces of the polyhedron. The intersection of points of all the resulting planes defines all of the patches in a manner which will obviously be collinear. This means that a given edge will have asymmetric rounding, with one value on one side and a (possibly) different value on the other side. I'm not sure I believe that the patches that result, especially from the first procedure, are in fact an affine transformation of the master patch, given the need to choose special k values for the top part. There is another case I think you may have overlooked, which is the concave corner case. The patch for this case is non-degenerate, and also has to be defined with reference to the adjacent points. -- Sent from: http://forum.openscad.org/
RP
Ronaldo Persiano
Wed, Mar 11, 2020 12:18 PM

I think, Adrian, our talk is becoming too much technical and specific for
the audience of this forum.  Perhaps we should continue it in private
messages allowing those who manifest to be interested in the topic to join
us. I can create a Google group if necessary.

Anyway, here are some comments about your last message. I agree with the
method of defining a rounding scale in a face basis. It is relatively
simple to deal with and it seems to meet the curvature continuity
condition. It would be comparable with the method of rounding edges with
elliptical arcs instead of circular arcs.

I understand the method in a equivalent but slight different way. Given a
rounding scale for each face, consider the vertices of the negative
offset of the face by the amount of its scale. You will have one offset
vertex near to a vertex for each face-vertex adjacency . Take the 3 offset
vertices of the adjacent faces of a vertex and use them to build a patch
for that vertex. The setting of the k's may be chosen
independently provided that it is the same value at the two extremes of an
edge. The effect of the k's would be far less dramatic than the rounding
scale. I have made some experiments with that method and it seems to
satisfy all requirements. I think this method might be used even with
non-prismatic polyhedra.

Non-convex vertices is a topic for another message.

I think, Adrian, our talk is becoming too much technical and specific for the audience of this forum. Perhaps we should continue it in private messages allowing those who manifest to be interested in the topic to join us. I can create a Google group if necessary. Anyway, here are some comments about your last message. I agree with the method of defining a rounding scale in a face basis. It is relatively simple to deal with and it seems to meet the curvature continuity condition. It would be comparable with the method of rounding edges with elliptical arcs instead of circular arcs. I understand the method in a equivalent but slight different way. Given a rounding scale for each face, consider the vertices of the negative offset of the face by the amount of its scale. You will have one offset vertex near to a vertex for each face-vertex adjacency . Take the 3 offset vertices of the adjacent faces of a vertex and use them to build a patch for that vertex. The setting of the k's may be chosen independently provided that it is the same value at the two extremes of an edge. The effect of the k's would be far less dramatic than the rounding scale. I have made some experiments with that method and it seems to satisfy all requirements. I think this method might be used even with non-prismatic polyhedra. Non-convex vertices is a topic for another message.
I
irevdev
Sat, Aug 15, 2020 11:12 AM

Hey adrianv,

I'm definitely up for cleaning up the interface. Sorry I'm very late to this
reply. If you wanted to open up some issues on github we could work through
them.

Would definitely be good to get things as intuitive as possible. I
definitely could improve it myself, but also perhaps I'm too close to the
code and find it harder to step back and think about it wholistically so if
you willing to help out, that would be great.

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

Hey adrianv, I'm definitely up for cleaning up the interface. Sorry I'm very late to this reply. If you wanted to open up some issues on github we could work through them. Would definitely be good to get things as intuitive as possible. I definitely could improve it myself, but also perhaps I'm too close to the code and find it harder to step back and think about it wholistically so if you willing to help out, that would be great. -- Sent from: http://forum.openscad.org/
A
adrianv
Sat, Aug 15, 2020 12:11 PM

I have to admit that since I wrote my own rounding library for BOSL2

https://github.com/revarbat/BOSL2/wiki/rounding.scad

I'm less interested in trying to figure out how to improve another library.
And I have my own issues in trying to simplify the API of some pretty
complicated functions I wrote.  But I'd be very interested in a general
conversation about rounding, what kinds of rounding would be useful that
don't (seem to) exist yet, or how we can do rounding better.

One function I want to write but haven't figured out how to write because I
can't define its behavior well enough is a rounded path join:  a function
that takes a list of paths with rounding parameters and joints the paths
together with rounding, even when the required roundover is bigger than one
segment of the path.  (I already did something like this for my
offset_stroke method, which will add roundings to the end that are larger
than one segment of the path.)  The problem is I am not sure how to specify
the rounding between two paths when the rounding gets large.  The basic idea
would be to have a cut size or radius and to track back along the paths to
try to find a way to achieve it, but if the path wiggles a lot, this can
fail in some strange ways.

One API issue is how to specify the size of roundovers, and when I
implemented continuous curvature rounding, which doesn't have a "radius", I
realized that radius is often not very intuitive.  Especially for sharp
pointing corners, radius is hard to understand intuitively.  I introduced
the "cut" distance to measure the size of a roundover:  this is basically
how much of the corner is cut off by the rounding process.  Another API
issue I ran into with round_corners was specifying the rounding size as an
extra point on the coordinate list:  this turned out to complicate my API
and was basically never useful.  I also ended up deciding that decreasing
the user specified roundings when they conflict wasn't the best interface
idea, because then the user doesn't know what actually happened, and it's
hard to tweak the result.  I might, for example, want more rounding, not
realize it's impossible, and get frustrated trying to increase values and
get no change.  (I suppose a warning message could help in this case.)  I
decided it was better to optionally display information that would help the
user find a nonconflicting set of roundings.

OpenSCAD mailing list-2 wrote

Hey adrianv,

I'm definitely up for cleaning up the interface. Sorry I'm very late to
this
reply. If you wanted to open up some issues on github we could work
through
them.

I have to admit that since I wrote my own rounding library for BOSL2 https://github.com/revarbat/BOSL2/wiki/rounding.scad I'm less interested in trying to figure out how to improve another library. And I have my own issues in trying to simplify the API of some pretty complicated functions I wrote. But I'd be very interested in a general conversation about rounding, what kinds of rounding would be useful that don't (seem to) exist yet, or how we can do rounding better. One function I want to write but haven't figured out how to write because I can't define its behavior well enough is a rounded path join: a function that takes a list of paths with rounding parameters and joints the paths together with rounding, even when the required roundover is bigger than one segment of the path. (I already did something like this for my offset_stroke method, which will add roundings to the end that are larger than one segment of the path.) The problem is I am not sure how to specify the rounding between two paths when the rounding gets large. The basic idea would be to have a cut size or radius and to track back along the paths to try to find a way to achieve it, but if the path wiggles a lot, this can fail in some strange ways. One API issue is how to specify the size of roundovers, and when I implemented continuous curvature rounding, which doesn't have a "radius", I realized that radius is often not very intuitive. Especially for sharp pointing corners, radius is hard to understand intuitively. I introduced the "cut" distance to measure the size of a roundover: this is basically how much of the corner is cut off by the rounding process. Another API issue I ran into with round_corners was specifying the rounding size as an extra point on the coordinate list: this turned out to complicate my API and was basically never useful. I also ended up deciding that decreasing the user specified roundings when they conflict wasn't the best interface idea, because then the user doesn't know what actually happened, and it's hard to tweak the result. I might, for example, want more rounding, not realize it's impossible, and get frustrated trying to increase values and get no change. (I suppose a warning message could help in this case.) I decided it was better to optionally display information that would help the user find a nonconflicting set of roundings. OpenSCAD mailing list-2 wrote > Hey adrianv, > > I'm definitely up for cleaning up the interface. Sorry I'm very late to > this > reply. If you wanted to open up some issues on github we could work > through > them. -- Sent from: http://forum.openscad.org/
I
irevdev
Sat, Aug 15, 2020 10:52 PM

I completely understand not wanting to improve another library.

I'm finding it difficult to visualise your joining path problem sorry.

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

I completely understand not wanting to improve another library. I'm finding it difficult to visualise your joining path problem sorry. -- Sent from: http://forum.openscad.org/