discuss@lists.openscad.org

OpenSCAD general discussion Mailing-list

View all threads

Rounded Polygon

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/