discuss@lists.openscad.org

OpenSCAD general discussion Mailing-list

View all threads

$fn and arcs

AM
Adrian Mariano
Sun, Aug 24, 2025 11:08 PM

Cory did quote links to the code.

Your analysis assumes you can do regular arithmetic on epsilon, which I
think is suspect if epsilon is machine precision, since every computational
step has the potential to introduce error on the order of epsilon---in
either direction.  In fact it appears that only by subtracting epsilon at
the end do you guarantee that you're not subject to subsequent rounding
error that makes the value too large.

In the helix() function in fact angle can be arbitrarily large, as the
helix may have many turns.

On Sun, Aug 24, 2025 at 6:46 PM Cory Cross openscad@corycross.org wrote:

On 8/22/25 3:28 PM, Adrian Mariano via Discuss wrote:

Why would it matter if n>360?  I don't see that it makes a difference if
you subtract epsilon from angle or from the whole expression.  I did the
latter because it was simpler.

So the error is in angle, and it's multiplied by n/360. We're assuming
the error is as much as epsilon, so subtracting at the end:

n*(angle+epsilon)/360 - epsilon
nangle/360 + epsilonn/360 - epsilon

so if n=720 we're still epsilon too much, and if (n*angle/360) is an
integer, the final result will round up to the next higher integer.

versus subtracting at angle:

n*(angle+epsilon-epsilon)/360
n*angle/360

independent of n when error==epsilon (which we're assuming). If it's
actually less than epsilon:

nangle/360 - epsilonn/360

That will only cause a different result if n*angle/360 was slightly more
than a whole number, which will never (for any sane measurements) be the
case when you are choosing some fraction of $fn arc, and only arose in
freak coincidences in existing code.

  • Cory Cross

On Fri, Aug 22, 2025 at 4:38 PM Cory Cross via Discuss <
discuss@lists.openscad.org> wrote:

On August 21, 2025 2:02:00 PM EDT, Adrian Mariano via Discuss <
discuss@lists.openscad.org> wrote:

Representability as a double is not sufficient. You have to also compute
that representation. Since arccos is involved this is not guaranteed.  I
see issues with n of 5, 6 and 8 which have integer angles of 72, 60 and
45.  It works for n of 3 and 12.

Oops, I inverted the equation. (n * arc_angle / 360) of course. Okay, so
a trigonometric function is calculating the angle and returning 72+epsilon
(or more!? hope not), so just subtracting epsilon from the whole equation
won't always work when n>360, so it should be taken from the angle.

  • Cory

Subtracting epsilon before the ceil seems ok and of course does fix it.

On Thu, Aug 21, 2025 at 13:30 Cory Cross via Discuss <
discuss@lists.openscad.org> wrote:

I think the cause is when either angle or 360/(n*arc_angle) isn't
perfectly representable by a double.

I think the best solution is to subtract epsilon before calling ceil. I
haven't thought of any situation this is worse, especially given n is

never

less than 3.

On August 21, 2025 10:45:52 AM EDT, Marius Kintel via Discuss <
discuss@lists.openscad.org> wrote:

In C++, OpenSCAD converts n to int first before doing the arc angle

calculation. That may introduce a tiny difference, as if you do the

same

calculation in OpenSCAD, it’s kept as double all the way. Not sure if
that’s the root cause though..

If I'm remembering my numerical methods lessons correctly, I don't

think

that's the reason, as the code correctly multiplies n*arc_angle first,
which will always be less than the maximum representable integer in a
double (for any reasonable n), so it will exact if the angle is
representable as a double.

  • Cory Cross

-Marius

On Aug 21, 2025, at 10:22, Adrian Mariano via Discuss <

Thanks.  The possibility of rounding error exists in the

computation.

Someone observed in BOSL2 that offset behaved irregularly.  The

existing

calculation does not match openscad but even with it fixed if I offset

a

regular n gon with $fn = n I get rounding errors and sometimes the ceil
rounds up giving an extra facet. Openscad seems to avoid this somehow

and

consistently produces just a single facet.

On Thu, Aug 21, 2025 at 09:43 Cory Cross via Discuss <

At least in DxfData:

       n = static_cast<int>(ceil(n * arc_angle / 360));

where n comes from

       int n = Calc::get_fragments_from_r(radius, fn, fs, fa);

which returns $fn so long as it's at least 3: <

<

Sorry for non-permalinks.

On August 21, 2025 8:18:44 AM EDT, Adrian Mariano via Discuss <

Does anybody know the calculation openscad uses for the number of

segments on an arc of angle theta as a function of $fn?  Exactly what

kind

of rounding is used?


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

Cory did quote links to the code. Your analysis assumes you can do regular arithmetic on epsilon, which I think is suspect if epsilon is machine precision, since every computational step has the potential to introduce error on the order of epsilon---in either direction. In fact it appears that only by subtracting epsilon at the end do you guarantee that you're not subject to subsequent rounding error that makes the value too large. In the helix() function in fact angle can be arbitrarily large, as the helix may have many turns. On Sun, Aug 24, 2025 at 6:46 PM Cory Cross <openscad@corycross.org> wrote: > On 8/22/25 3:28 PM, Adrian Mariano via Discuss wrote: > > Why would it matter if n>360? I don't see that it makes a difference if > you subtract epsilon from angle or from the whole expression. I did the > latter because it was simpler. > > > So the error is in `angle`, and it's multiplied by n/360. We're assuming > the error is as much as epsilon, so subtracting at the end: > > n*(angle+epsilon)/360 - epsilon > n*angle/360 + epsilon*n/360 - epsilon > > so if n=720 we're still epsilon too much, and if (n*angle/360) is an > integer, the final result will round up to the next higher integer. > > versus subtracting at angle: > > n*(angle+epsilon-epsilon)/360 > n*angle/360 > > independent of n when error==epsilon (which we're assuming). If it's > actually less than epsilon: > > n*angle/360 - epsilon*n/360 > > That will only cause a different result if n*angle/360 was slightly more > than a whole number, which will never (for any sane measurements) be the > case when you are choosing some fraction of $fn arc, and only arose in > freak coincidences in existing code. > > - Cory Cross > > > On Fri, Aug 22, 2025 at 4:38 PM Cory Cross via Discuss < > discuss@lists.openscad.org> wrote: > >> >> >> On August 21, 2025 2:02:00 PM EDT, Adrian Mariano via Discuss < >> discuss@lists.openscad.org> wrote: >> >Representability as a double is not sufficient. You have to also compute >> >that representation. Since arccos is involved this is not guaranteed. I >> >see issues with n of 5, 6 and 8 which have integer angles of 72, 60 and >> >45. It works for n of 3 and 12. >> >> Oops, I inverted the equation. (n * arc_angle / 360) of course. Okay, so >> a trigonometric function is calculating the angle and returning 72+epsilon >> (or more!? hope not), so just subtracting epsilon from the whole equation >> won't always work when n>360, so it should be taken from the angle. >> >> - Cory >> >> >> > >> >Subtracting epsilon before the ceil seems ok and of course does fix it. >> > >> >On Thu, Aug 21, 2025 at 13:30 Cory Cross via Discuss < >> >discuss@lists.openscad.org> wrote: >> > >> >> I think the cause is when either angle or 360/(n*arc_angle) isn't >> >> perfectly representable by a double. >> >> >> >> I think the best solution is to subtract epsilon before calling ceil. I >> >> haven't thought of any situation this is worse, especially given n is >> never >> >> less than 3. >> >> >> >> >> >> >> >> On August 21, 2025 10:45:52 AM EDT, Marius Kintel via Discuss < >> >> discuss@lists.openscad.org> wrote: >> >> >In C++, OpenSCAD converts n to int first before doing the arc angle >> >> calculation. That may introduce a tiny difference, as if you do the >> same >> >> calculation in OpenSCAD, it’s kept as double all the way. Not sure if >> >> that’s the root cause though.. >> >> >> >> If I'm remembering my numerical methods lessons correctly, I don't >> think >> >> that's the reason, as the code correctly multiplies n*arc_angle first, >> >> which will always be less than the maximum representable integer in a >> >> double (for any reasonable n), so it will exact if the angle is >> >> representable as a double. >> >> >> >> - Cory Cross >> >> >> >> >> >> >> >> >> >> > >> >> > -Marius >> >> > >> >> >> On Aug 21, 2025, at 10:22, Adrian Mariano via Discuss < >> >> discuss@lists.openscad.org> wrote: >> >> >> >> >> >> Thanks. The possibility of rounding error exists in the >> computation. >> >> Someone observed in BOSL2 that offset behaved irregularly. The >> existing >> >> calculation does not match openscad but even with it fixed if I offset >> a >> >> regular n gon with $fn = n I get rounding errors and sometimes the ceil >> >> rounds up giving an extra facet. Openscad seems to avoid this somehow >> and >> >> consistently produces just a single facet. >> >> >> >> >> >> On Thu, Aug 21, 2025 at 09:43 Cory Cross via Discuss < >> >> discuss@lists.openscad.org <mailto:discuss@lists.openscad.org>> wrote: >> >> >>> At least in DxfData: >> >> >>> >> >> >>> n = static_cast<int>(ceil(n * arc_angle / 360)); >> >> >>> >> >> >>> where n comes from >> >> >>> >> >> >>> int n = Calc::get_fragments_from_r(radius, fn, fs, fa); >> >> >>> >> >> >>> which returns $fn so long as it's at least 3: < >> >> >> https://github.com/openscad/openscad/blob/master/src%2Futils%2Fcalc.cc#L47 >> >> > >> >> >>> >> >> >>> < >> >> >> https://github.com/openscad/openscad/blob/master/src%2Fio%2FDxfData.cc#L205 >> >> > >> >> >>> >> >> >>> Sorry for non-permalinks. >> >> >>> >> >> >>> >> >> >>> On August 21, 2025 8:18:44 AM EDT, Adrian Mariano via Discuss < >> >> discuss@lists.openscad.org <mailto:discuss@lists.openscad.org>> wrote: >> >> >>>> Does anybody know the calculation openscad uses for the number of >> >> segments on an arc of angle theta as a function of $fn? Exactly what >> kind >> >> of rounding is used? >> >> >>> _______________________________________________ >> >> >>> OpenSCAD mailing list >> >> >>> To unsubscribe send an email to discuss-leave@lists.openscad.org >> >> <mailto:discuss-leave@lists.openscad.org >> >> >_______________________________________________ >> >> >> OpenSCAD mailing list >> >> >> To unsubscribe send an email to discuss-leave@lists.openscad.org >> >> > >> >> _______________________________________________ >> >> OpenSCAD mailing list >> >> To unsubscribe send an email to discuss-leave@lists.openscad.org >> _______________________________________________ >> OpenSCAD mailing list >> To unsubscribe send an email to discuss-leave@lists.openscad.org > > > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org > > >
CC
Cory Cross
Mon, Aug 25, 2025 12:03 AM

On 8/24/25 4:08 PM, Adrian Mariano via Discuss wrote:

Cory did quote links to the code.

Your analysis assumes you can do regular arithmetic on epsilon, which
I think is suspect if epsilon is machine precision, since every
computational step has the potential to introduce error on the order
of epsilon---in either direction.   In fact it appears that only by
subtracting epsilon at the end do you guarantee that you're not
subject to subsequent rounding error that makes the value too large.

Okay, let's assume we're exactly one epsilon too large, see if my Python
is correct. Some lines truncated

for n in range(40,60):

...     print("n=%d\t%s", n, format(720+1/2**n,'.17f'))
n=%d    %s 43 720.00000000000011369
n=%d    %s 44 720.00000000000000000

math.log2(1/math.ulp(720))

43.0

for n in range(2,30):

...     print("n=%d\t%s" % (n, format((720+1/2**43)*n,'.17f')))
...
n=2    1440.00000000000022737
n=3    2160.00000000000045475
...
n=6    4320.00000000000090949
...
n=12    8640.00000000000181899
...
n=23    16560.00000000000363798
n=24    17280.00000000000363798
n=25    18000.00000000000363798

for n in range(2,36000,10000):

...     postresult=n*(720+math.ulp(720))/360
...     postresult-=math.ulp(postresult)
...     angresult=n*(720+math.ulp(720)-math.ulp(720))/360
...     print("n=%d\t%s\t%s" % (n, format(postresult,'.17f'),
format(angresult,'.17f')))
...
n=2    4.00000000000000000    4.00000000000000000
n=10002    20004.00000000000000000    20004.00000000000000000
n=20002    40004.00000000000000000    40004.00000000000000000
n=30002    60004.00000000000000000    60004.00000000000000000

Okay, as long as you're calculating epsilon it looks correct either way.
(if you use the "machine epsilon" or epsilon of the angle, it gives
wrong answers)

  • Cory

In the helix() function in fact angle can be arbitrarily large, as the
helix may have many turns.

On Sun, Aug 24, 2025 at 6:46 PM Cory Cross openscad@corycross.org wrote:

 On 8/22/25 3:28 PM, Adrian Mariano via Discuss wrote:
 Why would it matter if n>360?  I don't see that it makes a
 difference if you subtract epsilon from angle or from the whole
 expression.  I did the latter because it was simpler.
 So the error is in `angle`, and it's multiplied by n/360. We're
 assuming the error is as much as epsilon, so subtracting at the end:

 n*(angle+epsilon)/360 - epsilon
 n*angle/360 + epsilon*n/360 - epsilon

 so if n=720 we're still epsilon too much, and if (n*angle/360) is
 an integer, the final result will round up to the next higher integer.

 versus subtracting at angle:

 n*(angle+epsilon-epsilon)/360
 n*angle/360

 independent of n when error==epsilon (which we're assuming). If
 it's actually less than epsilon:

 n*angle/360 - epsilon*n/360

 That will only cause a different result if n*angle/360 was
 slightly more than a whole number, which will never (for any sane
 measurements) be the case when you are choosing some fraction of
 $fn arc, and only arose in freak coincidences in existing code.

 - Cory Cross
 On Fri, Aug 22, 2025 at 4:38 PM Cory Cross via Discuss
 <discuss@lists.openscad.org> wrote:



     On August 21, 2025 2:02:00 PM EDT, Adrian Mariano via Discuss
     <discuss@lists.openscad.org> wrote:

Representability as a double is not sufficient. You have to

     also compute

that representation. Since arccos is involved this is not

     guaranteed.  I

see issues with n of 5, 6 and 8 which have integer angles of

     72, 60 and

45.  It works for n of 3 and 12.

     Oops, I inverted the equation. (n * arc_angle / 360) of
     course. Okay, so a trigonometric function is calculating the
     angle and returning 72+epsilon (or more!? hope not), so just
     subtracting epsilon from the whole equation won't always work
     when n>360, so it should be taken from the angle.

     - Cory

Subtracting epsilon before the ceil seems ok and of course

     does fix it.

On Thu, Aug 21, 2025 at 13:30 Cory Cross via Discuss <
discuss@lists.openscad.org> wrote:

I think the cause is when either angle or

     360/(n*arc_angle) isn't

perfectly representable by a double.

I think the best solution is to subtract epsilon before

     calling ceil. I

haven't thought of any situation this is worse, especially

     given n is never

less than 3.

On August 21, 2025 10:45:52 AM EDT, Marius Kintel via

     Discuss <

In C++, OpenSCAD converts n to int first before doing the

     arc angle

calculation. That may introduce a tiny difference, as if

     you do the same

calculation in OpenSCAD, it’s kept as double all the way.

     Not sure if

that’s the root cause though..

If I'm remembering my numerical methods lessons correctly,

     I don't think

that's the reason, as the code correctly multiplies

     n*arc_angle first,

which will always be less than the maximum representable

     integer in a

double (for any reasonable n), so it will exact if the

     angle is

representable as a double.

  • Cory Cross

-Marius

On Aug 21, 2025, at 10:22, Adrian Mariano via Discuss <

Thanks.  The possibility of rounding error exists in

     the computation.

Someone observed in BOSL2 that offset behaved

     irregularly.  The existing

calculation does not match openscad but even with it fixed

     if I offset a

regular n gon with $fn = n I get rounding errors and

     sometimes the ceil

rounds up giving an extra facet. Openscad seems to avoid

     this somehow and

consistently produces just a single facet.

On Thu, Aug 21, 2025 at 09:43 Cory Cross via Discuss <

     <mailto:discuss@lists.openscad.org>> wrote:

At least in DxfData:

           n = static_cast<int>(ceil(n * arc_angle / 360));

where n comes from

           int n = Calc::get_fragments_from_r(radius,

     fn, fs, fa);

which returns $fn so long as it's at least 3: <

     https://github.com/openscad/openscad/blob/master/src%2Futils%2Fcalc.cc#L47

<

     https://github.com/openscad/openscad/blob/master/src%2Fio%2FDxfData.cc#L205

Sorry for non-permalinks.

On August 21, 2025 8:18:44 AM EDT, Adrian Mariano via

     Discuss <
     <mailto:discuss@lists.openscad.org>> wrote:

Does anybody know the calculation openscad uses for

     the number of

segments on an arc of angle theta as a function of $fn? 

     Exactly what kind

of rounding is used?


OpenSCAD mailing list
To unsubscribe send an email to

     discuss-leave@lists.openscad.org

OpenSCAD mailing list
To unsubscribe send an email to

     discuss-leave@lists.openscad.org

OpenSCAD mailing list
To unsubscribe send an email to

     discuss-leave@lists.openscad.org
     _______________________________________________
     OpenSCAD mailing list
     To unsubscribe send an email to discuss-leave@lists.openscad.org


 _______________________________________________
 OpenSCAD mailing list
 To unsubscribe send an email todiscuss-leave@lists.openscad.org

OpenSCAD mailing list
To unsubscribe send an email todiscuss-leave@lists.openscad.org

On 8/24/25 4:08 PM, Adrian Mariano via Discuss wrote: > Cory did quote links to the code. > > Your analysis assumes you can do regular arithmetic on epsilon, which > I think is suspect if epsilon is machine precision, since every > computational step has the potential to introduce error on the order > of epsilon---in either direction.   In fact it appears that only by > subtracting epsilon at the end do you guarantee that you're not > subject to subsequent rounding error that makes the value too large. Okay, let's assume we're exactly one epsilon too large, see if my Python is correct. Some lines truncated >>> for n in range(40,60): ...     print("n=%d\t%s", n, format(720+1/2**n,'.17f')) n=%d    %s 43 720.00000000000011369 n=%d    %s 44 720.00000000000000000 >>> math.log2(1/math.ulp(720)) 43.0 >>> for n in range(2,30): ...     print("n=%d\t%s" % (n, format((720+1/2**43)*n,'.17f'))) ... n=2    1440.00000000000022737 n=3    2160.00000000000045475 ... n=6    4320.00000000000090949 ... n=12    8640.00000000000181899 ... n=23    16560.00000000000363798 n=24    17280.00000000000363798 n=25    18000.00000000000363798 >>> for n in range(2,36000,10000): ...     postresult=n*(720+math.ulp(720))/360 ...     postresult-=math.ulp(postresult) ...     angresult=n*(720+math.ulp(720)-math.ulp(720))/360 ...     print("n=%d\t%s\t%s" % (n, format(postresult,'.17f'), format(angresult,'.17f'))) ... n=2    4.00000000000000000    4.00000000000000000 n=10002    20004.00000000000000000    20004.00000000000000000 n=20002    40004.00000000000000000    40004.00000000000000000 n=30002    60004.00000000000000000    60004.00000000000000000 Okay, as long as you're calculating epsilon it looks correct either way. (if you use the "machine epsilon" or epsilon of the angle, it gives wrong answers) - Cory > In the helix() function in fact angle can be arbitrarily large, as the > helix may have many turns. > > On Sun, Aug 24, 2025 at 6:46 PM Cory Cross <openscad@corycross.org> wrote: > > On 8/22/25 3:28 PM, Adrian Mariano via Discuss wrote: >> Why would it matter if n>360?  I don't see that it makes a >> difference if you subtract epsilon from angle or from the whole >> expression.  I did the latter because it was simpler. > > So the error is in `angle`, and it's multiplied by n/360. We're > assuming the error is as much as epsilon, so subtracting at the end: > > n*(angle+epsilon)/360 - epsilon > n*angle/360 + epsilon*n/360 - epsilon > > so if n=720 we're still epsilon too much, and if (n*angle/360) is > an integer, the final result will round up to the next higher integer. > > versus subtracting at angle: > > n*(angle+epsilon-epsilon)/360 > n*angle/360 > > independent of n when error==epsilon (which we're assuming). If > it's actually less than epsilon: > > n*angle/360 - epsilon*n/360 > > That will only cause a different result if n*angle/360 was > slightly more than a whole number, which will never (for any sane > measurements) be the case when you are choosing some fraction of > $fn arc, and only arose in freak coincidences in existing code. > > - Cory Cross > >> >> On Fri, Aug 22, 2025 at 4:38 PM Cory Cross via Discuss >> <discuss@lists.openscad.org> wrote: >> >> >> >> On August 21, 2025 2:02:00 PM EDT, Adrian Mariano via Discuss >> <discuss@lists.openscad.org> wrote: >> >Representability as a double is not sufficient. You have to >> also compute >> >that representation. Since arccos is involved this is not >> guaranteed.  I >> >see issues with n of 5, 6 and 8 which have integer angles of >> 72, 60 and >> >45.  It works for n of 3 and 12. >> >> Oops, I inverted the equation. (n * arc_angle / 360) of >> course. Okay, so a trigonometric function is calculating the >> angle and returning 72+epsilon (or more!? hope not), so just >> subtracting epsilon from the whole equation won't always work >> when n>360, so it should be taken from the angle. >> >> - Cory >> >> >> > >> >Subtracting epsilon before the ceil seems ok and of course >> does fix it. >> > >> >On Thu, Aug 21, 2025 at 13:30 Cory Cross via Discuss < >> >discuss@lists.openscad.org> wrote: >> > >> >> I think the cause is when either angle or >> 360/(n*arc_angle) isn't >> >> perfectly representable by a double. >> >> >> >> I think the best solution is to subtract epsilon before >> calling ceil. I >> >> haven't thought of any situation this is worse, especially >> given n is never >> >> less than 3. >> >> >> >> >> >> >> >> On August 21, 2025 10:45:52 AM EDT, Marius Kintel via >> Discuss < >> >> discuss@lists.openscad.org> wrote: >> >> >In C++, OpenSCAD converts n to int first before doing the >> arc angle >> >> calculation. That may introduce a tiny difference, as if >> you do the same >> >> calculation in OpenSCAD, it’s kept as double all the way. >> Not sure if >> >> that’s the root cause though.. >> >> >> >> If I'm remembering my numerical methods lessons correctly, >> I don't think >> >> that's the reason, as the code correctly multiplies >> n*arc_angle first, >> >> which will always be less than the maximum representable >> integer in a >> >> double (for any reasonable n), so it will exact if the >> angle is >> >> representable as a double. >> >> >> >> - Cory Cross >> >> >> >> >> >> >> >> >> >> > >> >> > -Marius >> >> > >> >> >> On Aug 21, 2025, at 10:22, Adrian Mariano via Discuss < >> >> discuss@lists.openscad.org> wrote: >> >> >> >> >> >> Thanks.  The possibility of rounding error exists in >> the computation. >> >> Someone observed in BOSL2 that offset behaved >> irregularly.  The existing >> >> calculation does not match openscad but even with it fixed >> if I offset a >> >> regular n gon with $fn = n I get rounding errors and >> sometimes the ceil >> >> rounds up giving an extra facet. Openscad seems to avoid >> this somehow and >> >> consistently produces just a single facet. >> >> >> >> >> >> On Thu, Aug 21, 2025 at 09:43 Cory Cross via Discuss < >> >> discuss@lists.openscad.org >> <mailto:discuss@lists.openscad.org>> wrote: >> >> >>> At least in DxfData: >> >> >>> >> >> >>>           n = static_cast<int>(ceil(n * arc_angle / 360)); >> >> >>> >> >> >>> where n comes from >> >> >>> >> >> >>>           int n = Calc::get_fragments_from_r(radius, >> fn, fs, fa); >> >> >>> >> >> >>> which returns $fn so long as it's at least 3: < >> >> >> https://github.com/openscad/openscad/blob/master/src%2Futils%2Fcalc.cc#L47 >> >> > >> >> >>> >> >> >>> < >> >> >> https://github.com/openscad/openscad/blob/master/src%2Fio%2FDxfData.cc#L205 >> >> > >> >> >>> >> >> >>> Sorry for non-permalinks. >> >> >>> >> >> >>> >> >> >>> On August 21, 2025 8:18:44 AM EDT, Adrian Mariano via >> Discuss < >> >> discuss@lists.openscad.org >> <mailto:discuss@lists.openscad.org>> wrote: >> >> >>>> Does anybody know the calculation openscad uses for >> the number of >> >> segments on an arc of angle theta as a function of $fn?  >> Exactly what kind >> >> of rounding is used? >> >> >>> _______________________________________________ >> >> >>> OpenSCAD mailing list >> >> >>> To unsubscribe send an email to >> discuss-leave@lists.openscad.org >> >> <mailto:discuss-leave@lists.openscad.org >> >> >_______________________________________________ >> >> >> OpenSCAD mailing list >> >> >> To unsubscribe send an email to >> discuss-leave@lists.openscad.org >> >> > >> >> _______________________________________________ >> >> OpenSCAD mailing list >> >> To unsubscribe send an email to >> discuss-leave@lists.openscad.org >> _______________________________________________ >> OpenSCAD mailing list >> To unsubscribe send an email to discuss-leave@lists.openscad.org >> >> >> _______________________________________________ >> OpenSCAD mailing list >> To unsubscribe send an email todiscuss-leave@lists.openscad.org > > > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email todiscuss-leave@lists.openscad.org
JB
Jordan Brown
Mon, Aug 25, 2025 7:05 AM

On 8/24/2025 11:57 PM, Jordan Brown via Discuss wrote:

On 8/21/2025 2:18 PM, Adrian Mariano via Discuss wrote:

Does anybody know the calculation openscad uses for the number of
segments on an arc of angle theta as a function of $fn?  Exactly what
kind of rounding is used?

I don't think anybody ever directly quoted the source:

My apologies.  I read more into Adrian's question than was there; the
only case that came to mind that processes arcs was rotate_extrude and
so that's what I thought he was talking about.

Part of the true answer is that there is no true answer.  There is a
central function for doing the r/fn/fs/fa calculation for the number of
segments in a circle, but no corresponding central function for
calculating the number of segments in an arc.  Each component that needs
it does the calculation on its own.

For the particular case of offset(), which is what Adrian is looking
at, it's here:

https://github.com/openscad/openscad/blob/4c9d585cffd9d1e787366eb3023d9f9d3c5084fa/src/geometry/GeometryEvaluator.cc#L599

... which only partially answers the question:

         // ClipperLib documentation: The formula for the number of steps in a full
         // circular arc is ... Pi / acos(1 - arc_tolerance / abs(delta))
         double n = Calc::get_fragments_from_r(std::abs(node.delta), node.fn, node.fs, node.fa);
         double arc_tolerance = std::abs(node.delta) * (1 - cos_degrees(180 / n));
         geom = ClipperUtils::applyOffset(*polygon, node.delta, node.join_type, node.miter_limit,
                                          arc_tolerance);

so it's considerably uglier than rotate_extrude.

On 8/24/2025 11:57 PM, Jordan Brown via Discuss wrote: > On 8/21/2025 2:18 PM, Adrian Mariano via Discuss wrote: >> Does anybody know the calculation openscad uses for the number of >> segments on an arc of angle theta as a function of $fn?  Exactly what >> kind of rounding is used? > > I don't think anybody ever directly quoted the source: > My apologies.  I read more into Adrian's question than was there; the only case that came to mind that processes arcs was rotate_extrude and so that's what I thought he was talking about. Part of the true answer is that there is no true answer.  There is a central function for doing the r/fn/fs/fa calculation for the number of segments in a circle, but no corresponding central function for calculating the number of segments in an arc.  Each component that needs it does the calculation on its own. For the particular case of offset(), which *is* what Adrian is looking at, it's here: https://github.com/openscad/openscad/blob/4c9d585cffd9d1e787366eb3023d9f9d3c5084fa/src/geometry/GeometryEvaluator.cc#L599 ... which only partially answers the question: // ClipperLib documentation: The formula for the number of steps in a full // circular arc is ... Pi / acos(1 - arc_tolerance / abs(delta)) double n = Calc::get_fragments_from_r(std::abs(node.delta), node.fn, node.fs, node.fa); double arc_tolerance = std::abs(node.delta) * (1 - cos_degrees(180 / n)); geom = ClipperUtils::applyOffset(*polygon, node.delta, node.join_type, node.miter_limit, arc_tolerance); so it's considerably uglier than rotate_extrude.
AM
Adrian Mariano
Mon, Aug 25, 2025 8:31 PM

I can't tell what's going on in that clipperlib code fragment.  Does
node.delta hold the r value for the offset?

On Mon, Aug 25, 2025 at 3:06 AM Jordan Brown via Discuss <
discuss@lists.openscad.org> wrote:

On 8/24/2025 11:57 PM, Jordan Brown via Discuss wrote:

On 8/21/2025 2:18 PM, Adrian Mariano via Discuss wrote:

Does anybody know the calculation openscad uses for the number of segments
on an arc of angle theta as a function of $fn?  Exactly what kind of
rounding is used?

I don't think anybody ever directly quoted the source:

My apologies.  I read more into Adrian's question than was there; the only
case that came to mind that processes arcs was rotate_extrude and so that's
what I thought he was talking about.

Part of the true answer is that there is no true answer.  There is a
central function for doing the r/fn/fs/fa calculation for the number of
segments in a circle, but no corresponding central function for calculating
the number of segments in an arc.  Each component that needs it does the
calculation on its own.

For the particular case of offset(), which is what Adrian is looking at,
it's here:

https://github.com/openscad/openscad/blob/4c9d585cffd9d1e787366eb3023d9f9d3c5084fa/src/geometry/GeometryEvaluator.cc#L599

... which only partially answers the question:

     // ClipperLib documentation: The formula for the number of steps in a full
     // circular arc is ... Pi / acos(1 - arc_tolerance / abs(delta))
     double n = Calc::get_fragments_from_r(std::abs(node.delta), node.fn, node.fs, node.fa);
     double arc_tolerance = std::abs(node.delta) * (1 - cos_degrees(180 / n));
     geom = ClipperUtils::applyOffset(*polygon, node.delta, node.join_type, node.miter_limit,
                                      arc_tolerance);

so it's considerably uglier than rotate_extrude.


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

I can't tell what's going on in that clipperlib code fragment. Does node.delta hold the r value for the offset? On Mon, Aug 25, 2025 at 3:06 AM Jordan Brown via Discuss < discuss@lists.openscad.org> wrote: > On 8/24/2025 11:57 PM, Jordan Brown via Discuss wrote: > > On 8/21/2025 2:18 PM, Adrian Mariano via Discuss wrote: > > Does anybody know the calculation openscad uses for the number of segments > on an arc of angle theta as a function of $fn? Exactly what kind of > rounding is used? > > I don't think anybody ever directly quoted the source: > > My apologies. I read more into Adrian's question than was there; the only > case that came to mind that processes arcs was rotate_extrude and so that's > what I thought he was talking about. > > Part of the true answer is that there is no true answer. There is a > central function for doing the r/fn/fs/fa calculation for the number of > segments in a circle, but no corresponding central function for calculating > the number of segments in an arc. Each component that needs it does the > calculation on its own. > > For the particular case of offset(), which *is* what Adrian is looking at, > it's here: > > > https://github.com/openscad/openscad/blob/4c9d585cffd9d1e787366eb3023d9f9d3c5084fa/src/geometry/GeometryEvaluator.cc#L599 > > ... which only partially answers the question: > > // ClipperLib documentation: The formula for the number of steps in a full > // circular arc is ... Pi / acos(1 - arc_tolerance / abs(delta)) > double n = Calc::get_fragments_from_r(std::abs(node.delta), node.fn, node.fs, node.fa); > double arc_tolerance = std::abs(node.delta) * (1 - cos_degrees(180 / n)); > geom = ClipperUtils::applyOffset(*polygon, node.delta, node.join_type, node.miter_limit, > arc_tolerance); > > so it's considerably uglier than rotate_extrude. > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org
JB
Jordan Brown
Mon, Aug 25, 2025 9:17 PM

On 8/25/2025 10:31 PM, Adrian Mariano via Discuss wrote:

I can't tell what's going on in that clipperlib code fragment.  Does
node.delta hold the r value for the offset?

node.delta gets "r" if it's set, else gets "delta" if it's set, else is 1.

https://github.com/openscad/openscad/blob/4c9d585cffd9d1e787366eb3023d9f9d3c5084fa/src/core/OffsetNode.cc#L55

On Mon, Aug 25, 2025 at 3:06 AM Jordan Brown via Discuss
discuss@lists.openscad.org wrote:

 On 8/24/2025 11:57 PM, Jordan Brown via Discuss wrote:
 On 8/21/2025 2:18 PM, Adrian Mariano via Discuss wrote:
 Does anybody know the calculation openscad uses for the number
 of segments on an arc of angle theta as a function of $fn? 
 Exactly what kind of rounding is used?
 I don't think anybody ever directly quoted the source:
 My apologies.  I read more into Adrian's question than was there;
 the only case that came to mind that processes arcs was
 rotate_extrude and so that's what I thought he was talking about.

 Part of the true answer is that there is no true answer. There is
 a central function for doing the r/fn/fs/fa calculation for the
 number of segments in a circle, but no corresponding central
 function for calculating the number of segments in an arc.  Each
 component that needs it does the calculation on its own.

 For the particular case of offset(), which *is* what Adrian is
 looking at, it's here:

 https://github.com/openscad/openscad/blob/4c9d585cffd9d1e787366eb3023d9f9d3c5084fa/src/geometry/GeometryEvaluator.cc#L599

 ... which only partially answers the question:

              // ClipperLib documentation: The formula for the number of steps in a full
              // circular arc is ... Pi / acos(1 - arc_tolerance / abs(delta))
              double n = Calc::get_fragments_from_r(std::abs(node.delta), node.fn, node.fs, node.fa);
              double arc_tolerance = std::abs(node.delta) * (1 - cos_degrees(180 / n));
              geom = ClipperUtils::applyOffset(*polygon, node.delta, node.join_type, node.miter_limit,
                                               arc_tolerance);

 so it's considerably uglier than rotate_extrude.

 _______________________________________________
 OpenSCAD mailing list
 To unsubscribe send an email to discuss-leave@lists.openscad.org

OpenSCAD mailing list
To unsubscribe send an email todiscuss-leave@lists.openscad.org

On 8/25/2025 10:31 PM, Adrian Mariano via Discuss wrote: > I can't tell what's going on in that clipperlib code fragment.  Does > node.delta hold the r value for the offset? node.delta gets "r" if it's set, else gets "delta" if it's set, else is 1. https://github.com/openscad/openscad/blob/4c9d585cffd9d1e787366eb3023d9f9d3c5084fa/src/core/OffsetNode.cc#L55 > > On Mon, Aug 25, 2025 at 3:06 AM Jordan Brown via Discuss > <discuss@lists.openscad.org> wrote: > > On 8/24/2025 11:57 PM, Jordan Brown via Discuss wrote: >> On 8/21/2025 2:18 PM, Adrian Mariano via Discuss wrote: >>> Does anybody know the calculation openscad uses for the number >>> of segments on an arc of angle theta as a function of $fn?  >>> Exactly what kind of rounding is used? >> >> I don't think anybody ever directly quoted the source: >> > My apologies.  I read more into Adrian's question than was there; > the only case that came to mind that processes arcs was > rotate_extrude and so that's what I thought he was talking about. > > Part of the true answer is that there is no true answer. There is > a central function for doing the r/fn/fs/fa calculation for the > number of segments in a circle, but no corresponding central > function for calculating the number of segments in an arc.  Each > component that needs it does the calculation on its own. > > For the particular case of offset(), which *is* what Adrian is > looking at, it's here: > > https://github.com/openscad/openscad/blob/4c9d585cffd9d1e787366eb3023d9f9d3c5084fa/src/geometry/GeometryEvaluator.cc#L599 > > ... which only partially answers the question: > > // ClipperLib documentation: The formula for the number of steps in a full > // circular arc is ... Pi / acos(1 - arc_tolerance / abs(delta)) > double n = Calc::get_fragments_from_r(std::abs(node.delta), node.fn, node.fs, node.fa); > double arc_tolerance = std::abs(node.delta) * (1 - cos_degrees(180 / n)); > geom = ClipperUtils::applyOffset(*polygon, node.delta, node.join_type, node.miter_limit, > arc_tolerance); > > so it's considerably uglier than rotate_extrude. > > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org > > > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email todiscuss-leave@lists.openscad.org