Rounded Polygon

classic Classic list List threaded Threaded
16 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Rounded Polygon

irevdev
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.



code here

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).
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Rounded Polygon

TLC123
Oh Yes this will be used extensively , i assure you.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Rounded Polygon

irevdev
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.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Rounded Polygon

TLC123
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:
CentreN2PointsArc(t12,t23,cen,CWorCCW,fn); 
for:

//Oc test can be done before all the calculations but  i made it as a singel copy/paste drop in chunk
    dot(un(p1-p2),(p2-p3))>0.98? // if p1,p2,p3 are more collinar than 0.98
[p1,p2,p3] // then return points as is
 : CentreN2PointsArc(t12,t23,cen,CWorCCW,fn); // else return the normal thing

//fix using functions 
function dot (a,b)=a*b; // dot product is implied in * of vectors
function un(v)=v/max(norm(v),1e-16);// div by zero safe unit normal


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.

module test()
{
p=[for(i=[0:10])[rnd(0,100),rnd(0,100),rnd(0,10)]];
po=[for(i=[0:len(p)-1])[p[i].x,p[i].y]];
pr=[for(i=[0:len(p)-1])p[i][2]];
R=polyRound(po,pr,3);
 polygon(R);

}

function rnd(a = 1, b = 0, s = []) = 
  s == [] ? 
   (rands(min(a, b), max(   a, b), 1)[0]) 
  : 
   (rands(min(a, b), max(a, b), 1, s)[0])
  ; 

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Rounded Polygon

irevdev
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:
CentreN2PointsArc(t12,t23,cen,CWorCCW,fn); 
for:

//Oc test can be done before all the calculations but  i made it as a singel copy/paste drop in chunk
    dot(un(p1-p2),(p2-p3))>0.98? // if p1,p2,p3 are more collinar than 0.98
[p1,p2,p3] // then return points as is
 : CentreN2PointsArc(t12,t23,cen,CWorCCW,fn); // else return the normal thing
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.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Rounded Polygon

droftarts
In reply to this post by TLC123
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). 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

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Rounded Polygon

droftarts
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
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Rounded Polygon

KeithSloan52
This post was updated on .
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.

4) offset should work as of FreeCAD 0.17

So if you have problems then please try the latest 0.17 version and if still, problems please report in the FreeCAD forum.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Rounded Polygon

irevdev
In reply to this post by droftarts
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.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Rounded Polygon

droftarts
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
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Rounded Polygon

Ronaldo
In reply to this post by TLC123
2017-07-23 5:21 GMT-03:00 TLC123 <[hidden email]>:
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.

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Rounded Polygon

Parkinbot
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;
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Rounded Polygon

TLC123
In reply to this post by irevdev
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
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Rounded Polygon

Parkinbot
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?
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Rounded Polygon

TLC123
Report what radius have been corrected by how much and have a
option to autofix or not?
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Rounded Polygon

irevdev
This post was updated on .
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
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.

The radii conflict handling works by reducing two conflicting radii by a factor, this means that the two will keep their 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.

Not sure how well that image will turn out, here is a link for it
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 know if any of the radii have been reduced because of a conflict. see some of the examples.
Loading...