Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.postscript > #1731 > unrolled thread

How does 'arc' work?

Started byluser- -droog <mijoryx@yahoo.com>
First post2013-11-20 23:23 -0800
Last post2016-04-19 02:54 -0700
Articles 15 on this page of 35 — 5 participants

Back to article view | Back to comp.lang.postscript


Contents

  How does 'arc' work? luser- -droog <mijoryx@yahoo.com> - 2013-11-20 23:23 -0800
    Re: How does 'arc' work? bugbear <bugbear@trim_papermule.co.uk_trim> - 2013-11-21 14:05 +0000
      Re: How does 'arc' work? luser- -droog <mijoryx@yahoo.com> - 2013-12-01 04:03 -0800
    Re: How does 'arc' work? jdaw1 <jdawiseman@gmail.com> - 2013-11-23 15:06 -0800
      Re: How does 'arc' work? luser- -droog <mijoryx@yahoo.com> - 2013-12-01 03:48 -0800
        Re: How does 'arc' work? luser- -droog <mijoryx@yahoo.com> - 2013-12-01 03:58 -0800
          Re: How does 'arc' work? luser- -droog <mijoryx@yahoo.com> - 2013-12-10 23:02 -0800
            Re: How does 'arc' work? luser- -droog <mijoryx@yahoo.com> - 2013-12-11 00:17 -0800
              Re: How does 'arc' work? luser- -droog <mijoryx@yahoo.com> - 2013-12-11 00:20 -0800
                Re: How does 'arc' work? luser- -droog <mijoryx@yahoo.com> - 2013-12-11 01:37 -0800
                Re: How does 'arc' work? tlvp <mPiOsUcB.EtLlLvEp@att.net> - 2014-02-28 03:47 -0500
                  Re: How does 'arc' work? luser- -droog <mijoryx@yahoo.com> - 2014-03-01 00:30 -0800
            Re: How does 'arc' work? jdaw1 <jdawiseman@gmail.com> - 2014-04-29 13:10 -0700
      Re: How does 'arc' work? jdaw1 <jdawiseman@gmail.com> - 2019-02-02 16:19 -0800
    Re: How does 'arc' work? jdaw1 <jdawiseman@gmail.com> - 2014-05-02 06:29 -0700
      Re: How does 'arc' work? jdaw1 <jdawiseman@gmail.com> - 2014-05-08 02:21 -0700
        Re: How does 'arc' work? jdaw1 <jdawiseman@gmail.com> - 2016-04-01 15:28 -0700
          Re: How does 'arc' work? luser- -droog <mijoryx@yahoo.com> - 2016-04-02 21:35 -0700
            Re: How does 'arc' work? jdaw1 <jdawiseman@gmail.com> - 2016-04-03 13:54 -0700
              Re: How does 'arc' work? luser- -droog <mijoryx@yahoo.com> - 2016-04-18 21:40 -0700
                Re: How does 'arc' work? luser- -droog <mijoryx@yahoo.com> - 2016-04-19 15:04 -0700
                  Re: How does 'arc' work? jdaw1 <jdawiseman@gmail.com> - 2016-04-20 02:06 -0700
                  Re: How does 'arc' work? jdaw1 <jdawiseman@gmail.com> - 2016-04-20 05:18 -0700
                    Re: How does 'arc' work? luser- -droog <mijoryx@yahoo.com> - 2016-04-22 00:40 -0700
                      Re: How does 'arc' work? luser- -droog <mijoryx@yahoo.com> - 2016-04-22 11:32 -0700
                        Re: How does 'arc' work? luser- -droog <mijoryx@yahoo.com> - 2016-04-23 20:49 -0700
                          Re: How does 'arc' work? luser- -droog <mijoryx@yahoo.com> - 2016-04-23 22:46 -0700
                          Re: How does 'arc' work? jdaw1 <jdawiseman@gmail.com> - 2016-04-24 04:01 -0700
                            Re: How does 'arc' work? luser- -droog <mijoryx@yahoo.com> - 2016-04-30 21:47 -0700
                              Re: How does 'arc' work? luser- -droog <mijoryx@yahoo.com> - 2016-05-01 02:59 -0700
          Re: How does 'arc' work? Scott Hemphill <hemphill@hemphills.net> - 2016-04-03 10:40 -0400
            Re: How does 'arc' work? luser- -droog <mijoryx@yahoo.com> - 2016-04-05 21:48 -0700
              Re: How does 'arc' work? Scott Hemphill <hemphill@hemphills.net> - 2016-04-06 10:37 -0400
              Re: How does 'arc' work? luser- -droog <mijoryx@yahoo.com> - 2016-04-07 23:59 -0700
              Re: How does 'arc' work? jdaw1 <jdawiseman@gmail.com> - 2016-04-19 02:54 -0700

Page 2 of 2 — ← Prev page 1 [2]


#2532

Fromluser- -droog <mijoryx@yahoo.com>
Date2016-04-19 15:04 -0700
Message-ID<1c1d99b7-0d1b-402b-a160-35747f2d94ff@googlegroups.com>
In reply to#2530
On Monday, April 18, 2016 at 11:40:24 PM UTC-5, luser- -droog wrote:
> On Sunday, April 3, 2016 at 3:54:55 PM UTC-5, jdaw1 wrote:
> > On Sunday, 3 April 2016 05:35:24 UTC+1, luser- -droog  wrote:
> > 
> > > Aside from the cos/sin bungle, what do you need that these formulas
> > > don't get you?
> > > 
> > > x0 = cos(a) 
> > > y0 = sin(a) 
> > > x1 = (4 - cos(a)) / 3 
> > > y1 = ((1 - cos(a))(cos(a) - 3)) / (3*sin(a)) 
> > > x2 = x1 
> > > y2 = -y1 
> > > x3 = x0 
> > > y3 = -y0
> > 
> > Are they correct? I am expecting, with an angle of π/2 = 90°, that Sqrt[(x0-x1)^2+(y0-y1)^2] should be about 0.552. I think your formula returns 2×Sqrt[13]/3 ≈ 2.4037. Even with a = π/4 = 45°, it returns a distance of 1.09565.
> > 
> > Or have I made an error?
> 
> I'm not sure! Referring to this file of yours:
> http://www.jdawiseman.com/2014/Bezier_part_circle_20140508.pdf
> I'm not sure I understand it. Does the "Knots" stuff accurately
> model the Bezier interpolation?
> 
> Empirically, my code seems to draw things that look like circular 
> arcs to me. 
> 
> And my math-guru spent a few days with the equations and
> came up with the same results. 

This is not correct. The result for y1 is different.
The new result is:

  y1 = (1 - x1*cos(a)) / sin(a)

or fully expanded:

  y1 = ((3 - cos(a))(1 - cos(a)))/ sin(a)

> The derivation only worries 
> about the middle point of the curve, where the naïve recursive
> deCasteljau subdivision will later chop the curve in twain and
> select the point as the join. We then just assume by symmetry
> that further subdivision points will be on the same arc.
> 
> I also don't see in your notes any easy formula that I can grab
> and apply to the problem of calculating the control points given
> theta.
> 
> On the other hand, based on the outputs from Scott's program,
> it appears my lengths are fairly consistent in being close
> to double the "desired" measure. So it's probably worthwhile
> to try scaling my tangent lengths and compare outputs. Maybe my
> circles are not as pretty as they might be...

The output does appear better. The edges seem smoother.
Have not yet checked Scott's measurements.

[toc] | [prev] | [next] | [standalone]


#2533

Fromjdaw1 <jdawiseman@gmail.com>
Date2016-04-20 02:06 -0700
Message-ID<eaa95dcf-797d-4a2c-bd2f-751776bf2cf8@googlegroups.com>
In reply to#2532
I think you want the half-way point to have exactly the correct radius. Please confirm that is so.

If so, that which I call ‘z’, the distance of the inner control points from the outer, of course along the tangent to the circle, satisfies z == Tan[a/4] * 4/3.

With a=90°, Tan[a/4] = Tan[22½°] = √2-1, so z = (√2-1)*4/3 ≈ 0.55228474983. Adobe’s value of 0.552 won’t have exactly the correct radius at 45°. Indeed, at 45° Adobe’s radius is Sqrt[499849/500000] ≈ 0.999848988597778.

There are several sensible grounds for choosing z, all of which give values close to 0.552. Correct radius at half-way? Correct fill area (z = 2-Sqrt[(22-5π)/3])? Max and min radii symmetrical around ½ (z = root of a order-12 polynomial: 2097152, -23592960, 117129216, -342814720, 668905728, -921504768, 883891456, -515232000, 96817248, 63288000, -28977264, 466560, 18225, so z ≈ 0.551915)? Minimal absolute dRadius/dAngle (z ≈ 0.552031)? They’re all close to 0.552.

But what is Adobe’s formula for non-90° angles?

[toc] | [prev] | [next] | [standalone]


#2534

Fromjdaw1 <jdawiseman@gmail.com>
Date2016-04-20 05:18 -0700
Message-ID<86c6f499-5c26-4f80-8e43-8d7da8016f93@googlegroups.com>
In reply to#2532
Droog: I think that I have found your error. 
http://www.jdawiseman.com/2016/20160420_Arc_Radius_Droog.nb
http://www.jdawiseman.com/2016/20160420_Arc_Radius_Droog.pdf

[toc] | [prev] | [next] | [standalone]


#2536

Fromluser- -droog <mijoryx@yahoo.com>
Date2016-04-22 00:40 -0700
Message-ID<af27768a-071d-4167-b83d-3a3f4e9d1b71@googlegroups.com>
In reply to#2534
On Wednesday, April 20, 2016 at 7:18:02 AM UTC-5, jdaw1 wrote:
> Droog: I think that I have found your error. 
> http://www.jdawiseman.com/2016/20160420_Arc_Radius_Droog.nb
> http://www.jdawiseman.com/2016/20160420_Arc_Radius_Droog.pdf

Thanks for this! It looks like everything I might need to
dig further. But, I'm kinda burnt-out on xpost and taking
a few days on other projects. I've spent the last few weeks
debugging memory problems raised by a change to the memory
tables. The good news is it's almost 50% faster and suddenly
collecting credible quantities of garbage (for a long time,
the gc results have been suspiciously low). The bad news is
there's still (at least) one bug that's still proving 
difficult to diagnose. If the gc runs at certain unfortuitous
moments, it hits a bunch of errors. As a result of this week's
efforts, this is now a regular postscript VMerror and not a
crash. But it's still bad, but can be avoided by compiling
with -DXPOST_NO_GC or by tweaking the 
XPOST_GARBAGE_COLLECTION_THRESHOLD so it doesn't happen in
just that wrong spot. Even weirder, running on different
OSes produce slightly different errors. It's always 
"can't find table for ent XXXXXX" with some out-of-bounds
number. But mys2, Cygwin, and Linux all report a different
ent number.

I discovered that part of the problem in the numbers
revealed by Scott's program is that xpost is erroneously
producing 2 beziers for the 90-degree arc, for some reason.
Re-reading the code (quoted below), I still don't see why it's 
doing that.

One apparent difference is that you're taking a tangent to 
find the z value, whereas the idea I've been following
was to solve that equation for y1. I'm not sure I see where
the calculation for z comes from, but perhaps that will be
more clear when my brain is less mushy.

And I could always peek at gs or even ralpage for further
reference (and stealing).

For reference, my current implementation (with un-updated
postscript original in comments). This version does not (yet)
incorporate the suggested calculations in the above pdf.
https://github.com/luser-dr00g/xpost/blob/19ace0b18a946ddd95a9e489a2b3759dd14f1221/src/lib/xpost_op_path.c#L511

/*
% packs the center-point, radius and center-angle in a matrix
% then performs the simpler task of calculating a bezier
% for the arc that is symmetrical about the x-axis
% formula derived from http://www.tinaja.com/glib/bezarc1.pdf
/arcbez { % draw single bezier % x y r angle1 angle2  .  x1 y1 x2 y2 x3 y3 x0 y0
    DICT
    %5 dict
    begin
    %/mat matrix def
    5 3 roll mat translate pop                         % r angle1 angle2
    3 2 roll dup mat1 scale mat mat concatmatrix pop % angle1 angle2
    2 copy exch sub /da exch def                       % da=a2-a1
    add 2 div mat1 rotate mat mat concatmatrix pop
    /da_2 da 2 div def
    /sin_a da_2 sin def
    /cos_a da_2 cos def
    4 cos_a sub 3 div % x1
    1 cos_a sub cos_a 3 sub mul
    3 sin_a mul div   % x1 y1
    neg
    1 index           % x1 y1 x2(==x1)
    1 index neg       % x1 y1 x2 y2(==-y1)
    cos_a sin_a neg   % x1 y1 x2 y2 x3 y3
    cos_a sin_a       %               ... x0 y0
    4 { 8 2 roll mat transform } repeat
    %pstack()=
    end
}
dup 0 10 dict
    dup /mat matrix put
    dup /mat1 matrix put
put
bind
def
*/


static
void _transform(Xpost_Matrix mat, real x, real y, real *xres, real *yres)
{
    *xres = mat.xx * x + mat.xy * y + mat.xz;
    *yres = mat.yx * x + mat.yy * y + mat.yz;
}

static
Xpost_Object _arc_start_proc;

static
int _arcbez(Xpost_Context *ctx,
            Xpost_Object x, Xpost_Object y, Xpost_Object r,
            Xpost_Object angle1, Xpost_Object angle2)
{
    Xpost_Matrix mat1, mat2, mat3;
    real da_2, sin_a, cos_a;
    real x0, y0, x1, y1, x2, y2, x3, y3;

    xpost_matrix_scale(&mat1, r.real_.val, r.real_.val);
    xpost_matrix_translate(&mat2, x.real_.val, y.real_.val);
    xpost_matrix_mult(&mat2, &mat1, &mat3);
    xpost_matrix_rotate(&mat2, (real)(((angle1.real_.val + angle2.real_.val) / 2.0) * RAD_PER_DEG));
    xpost_matrix_mult(&mat3, &mat2, &mat1);

    da_2 = (real)(((angle2.real_.val - angle1.real_.val) / 2.0) * RAD_PER_DEG);
    sin_a = (real)sin(da_2);
    cos_a = (real)cos(da_2);
    x0 = cos_a;
    y0 = sin_a;
    x1 = (real)((4 - cos_a) / 3.0);
    //y1 = - (((1 - cos_a) * (cos_a - 3)) / (3 * sin_a));
    y1 = (1 - x1*cos_a) / sin_a;
    x2 = x1;
    y2 = -y1;
    x3 = cos_a;
    y3 = -sin_a;
    _transform(mat1, x0, y0, &x0, &y0);
    _transform(mat1, x1, y1, &x1, &y1);
    _transform(mat1, x2, y2, &x2, &y2);
    _transform(mat1, x3, y3, &x3, &y3);
    xpost_stack_push(ctx->lo, ctx->os, xpost_real_cons(x1));
    xpost_stack_push(ctx->lo, ctx->os, xpost_real_cons(y1));
    xpost_stack_push(ctx->lo, ctx->os, xpost_real_cons(x2));
    xpost_stack_push(ctx->lo, ctx->os, xpost_real_cons(y2));
    xpost_stack_push(ctx->lo, ctx->os, xpost_real_cons(x3));
    xpost_stack_push(ctx->lo, ctx->os, xpost_real_cons(y3));
    xpost_stack_push(ctx->lo, ctx->os, xpost_real_cons(x0));
    xpost_stack_push(ctx->lo, ctx->os, xpost_real_cons(y0));
    return 0;
}

static
int _arc(Xpost_Context *ctx,
         Xpost_Object x, Xpost_Object y, Xpost_Object r,
         Xpost_Object angle1, Xpost_Object angle2)
{
    double a1 = angle1.real_.val;
    double a2 = angle2.real_.val;
    while (a2 < a1)
    {
        double t;
        t = a2 + 360;
        a2 = t;
    }
    if ((a2 - a1) > 90)
    {
        _arc(ctx, x, y, r, xpost_real_cons(a1), xpost_real_cons((real)(a2 - ((a2 - a1)/2.0))));
        _arc(ctx, x, y, r, xpost_real_cons((real)(a1 + ((a2 - a1)/2.0))), xpost_real_cons(a2));
    }
    else
    {
        //Xpost_Object path = _cpath(ctx);
        //int pathlen = xpost_dict_length_memory(xpost_context_select_memory(ctx, path), path);
        _arcbez(ctx, x, y, r, xpost_real_cons(a1), xpost_real_cons(a2));
        xpost_stack_push(ctx->lo, ctx->es, xpost_operator_cons_opcode(_curveto_opcode));
        xpost_stack_push(ctx->lo, ctx->es, _arc_start_proc);
        /*
        if (pathlen)
            xpost_stack_push(ctx->lo, ctx->es, xpost_operator_cons_opcode(_lineto_opcode));
        else
            xpost_stack_push(ctx->lo, ctx->es, xpost_operator_cons_opcode(_moveto_opcode));
            */
    }
    return 0;
}

static
int _arcn(Xpost_Context *ctx,
          Xpost_Object x, Xpost_Object y, Xpost_Object r,
          Xpost_Object angle1, Xpost_Object angle2)
{
    real a1 = angle1.real_.val;
    real a2 = angle2.real_.val;
    while (a2 > a1)
    {
        double t;
        t = a2 - 360;
        a2 = t;
    }
    if ((a1 - a2) > 90)
    {
        _arcn(ctx, x, y, r, xpost_real_cons(a1), xpost_real_cons(a2 + (real)((a1 - a2)/2.0)));
        _arcn(ctx, x, y, r, xpost_real_cons(a1 - (real)((a1 - a2)/2.0)), xpost_real_cons(a2));
    }
    else
    {
        //Xpost_Object path = _cpath(ctx);
        //int pathlen = xpost_dict_length_memory(xpost_context_select_memory(ctx, path), path);
        _arcbez(ctx, x, y, r, xpost_real_cons(a1), xpost_real_cons(a2));
        xpost_stack_push(ctx->lo, ctx->es, xpost_operator_cons_opcode(_curveto_opcode));
        xpost_stack_push(ctx->lo, ctx->es, _arc_start_proc);
        /*
        if (pathlen)
            xpost_stack_push(ctx->lo, ctx->es, xpost_operator_cons_opcode(_lineto_opcode));
        else
            xpost_stack_push(ctx->lo, ctx->es, xpost_operator_cons_opcode(_moveto_opcode));
            */
    }
    return 0;
}

[toc] | [prev] | [next] | [standalone]


#2537

Fromluser- -droog <mijoryx@yahoo.com>
Date2016-04-22 11:32 -0700
Message-ID<1b4fc3ac-e6a1-4a00-80da-f9d3a96e044c@googlegroups.com>
In reply to#2536
I tried coming at it from a different angle. I re-read chapter 7
http://www.math.ubc.ca/~cass/graphics/manual/pdf/ch7.pdf
and tried to write the arc->Bezier as a general tool for
parametric curves. But when it finally mostly worked, the
tangent vectors are again the wrong lengths. So I visually
tweaked the constant so the first few iterations seem to match up.

$ cat bez.ps
%!

% a r g s [/a /r /g /s] n  .  -
/argsbegin {
    dict begin
    dup length 1 sub -1 0 {
        2 copy get
        4 3 roll def
        pop
    } for
    pop
} def

/2= {
    2 copy exch =only (,)print =
    gsave
        2 copy newpath
        currentlinewidth 3 mul 0 360 arc fill
    grestore
} def

% t0 t1 f g f' g' N  .  -  (creates path)
/piecewisebezier {
    {t0 t1 f g f' g' N} 16 argsbegin
    /h t1 t0 sub N div def
    (h=)print h =
    /h3 h 1.8 div def  % h 3 div  makes the vectors too short
    (h3=)print h3 =
    /t t0 def
    /updatexy {
        (t=)print t =
        /x  t f  def
        /y  t g  def
        /x' t f' h3 mul def
        /y' t g' h3 mul def
        %(x,y=)print x =only (,)print y =
    } def
    updatexy

    x y
    2=
    moveto  % (f(t0), g(t0))

    N {
        x x' add
        y y' add  % (f(t)+f'(t)*dt/3, g(t)+g'(t)*dt/3)
        2=

        /t t h add def
        updatexy
        x x' sub
        y y' sub  % (f(t+dt)-f'(t+dt)*dt/3, g(t+dt)-g'(t+dt)*dt/3)
        2=

        x y             % (f(t+dt), g(t+dt))
        2=

        curveto
        %lineto pop pop pop pop
    } repeat
    end
} def

300 400 translate
currentlinewidth
300 dup dup scale
div setlinewidth

0 1 {90 mul cos}{90 mul sin}{90 mul sin neg}{90 mul cos} 1 piecewisebezier stroke
2 1 3 {
    0 1 {90 mul cos}{90 mul sin}{90 mul sin neg}{90 mul cos} 7 6 roll piecewisebezier stroke
} for
showpage



coordinates:
h=1.0
h3=0.555556
t=0
1.0,0.0
1.0,0.555556
t=1.0
0.555556,1.0
0.0,1.0
h=0.5
h3=0.277778
t=0
1.0,0.0
1.0,0.277778
t=0.5
0.903525,0.510688
0.707107,0.707107
0.510688,0.903525
t=1.0
0.277778,1.0
0.0,1.0
h=0.333333
h3=0.185185
t=0
1.0,0.0
1.0,0.185185
t=0.333333
0.958618,0.339625
0.866025,0.5
0.773433,0.660375
t=0.666667
0.660375,0.773433
0.5,0.866025
0.339625,0.958618
t=1.0
0.185185,1.0
0.0,1.0

[toc] | [prev] | [next] | [standalone]


#2538

Fromluser- -droog <mijoryx@yahoo.com>
Date2016-04-23 20:49 -0700
Message-ID<695f97ef-be0b-4ad9-ab46-a78e8c5f4fb6@googlegroups.com>
In reply to#2537
On Friday, April 22, 2016 at 1:32:22 PM UTC-5, luser- -droog wrote:
> I tried coming at it from a different angle. I re-read chapter 7
> http://www.math.ubc.ca/~cass/graphics/manual/pdf/ch7.pdf
> and tried to write the arc->Bezier as a general tool for
> parametric curves. But when it finally mostly worked, the
> tangent vectors are again the wrong lengths. So I visually
> tweaked the constant so the first few iterations seem to match up.
> 

Improved. Uses .552 for 90 degrees and proportionally decreasing
lengths for shorter angles and choosing the number of segments 
by the base-90 logarithm of the angle span.



josh@LAPTOP-ILO10OOF ~
$ cat bez.ps
%!

% a r g s [/a /r /g /s] n  .  -
/argsbegin {
    dict begin
    dup length 1 sub -1 0 {
        2 copy get
        4 3 roll def
        pop
    } for
    pop
} def

/2= {
    %2 copy exch =only ( )print =
    gsave
        2 copy newpath
        currentlinewidth 3 mul 0 360 arc fill
    grestore
}
%pop {}  %uncomment to suppress points as little circles
def

% t0 t1 f g f' g' N  .  -  (creates path)
/piecewisebezier {
    {t0 t1 f g f' g' N} 16 argsbegin
    /h t1 t0 sub N div def
    %(h=)print h =
    %/h3 h 3 div def  % makes the vectors too short
    %/h3 h 1.8 div def  % == .5556 mul
    %/h3 h .552282 mul def
    /h3 h .00613 mul def % .00613 == .552 / 90
    %(h3=)print h3 =
    /t t0 def
    /updatexy {
        %(t=)print t =
        /x  t f  def
        /y  t g  def
        /x' t f' h3 mul def
        /y' t g' h3 mul def
        %(x,y=)print x =only (,)print y =
    } def
    updatexy

    x y
    2=
    moveto  % (f(t0), g(t0))

    N {
        x x' add
        y y' add  % (f(t)+f'(t)*dt/3, g(t)+g'(t)*dt/3)
        2=

        /t t h add def
        updatexy
        x x' sub
        y y' sub  % (f(t+dt)-f'(t+dt)*dt/3, g(t+dt)-g'(t+dt)*dt/3)
        2=

        x y             % (f(t+dt), g(t+dt))
        2=

        curveto
        %lineto pop pop pop pop
    } repeat
    end
} def

/draw {
    gsave
        {moveto}
        {lineto}
        {6 4 roll lineto 4 2 roll lineto lineto}
        {closepath} pathforall
        stroke
    grestore
    stroke
}
%pop {stroke}
def

%180 3.14159 div =

305 400 translate

{
    currentlinewidth
    300 dup dup scale
    div setlinewidth
    /A 0 def
    /B 90 def

    {
        %A B {cos}{sin}{sin neg}{cos} 1 piecewisebezier draw
        1 1 1 {
            %2 mul
            A B {cos}{sin}{sin neg}{cos} 7 6 roll piecewisebezier draw
        } for
    } pop

    {
        10 10 90 {
            A exch {cos}{sin}{sin neg}{cos} 1 piecewisebezier draw
        } for
    } pop
} pop

/myarc {
    {x y r a1 a2} 10 argsbegin
    a1 a2
    {cos r mul}{sin r mul}{sin neg r mul}{cos r mul}
    a2 a1 sub log 90 log div ceiling cvi
    piecewisebezier
    end
} def

0 0 300 0 90 myarc draw

10 10 90 {
    0 0 2 index 2 mul 0 5 4 roll myarc draw
} for

10 10 90 {
    0 0 2 index 2 mul 90 5 4 roll 180 add myarc draw
} for

showpage

josh@LAPTOP-ILO10OOF ~
$

[toc] | [prev] | [next] | [standalone]


#2539

Fromluser- -droog <mijoryx@yahoo.com>
Date2016-04-23 22:46 -0700
Message-ID<93555e96-342c-47a8-ac31-2d387fd436d9@googlegroups.com>
In reply to#2538
On Saturday, April 23, 2016 at 10:49:47 PM UTC-5, luser- -droog wrote:
> On Friday, April 22, 2016 at 1:32:22 PM UTC-5, luser- -droog wrote:
> > I tried coming at it from a different angle. I re-read chapter 7
> > http://www.math.ubc.ca/~cass/graphics/manual/pdf/ch7.pdf
> > and tried to write the arc->Bezier as a general tool for
> > parametric curves. But when it finally mostly worked, the
> > tangent vectors are again the wrong lengths. So I visually
> > tweaked the constant so the first few iterations seem to match up.
> > 
> 
> Improved. Uses .552 for 90 degrees and proportionally decreasing
> lengths for shorter angles and choosing the number of segments 
> by the base-90 logarithm of the angle span.
> 

Re-write/cleanup. Drop-in replacement for arc.

josh@LAPTOP-ILO10OOF ~
$ cat arc.ps 
%!

/.args {
    dup length 1 sub -1 0 {
        2 copy get 4 3 roll def pop
    } for
    pop
} def
/.argsbegin {
    dict begin
        .args
} def

/arc {
    {x y r a1 a2} 20 .argsbegin
    matrix currentmatrix x y translate
    a1 a2 {cos r mul}{sin r mul}{sin neg r mul}{cos r mul}
        a2 a1 sub log 90 log div ceiling cvi
    {t0 t1 f g f' g' N} .args
    /h t1 t0 sub N div def
    /hdelta h .00613 mul def
    /updatexy {
        /x t f def
        /y t g def
        /x' t f' hdelta mul def
        /y' t g' hdelta mul def
    } def

    /t t0 def updatexy
    x y moveto
    N {
        x x' add  y y' add
        /t t h add def updatexy
        x x' sub  y y' sub
        x         y        curveto
    } repeat

    setmatrix
    end
} def

{
/X 306 def
/Y 400 def

X Y 300 0 90 arc stroke 

10 10 90 { 
    X Y 2 index 2 mul 0 5 4 roll arc stroke 
} for 

10 10 90 { 
    X Y 2 index 2 mul 90 5 4 roll 180 add arc stroke 
} for 

showpage
} pop

(xpost/arcdist.ps) run



And Scott's arcdist program yields:

10 0.0612999
20 0.122599
30 0.183900
40 0.245200
50 0.306500
60 0.367999
70 0.429099
80 0.490400
90 0.551700

[toc] | [prev] | [next] | [standalone]


#2540

Fromjdaw1 <jdawiseman@gmail.com>
Date2016-04-24 04:01 -0700
Message-ID<7c300a7c-d8f1-4407-8ef2-4e37f0518b2c@googlegroups.com>
In reply to#2538
On Sunday, 24 April 2016 04:49:47 UTC+1, luser- -droog  wrote:
> Improved. Uses .552 for 90 degrees and proportionally decreasing
> lengths for shorter angles and choosing the number of segments 
> by the base-90 logarithm of the angle span.

I’m sure you don’t mean “base-90 logarithm”. IIRC, Adobe Distiller uses 90° pieces, and if necessary a smaller last piece (so dividing by 90°). 

Adobe Distiller doesn’t quite use proportionality either, though that isn’t bad. As far as I can tell, Adobe might be doing something like 
0.005825526 a - 4.49157E-07 a^2 + 4.32805E-08 a^3, with an exception at 90° of exactly 0.552. (Adobe employees: please reveal the exact formula.)

Linear differs from Adobe by the most at ≈52.4°, differing by ≈ 0.0111.

[toc] | [prev] | [next] | [standalone]


#2555

Fromluser- -droog <mijoryx@yahoo.com>
Date2016-04-30 21:47 -0700
Message-ID<1c267ad1-9cc6-4120-8b40-a4455e0da544@googlegroups.com>
In reply to#2540
On Sunday, April 24, 2016 at 6:01:56 AM UTC-5, jdaw1 wrote:
> On Sunday, 24 April 2016 04:49:47 UTC+1, luser- -droog  wrote:
> > Improved. Uses .552 for 90 degrees and proportionally decreasing
> > lengths for shorter angles and choosing the number of segments 
> > by the base-90 logarithm of the angle span.
> 
> I’m sure you don’t mean “base-90 logarithm”. IIRC, Adobe Distiller uses 90° pieces, and if necessary a smaller last piece (so dividing by 90°). 
> 
> Adobe Distiller doesn’t quite use proportionality either, though that isn’t bad. As far as I can tell, Adobe might be doing something like 
> 0.005825526 a - 4.49157E-07 a^2 + 4.32805E-08 a^3, with an exception at 90° of exactly 0.552. (Adobe employees: please reveal the exact formula.)
> 
> Linear differs from Adobe by the most at ≈52.4°, differing by ≈ 0.0111.

I peeked at ghostscript's implementation:
http://git.ghostscript.com/?p=ghostpdl.git;a=blob;f=base/gspath1.c;h=25644c2bae912fad7e9e9206a973b245fe6d67d0;hb=HEAD

and here's a version that more closely copies that behavior. It partitions the
angle span into orthogonal 90-degree segments, possibly with partial initial
and final <90-degree segments.

$ cat arc.ps
%!

/debug false def  % set true to print points to stdout

/.args {
    dup length 1 sub -1 0 {
        2 copy get 4 3 roll def pop
    } for
    pop
} def
/.argsbegin {
    dict begin
        .args
} def

% x y  .  x-y*floor(x/y)
/fmod {
    2 copy div floor mul sub
} def
%45.0 90.0 fmod = % 45.0
%927.0 90 fmod = % 27.0

/point {
    gsave
        newpath
        currentlinewidth 3 mul 0 360 arc fill
    grestore
} bind def

/debugpoint {
    debug { 2 copy exch =only ( )print = } if
} def

/next_arc_curve {
    /t0 a1 def
    /t1 anext def
    debug {
        (next_arc_curve)=
        t0 t1 exch =only (..)=only =
    } if
    /h t1 t0 sub def
    /hdelta h .00613647 mul def
    /updatexy {
        /x t cos r mul def
        /y t sin r mul def
        /x' t sin neg r mul hdelta mul def
        /y' t cos r mul hdelta mul def
    } def
    /t t0 def updatexy
    x y
    debugpoint
    %moveto
    { currentpoint pop pop } stopped { moveto }{ lineto } ifelse
    x x' add  y y' add
    debugpoint
    /t t h add def updatexy
    x x' sub  y y' sub
    debugpoint
    x         y
    debugpoint
    curveto
    /a1 anext def
} def

/next_arc_quadrant {
    /t0 a1 def
    /t1 anext def
    debug {
        (next_arc_quadrant)=
        t0 t1 exch =only (..)=only =
    } if
    /h 90 def
    /hdelta .552282 def
    /updatexy {
        /x t cos r mul def
        /y t sin r mul def
        /x' t sin neg r mul hdelta mul def
        /y' t cos r mul hdelta mul def
    } def
    /t t0 def updatexy
    x y
    debugpoint
    %moveto
    { currentpoint pop pop } stopped { moveto }{ lineto } ifelse
    x x' add  y y' add
    debugpoint
    /t t h add def updatexy
    x x' sub  y y' sub
    debugpoint
    x         y
    debugpoint
    curveto
    /a1 anext def
} def

/arc {
    {x y r a1 a2} 20 .argsbegin
    matrix currentmatrix x y translate
    debug {
        (a1=)print a1 =
        (a2=)print a2 =
    } if

    r 0 lt {
        /r r neg def
        /a1 a1 180 add def
        /a2 a2 180 add def
    } if

    { a2 a1 lt  not { exit } if  % while (a2<a1)
        (adjust by 360)=
        /a2 a2 360 add def
    } loop

    {
        % first part up to 90 deg
        a1 90 fmod 0 ne {
            /anext a1 90 div floor 90 mul def
            anext a2 lt not {exit} if  % goto last part
            debug { (first part)= } if
            next_arc_curve
        } if

        % multiples of 90 deg
        {
            /anext a1 90 add def
            anext a2 le  not {exit} if  % while (anext<a2)
            next_arc_quadrant
        } loop

    exit } loop

    % last part, if any
    a1 a2 lt {
        /anext a2 def
        debug { (last part)= } if
        next_arc_curve
    } if

    setmatrix
    end
} def

/draw {
    false { gsave
        {point}
        {point}
        {point point point}
        {} pathforall
    grestore } if
    true { gsave
        {moveto}
        {lineto}
        {6 4 roll lineto 4 2 roll lineto lineto}
        {closepath} pathforall
        stroke
    grestore } if
    stroke
}
%pop {stroke}  %uncomment to suppress lines through control points
def

{
/X 306 def
/Y 400 def

X Y 300 0 90 arc draw 

10 10 90 { X Y 2 index 2 mul 0 5 4 roll arc draw } for 

10 10 90 { X Y 2 index 2 mul 90 5 4 roll 180 add arc draw } for 

showpage
} exec%pop

%(xpost/arcdist.ps) run

[toc] | [prev] | [next] | [standalone]


#2556

Fromluser- -droog <mijoryx@yahoo.com>
Date2016-05-01 02:59 -0700
Message-ID<359fdb77-b30c-451f-ac77-465658cf1fb7@googlegroups.com>
In reply to#2555
On Saturday, April 30, 2016 at 11:47:32 PM UTC-5, luser- -droog wrote:
> On Sunday, April 24, 2016 at 6:01:56 AM UTC-5, jdaw1 wrote:
> > On Sunday, 24 April 2016 04:49:47 UTC+1, luser- -droog  wrote:
> > > Improved. Uses .552 for 90 degrees and proportionally decreasing
> > > lengths for shorter angles and choosing the number of segments 
> > > by the base-90 logarithm of the angle span.
> > 
> > I’m sure you don’t mean “base-90 logarithm”. IIRC, Adobe Distiller uses 90° pieces, and if necessary a smaller last piece (so dividing by 90°). 
> > 
> > Adobe Distiller doesn’t quite use proportionality either, though that isn’t bad. As far as I can tell, Adobe might be doing something like 
> > 0.005825526 a - 4.49157E-07 a^2 + 4.32805E-08 a^3, with an exception at 90° of exactly 0.552. (Adobe employees: please reveal the exact formula.)
> > 
> > Linear differs from Adobe by the most at ≈52.4°, differing by ≈ 0.0111.
> 
> I peeked at ghostscript's implementation:
> http://git.ghostscript.com/?p=ghostpdl.git;a=blob;f=base/gspath1.c;h=25644c2bae912fad7e9e9206a973b245fe6d67d0;hb=HEAD
> 
> and here's a version that more closely copies that behavior. It partitions the
> angle span into orthogonal 90-degree segments, possibly with partial initial
> and final <90-degree segments.
> 

This update suppresses the degenerate lineto between each segment. And it implements the above cubic formula for the
tangent vector lengths. Scott Hemphill's measurement program
yields (gs):

10 0.0582551
20 0.116678
30 0.17553
40 0.235071
50 0.295563
60 0.357264
70 0.420432
80 0.485327
90 0.552282

(xpost yields the same numbers to an unnecessary length
of decimal places).

josh@LAPTOP-ILO10OOF ~
$ cat arc.ps
%!

/debug true def  % set true to print points to stdout

/.args {
    dup length 1 sub -1 0 {
        2 copy get 4 3 roll def pop
    } for
    pop
} def
/.argsbegin {
    dict begin
        .args
} def

% x y  .  x-y*floor(x/y)
/fmod {
    2 copy div floor mul sub
} def
%45.0 90.0 fmod = % 45.0
%927.0 90 fmod = % 27.0

/point {
    gsave
        newpath
        currentlinewidth 3 mul 0 360 arc fill
    grestore
} bind def

/debugpoint {
    debug { 2 copy exch =only ( )print = } if
} def

/next_arc_curve {
    /t0 a1 def
    /t1 anext def
    debug {
        (next_arc_curve)=
        t0 t1 exch =only (..)=only =
    } if
    /h t1 t0 sub def
    %/hdelta h .00613647 mul def
    /hdelta
        .005825526 h mul
        4.49157E-07 h h mul mul sub
        4.32805E-08 h h h mul mul mul add
    def
    /updatexy {
        /x t cos r mul def
        /y t sin r mul def
        /x' t sin neg r mul hdelta mul def
        /y' t cos r mul hdelta mul def
    } def
    /t t0 def updatexy
    initialseg {
        x y
        debugpoint
        %moveto
        { currentpoint pop pop } stopped { moveto }{ lineto } ifelse
        /initialseg false def
    } if
    x x' add  y y' add
    debugpoint
    /t t h add def updatexy
    x x' sub  y y' sub
    debugpoint
    x         y
    debugpoint
    curveto
    /a1 anext def
} def

/next_arc_quadrant {
    /t0 a1 def
    /t1 anext def
    debug {
        (next_arc_quadrant)=
        t0 t1 exch =only (..)=only =
    } if
    /h 90 def
    /hdelta .552282 def
    /updatexy {
        /x t cos r mul def
        /y t sin r mul def
        /x' t sin neg r mul hdelta mul def
        /y' t cos r mul hdelta mul def
    } def
    /t t0 def updatexy
    initialseg {
        x y
        debugpoint
        %moveto
        { currentpoint pop pop } stopped { moveto }{ lineto } ifelse
        /initialseg false def
    } if
    x x' add  y y' add
    debugpoint
    /t t h add def updatexy
    x x' sub  y y' sub
    debugpoint
    x         y
    debugpoint
    curveto
    /a1 anext def
} def

/arc {
    {x y r a1 a2} 20 .argsbegin
    matrix currentmatrix x y translate
    debug {
        (a1=)print a1 =
        (a2=)print a2 =
    } if

    r 0 lt {
        /r r neg def
        /a1 a1 180 add def
        /a2 a2 180 add def
    } if

    { a2 a1 lt  not { exit } if  % while (a2<a1)
        (adjust by 360)=
        /a2 a2 360 add def
    } loop

    {
        /initialseg true def

        % first part up to 90 deg
        a1 90 fmod 0 ne {
            /anext a1 90 div floor 90 mul def
            anext a2 lt not {exit} if  % goto last part
            debug { (first part)= } if
            next_arc_curve
        } if

        % multiples of 90 deg
        {
            /anext a1 90 add def
            anext a2 le  not {exit} if  % while (anext<a2)
            next_arc_quadrant
        } loop

    exit } loop

    % last part, if any
    a1 a2 lt {
        /anext a2 def
        debug { (last part)= } if
        next_arc_curve
    } if

    setmatrix
    end
} def

/draw {
    false { gsave
        {point}
        {point}
        {point point point}
        {} pathforall
    grestore } if
    true { gsave
        {moveto}
        {lineto}
        {6 4 roll lineto 4 2 roll lineto lineto}
        {closepath} pathforall
        stroke
    grestore } if
    stroke
}
%pop {stroke}  %uncomment to suppress lines through control points
def

{
/X 306 def
/Y 400 def

X Y 300 0 90 arc draw 

10 10 90 { X Y 2 index 2 mul 0 5 4 roll arc draw } for 

10 10 90 { X Y 2 index 2 mul 90 5 4 roll 180 add arc draw } for 

showpage
} pop%exec%pop

(xpost/arcdist.ps) run

[toc] | [prev] | [next] | [standalone]


#2485

FromScott Hemphill <hemphill@hemphills.net>
Date2016-04-03 10:40 -0400
Message-ID<87zitaycui.fsf@hemphills.net>
In reply to#2481
jdaw1 <jdawiseman@gmail.com> writes:

> All the above reasoning was about 90° angles. What about smaller angles?

What above reasoning?

> For the Bézier curve, obviously the two outer control points are at
> the y=sin() x=cos() ends of the segment of the circle. Obviously the
> two inner control points are at an angle that is tangent to that
> segment of the circle. This leaves one missing parameter: how far away
> are the inner control points?
>
> For 90° of the unit circle, 0.552, as discussed above. I didn’t
> realise until recently that 90° is a special case: extrapolating the
> distances for smaller angles to 90° would give 0.552285, the 0.552
> crossover happening near 89.9582°.
>
> For code to generate numbers, and subsequent analysis, see 
> http://www.jdawiseman.com/2016/20160401_bezier_arcs.ps 
> http://www.jdawiseman.com/2016/20160401_bezier_arcs.xlsx 
>
> Comment and improvements welcomed. 
>
> Do any readers of this forum know the actual angle→distance formula?

For real PostScript?  Feed this to your printer.  Modify it as desired.

========================================================================
%!PS

% What is the distance of an inner Bezier curve control point to the outer
% point as a function of angle in an "arc" operator

/dist
{
  /angle exch def
  gsave
    newpath
    0 0 1000 0 angle arc
    {pop pop} {pop pop} {pop pop pop pop exch pop} {} pathforall
  grestore
  1000 div
}
bind def

/tmpstr 20 string def

% I use paper size "letter"

/in { 72 mul } bind def
/Times-Roman findfont 10 scalefont setfont
/lineskip 12 def
/nl { 1 in y moveto /y y lineskip sub def } bind def
/y 10 in def
nl

10 10 90 { dup tmpstr cvs show (  ) show dist tmpstr cvs show nl } for

showpage
========================================================================

Scott
-- 
Scott Hemphill	hemphill@alumni.caltech.edu
"This isn't flying.  This is falling, with style."  -- Buzz Lightyear

[toc] | [prev] | [next] | [standalone]


#2491

Fromluser- -droog <mijoryx@yahoo.com>
Date2016-04-05 21:48 -0700
Message-ID<cb3786e9-77ac-4257-af36-73f046a85b5a@googlegroups.com>
In reply to#2485
On Sunday, April 3, 2016 at 9:40:55 AM UTC-5, Scott Hemphill wrote:
 
> For real PostScript?  Feed this to your printer.  Modify it as desired.
> 
> ========================================================================
> %!PS
> 
> % What is the distance of an inner Bezier curve control point to the outer
> % point as a function of angle in an "arc" operator
> 
> /dist
> {
>   /angle exch def
>   gsave
>     newpath
>     0 0 1000 0 angle arc
>     {pop pop} {pop pop} {pop pop pop pop exch pop} {} pathforall
>   grestore
>   1000 div
> }
> bind def
> 
> /tmpstr 20 string def
> 
> % I use paper size "letter"
> 
> /in { 72 mul } bind def
> /Times-Roman findfont 10 scalefont setfont
> /lineskip 12 def
> /nl { 1 in y moveto /y y lineskip sub def } bind def
> /y 10 in def
> nl
> 
> 10 10 90 { dup tmpstr cvs show (  ) show dist tmpstr cvs show nl } for
> 
> showpage
> ========================================================================
> 

Very cool. There may indeed be something wrong with my implementation.

gs gives:
10 0.0582147
20 0.11665
30 0.175536
40 0.235099
50 0.295591
60 0.357264
70 0.420398
80 0.485293
90 0.552282

whereas xpost gives:
10 0.115506
20 0.231321
30 0.346987
40 0.461987
50 0.575741
60 0.687515
70 0.796415
80 0.901347
90 1.000998

[toc] | [prev] | [next] | [standalone]


#2495

FromScott Hemphill <hemphill@hemphills.net>
Date2016-04-06 10:37 -0400
Message-ID<877fgals5o.fsf@hemphills.net>
In reply to#2491
luser- -droog <mijoryx@yahoo.com> writes:

> On Sunday, April 3, 2016 at 9:40:55 AM UTC-5, Scott Hemphill wrote:
>  
>> For real PostScript?  Feed this to your printer.  Modify it as desired.
>> 
>> ========================================================================
>> %!PS
>> 
>> % What is the distance of an inner Bezier curve control point to the outer
>> % point as a function of angle in an "arc" operator
>> 
>> /dist
>> {
>>   /angle exch def
>>   gsave
>>     newpath
>>     0 0 1000 0 angle arc
>>     {pop pop} {pop pop} {pop pop pop pop exch pop} {} pathforall
>>   grestore
>>   1000 div
>> }
>> bind def
>> 
>> /tmpstr 20 string def
>> 
>> % I use paper size "letter"
>> 
>> /in { 72 mul } bind def
>> /Times-Roman findfont 10 scalefont setfont
>> /lineskip 12 def
>> /nl { 1 in y moveto /y y lineskip sub def } bind def
>> /y 10 in def
>> nl
>> 
>> 10 10 90 { dup tmpstr cvs show (  ) show dist tmpstr cvs show nl } for
>> 
>> showpage
>> ========================================================================
>> 
>
> Very cool. There may indeed be something wrong with my implementation.
>
> gs gives:
> 10 0.0582147
> 20 0.11665
> 30 0.175536
> 40 0.235099
> 50 0.295591
> 60 0.357264
> 70 0.420398
> 80 0.485293
> 90 0.552282
>
> whereas xpost gives:
> 10 0.115506
> 20 0.231321
> 30 0.346987
> 40 0.461987
> 50 0.575741
> 60 0.687515
> 70 0.796415
> 80 0.901347
> 90 1.000998

I changed the above program to make an arc with radius 1024 instead of
1000 so that presumably the processor can do the division with no
additional roundoff error.

My HP LaserJet Pro M452dw gives:

10 0.0582143
20 0.116652
30 0.175537
40 0.235103
50 0.295593
60 0.357266
70 0.420398
80 0.485294
90 0.55228

There is something funky going on with small radii, which is why I used
a larger radius to begin with.  If I change the radius from 1024 to 1, I
get this:

10 0.0582886
20 0.116699
30 0.175537
40 0.235107
50 0.295593
60 0.357239
70 0.42041
80 0.485291
90 0.552307

Scott
-- 
Scott Hemphill	hemphill@alumni.caltech.edu
"This isn't flying.  This is falling, with style."  -- Buzz Lightyear

[toc] | [prev] | [next] | [standalone]


#2505

Fromluser- -droog <mijoryx@yahoo.com>
Date2016-04-07 23:59 -0700
Message-ID<b7fc2f09-a477-4d96-bde9-e09e0eeab9d7@googlegroups.com>
In reply to#2491
On Tuesday, April 5, 2016 at 11:48:46 PM UTC-5, luser- -droog wrote:
> On Sunday, April 3, 2016 at 9:40:55 AM UTC-5, Scott Hemphill wrote:
>  
> > For real PostScript?  Feed this to your printer.  Modify it as desired.
> > 
> > ========================================================================
> > %!PS
> > 
> > % What is the distance of an inner Bezier curve control point to the outer
> > % point as a function of angle in an "arc" operator
> > 
<snip>
> Very cool. There may indeed be something wrong with my implementation.
> 
> gs gives:
> 10 0.0582147
> 20 0.11665
> 30 0.175536
> 40 0.235099
> 50 0.295591
> 60 0.357264
> 70 0.420398
> 80 0.485293
> 90 0.552282
> 
> whereas xpost gives:
> 10 0.115506
> 20 0.231321
> 30 0.346987
> 40 0.461987
> 50 0.575741
> 60 0.687515
> 70 0.796415
> 80 0.901347
> 90 1.000998

I've double-checked my code and my source material:
http://www.tinaja.com/glib/bezarc1.pdf

I don't see where the problem is (nor indeed what to
do about if it is located). My output looks like arcs
to me.

[toc] | [prev] | [next] | [standalone]


#2531

Fromjdaw1 <jdawiseman@gmail.com>
Date2016-04-19 02:54 -0700
Message-ID<a96fa134-7429-4692-a60c-538306d1435b@googlegroups.com>
In reply to#2491
On Wednesday, 6 April 2016 05:48:46 UTC+1, luser- -droog  wrote:
> Very cool. There may indeed be something wrong with my implementation.
> 
> gs gives:
> 10 0.0582147
> 20 0.11665
> 30 0.175536
> 40 0.235099
> 50 0.295591
> 60 0.357264
> 70 0.420398
> 80 0.485293
> 90 0.552282
> 
> whereas xpost gives:
> 10 0.115506
> 20 0.231321
> 30 0.346987
> 40 0.461987
> 50 0.575741
> 60 0.687515
> 70 0.796415
> 80 0.901347
> 90 1.000998

If xpost really had the 90° inner control points more than a radius away from the outer control points, the Bézier curve would look more square than circular. You say they look circular. So that isn't the problem. Is this a reporting error: are your curves good, but the numbers in these tables wrong?

[toc] | [prev] | [standalone]


Page 2 of 2 — ← Prev page 1 [2]

Back to top | Article view | comp.lang.postscript


csiph-web