Rounded Polygon

classic Classic list List threaded Threaded
172 messages Options
123456 ... 9
rew
Reply | Threaded
Open this post in threaded view
|

Re: Rounded Polygon

rew
Hi,

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

        Roger.

--
** [hidden email] ** 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
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

bezier_3d.png (28K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Rounded Polygon

Ronaldo
In reply to this post by adrianv


adrianv <[hidden email]> 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:

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
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: Rounded Polygon

thehans
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 <[hidden email]> wrote:


adrianv <[hidden email]> 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:

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
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

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

Re: Rounded Polygon

adrianv
In reply to this post by Ronaldo
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
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: Rounded Polygon

thehans
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 :


On Thu, Mar 14, 2019 at 5:03 PM adrianv <[hidden email]> 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
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

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

Re: Rounded Polygon

Ronaldo
In reply to this post by adrianv
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
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

nonConvexCase.PNG (8K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Rounded Polygon

nophead
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 <[hidden email]> 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
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

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

Re: Rounded Polygon

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


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.

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

Re: Rounded Polygon

Parkinbot
In reply to this post by nophead
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/

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

Re: Rounded Polygon

Gadgetmind
In reply to this post by Ronaldo
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
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: Rounded Polygon

nophead
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 <[hidden email]> 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
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

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

Re: Rounded Polygon

cacb
In reply to this post by Gadgetmind
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

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

Re: Rounded Polygon

adrianv
In reply to this post by nophead
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/

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

Re: Rounded Polygon

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

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

Re: Rounded Polygon

adrianv
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/

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

Re: Rounded Polygon

adrianv
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/

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

Re: Rounded Polygon

adrianv
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/

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

Re: Rounded Polygon

adrianv
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/

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

Re: Rounded Polygon

Ronaldo
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 <[hidden email]> 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. 

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

Re: Rounded Polygon

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




Sent from the OpenSCAD mailing list archive at Nabble.com.

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
123456 ... 9