13a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org/**************************************************************************
23a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org *
33a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org * Copyright 2009 VMware, Inc.  All Rights Reserved.
43a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org *
53a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org * Permission is hereby granted, free of charge, to any person obtaining a
63a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org * copy of this software and associated documentation files (the
73a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org * "Software"), to deal in the Software without restriction, including
83a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org * without limitation the rights to use, copy, modify, merge, publish,
93a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org * distribute, sub license, and/or sell copies of the Software, and to
103a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org * permit persons to whom the Software is furnished to do so, subject to
113a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org * the following conditions:
123a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org *
133a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org * The above copyright notice and this permission notice (including the
143a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org * next paragraph) shall be included in all copies or substantial portions
153a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org * of the Software.
163a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org *
173a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
183a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
193a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
203a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
213a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
223a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
233a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
243a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org *
253a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org **************************************************************************/
263a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
273a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#include "arc.h"
283a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
293a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#include "matrix.h"
303a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#include "bezier.h"
313a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#include "polygon.h"
323a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#include "stroker.h"
333a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#include "path.h"
343a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
353a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#include "util/u_debug.h"
36760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org#include "util/u_math.h"
373a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
383a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#ifndef M_PI
393a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#define M_PI 3.14159265358979323846
403a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#endif
413a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
423a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#define DEBUG_ARCS 0
433a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
443a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgstatic const VGfloat two_pi = M_PI * 2;
453a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
463a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
473a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgstatic const double coeffs3Low[2][4][4] = {
483a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   {
493a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      {  3.85268,   -21.229,      -0.330434,    0.0127842  },
503a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      { -1.61486,     0.706564,    0.225945,    0.263682   },
513a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      { -0.910164,    0.388383,    0.00551445,  0.00671814 },
523a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      { -0.630184,    0.192402,    0.0098871,   0.0102527  }
533a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   },
543a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   {
553a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      { -0.162211,    9.94329,     0.13723,     0.0124084  },
563a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      { -0.253135,    0.00187735,  0.0230286,   0.01264    },
573a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      { -0.0695069,  -0.0437594,   0.0120636,   0.0163087  },
583a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      { -0.0328856,  -0.00926032, -0.00173573,  0.00527385 }
593a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   }
603a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org};
613a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
623a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org/* coefficients for error estimation
633a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   while using cubic Bézier curves for approximation
643a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   1/4 <= b/a <= 1 */
653a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgstatic const double coeffs3High[2][4][4] = {
663a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   {
673a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      {  0.0899116, -19.2349,     -4.11711,     0.183362   },
683a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      {  0.138148,   -1.45804,     1.32044,     1.38474    },
693a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      {  0.230903,   -0.450262,    0.219963,    0.414038   },
703a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      {  0.0590565,  -0.101062,    0.0430592,   0.0204699  }
713a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   },
723a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   {
733a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      {  0.0164649,   9.89394,     0.0919496,   0.00760802 },
743a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      {  0.0191603,  -0.0322058,   0.0134667,  -0.0825018  },
753a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      {  0.0156192,  -0.017535,    0.00326508, -0.228157   },
763a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      { -0.0236752,   0.0405821,  -0.0173086,   0.176187   }
773a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   }
783a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org};
793a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
803a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org/* safety factor to convert the "best" error approximation
813a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   into a "max bound" error */
823a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgstatic const double safety3[] = {
833a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   0.001, 4.98, 0.207, 0.0067
843a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org};
853a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
863a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org/* The code below is from the OpenVG 1.1 Spec
873a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org * Section 18.4 */
883a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
893a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org/* Given: Points (x0, y0) and (x1, y1)
903a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org * Return: TRUE if a solution exists, FALSE otherwise
913a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org *         Circle centers are written to (cx0, cy0) and (cx1, cy1)
923a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org */
933a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgstatic VGboolean
943a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgfind_unit_circles(double x0, double y0, double x1, double y1,
953a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                  double *cx0, double *cy0,
963a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                  double *cx1, double *cy1)
973a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org{
983a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   /* Compute differences and averages */
993a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   double dx = x0 - x1;
1003a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   double dy = y0 - y1;
1013a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   double xm = (x0 + x1)/2;
1023a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   double ym = (y0 + y1)/2;
1033a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   double dsq, disc, s, sdx, sdy;
1043a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
1053a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   /* Solve for intersecting unit circles */
1063a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   dsq = dx*dx + dy*dy;
1073a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   if (dsq == 0.0) return VG_FALSE; /* Points are coincident */
1083a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   disc = 1.0/dsq - 1.0/4.0;
1093a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
1103a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   /* the precision we care about here is around float so if we're
1113a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org    * around the float defined zero then make it official to avoid
1123a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org    * precision problems later on */
1133a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   if (floatIsZero(disc))
1143a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      disc = 0.0;
1153a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
1163a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   if (disc < 0.0) return VG_FALSE; /* Points are too far apart */
1173a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   s = sqrt(disc);
1183a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   sdx = s*dx;
1193a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   sdy = s*dy;
1203a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   *cx0 = xm + sdy;
1213a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   *cy0 = ym - sdx;
1223a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   *cx1 = xm - sdy;
1233a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   *cy1 = ym + sdx;
1243a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   return VG_TRUE;
1253a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org}
1263a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
1273a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
1283a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org/* Given:  Ellipse parameters rh, rv, rot (in degrees),
1293a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org *         endpoints (x0, y0) and (x1, y1)
1303a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org * Return: TRUE if a solution exists, FALSE otherwise
1313a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org *         Ellipse centers are written to (cx0, cy0) and (cx1, cy1)
1323a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org */
1333a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgstatic VGboolean
1343a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgfind_ellipses(double rh, double rv, double rot,
1353a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org              double x0, double y0, double x1, double y1,
1363a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org              double *cx0, double *cy0, double *cx1, double *cy1)
1373a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org{
1383a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   double COS, SIN, x0p, y0p, x1p, y1p, pcx0, pcy0, pcx1, pcy1;
1393a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   /* Convert rotation angle from degrees to radians */
1403a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   rot *= M_PI/180.0;
1413a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   /* Pre-compute rotation matrix entries */
1423a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   COS = cos(rot); SIN = sin(rot);
1433a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   /* Transform (x0, y0) and (x1, y1) into unit space */
1443a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   /* using (inverse) rotate, followed by (inverse) scale   */
1453a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   x0p = (x0*COS + y0*SIN)/rh;
1463a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   y0p = (-x0*SIN + y0*COS)/rv;
1473a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   x1p = (x1*COS + y1*SIN)/rh;
1483a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   y1p = (-x1*SIN + y1*COS)/rv;
1493a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   if (!find_unit_circles(x0p, y0p, x1p, y1p,
1503a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                          &pcx0, &pcy0, &pcx1, &pcy1)) {
1513a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      return VG_FALSE;
1523a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   }
1533a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   /* Transform back to original coordinate space */
1543a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   /* using (forward) scale followed by (forward) rotate */
1553a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   pcx0 *= rh; pcy0 *= rv;
1563a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   pcx1 *= rh; pcy1 *= rv;
1573a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   *cx0 = pcx0*COS - pcy0*SIN;
1583a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   *cy0 = pcx0*SIN + pcy0*COS;
1593a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   *cx1 = pcx1*COS - pcy1*SIN;
1603a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   *cy1 = pcx1*SIN + pcy1*COS;
1613a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   return VG_TRUE;
1623a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org}
1633a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
1643a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgstatic INLINE VGboolean
1653a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgtry_to_fix_radii(struct arc *arc)
1663a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org{
1673a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   double COS, SIN, rot, x0p, y0p, x1p, y1p;
1683a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   double dx, dy, dsq, scale;
1693a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
1703a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   /* Convert rotation angle from degrees to radians */
1713a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   rot = DEGREES_TO_RADIANS(arc->theta);
1723a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
1733a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   /* Pre-compute rotation matrix entries */
1743a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   COS = cos(rot); SIN = sin(rot);
1753a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
1763a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   /* Transform (x0, y0) and (x1, y1) into unit space */
1773a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   /* using (inverse) rotate, followed by (inverse) scale   */
1783a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   x0p = (arc->x1*COS + arc->y1*SIN)/arc->a;
1793a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   y0p = (-arc->x1*SIN + arc->y1*COS)/arc->b;
1803a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   x1p = (arc->x2*COS + arc->y2*SIN)/arc->a;
1813a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   y1p = (-arc->x2*SIN + arc->y2*COS)/arc->b;
1823a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   /* Compute differences and averages */
1833a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   dx = x0p - x1p;
1843a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   dy = y0p - y1p;
1853a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
1863a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   dsq = dx*dx + dy*dy;
1873a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#if 0
1883a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   if (dsq <= 0.001) {
1893a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      debug_printf("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaaaaa\n");
1903a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   }
1913a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#endif
1923a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   scale = 1/(2/sqrt(dsq));
1933a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   arc->a *= scale;
1943a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   arc->b *= scale;
1953a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   return VG_TRUE;
1963a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org}
1973a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
1983a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgstatic INLINE double vector_normalize(double *v)
1993a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org{
2003a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   double sq = v[0] * v[0] + v[1] * v[1];
2013a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   return sqrt(sq);
2023a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org}
2033a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgstatic INLINE double vector_orientation(double *v)
2043a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org{
2053a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   double norm = vector_normalize(v);
2063a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   double cosa = v[0] / norm;
2073a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   double sina = v[1] / norm;
2083a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   return (sina>=0 ? acos(cosa) : 2*M_PI - acos(cosa));
2093a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org}
2103a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgstatic INLINE double vector_dot(double *v0,
2113a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                                double *v1)
2123a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org{
2133a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   return v0[0] * v1[0] + v0[1] * v1[1];
2143a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org}
2153a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
2163a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgstatic INLINE double vector_angles(double *v0,
2173a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                                   double *v1)
2183a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org{
2193a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   double dot = vector_dot(v0, v1);
2203a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   double norm0 = vector_normalize(v0);
2213a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   double norm1 = vector_normalize(v1);
2223a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
2233a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   return acos(dot / (norm0 * norm1));
2243a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org}
2253a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
2263a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgstatic VGboolean find_angles(struct arc *arc)
2273a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org{
2283a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   double vec0[2], vec1[2];
2293a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   double lambda1, lambda2;
2303a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   double angle;
2313a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   struct matrix matrix;
2323a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
2333a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   if (floatIsZero(arc->a) || floatIsZero(arc->b)) {
2343a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      return VG_FALSE;
2353a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   }
2363a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   /* map the points to an identity circle */
2373a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   matrix_load_identity(&matrix);
2383a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   matrix_scale(&matrix, 1.f, arc->a/arc->b);
2393a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   matrix_rotate(&matrix, -arc->theta);
2403a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   matrix_map_point(&matrix,
2413a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                    arc->x1, arc->y1,
2423a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                    &arc->x1, &arc->y1);
2433a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   matrix_map_point(&matrix,
2443a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                    arc->x2, arc->y2,
2453a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                    &arc->x2, &arc->y2);
2463a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   matrix_map_point(&matrix,
2473a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                    arc->cx, arc->cy,
2483a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                    &arc->cx, &arc->cy);
2493a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
2503a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#if DEBUG_ARCS
2513a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   debug_printf("Matrix 3 [%f, %f, %f| %f, %f, %f| %f, %f, %f]\n",
2523a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                matrix.m[0], matrix.m[1], matrix.m[2],
2533a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                matrix.m[3], matrix.m[4], matrix.m[5],
2543a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                matrix.m[6], matrix.m[7], matrix.m[8]);
2553a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   debug_printf("Endpoints [%f, %f], [%f, %f]\n",
2563a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                arc->x1, arc->y1, arc->x2, arc->y2);
2573a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#endif
2583a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
2593a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   vec0[0] = arc->x1 - arc->cx;
2603a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   vec0[1] = arc->y1 - arc->cy;
2613a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   vec1[0] = arc->x2 - arc->cx;
2623a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   vec1[1] = arc->y2 - arc->cy;
2633a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
2643a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#if DEBUG_ARCS
2653a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   debug_printf("Vec is [%f, %f], [%f, %f], [%f, %f]\n",
2663a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                vec0[0], vec0[1], vec1[0], vec1[1], arc->cx, arc->cy);
2673a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#endif
2683a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
2693a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   lambda1 = vector_orientation(vec0);
2703a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
2713a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   if (isnan(lambda1))
2723a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      lambda1 = 0.f;
2733a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
2743a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   if (arc->type == VG_SCWARC_TO ||
2753a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org       arc->type == VG_SCCWARC_TO)
2763a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      angle = vector_angles(vec0, vec1);
2773a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   else if (arc->type == VG_LCWARC_TO ||
2783a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org            arc->type == VG_LCCWARC_TO) {
2793a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      angle = 2*M_PI - vector_angles(vec0, vec1);
2803a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   } else
2813a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      abort();
2823a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
2833a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   if (isnan(angle))
2843a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      angle = M_PI;
2853a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
2863a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
2873a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   if (arc->type == VG_SCWARC_TO ||
2883a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org       arc->type == VG_LCWARC_TO)
2893a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      lambda2 = lambda1 - angle;
2903a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   else
2913a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      lambda2 = lambda1 + angle;
2923a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
2933a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#if DEBUG_ARCS
2943a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   debug_printf("Angle is %f and (%f, %f)\n", angle, lambda1, lambda2);
2953a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#endif
2963a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
2973a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#if 0
2983a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   arc->eta1 = atan2(sin(lambda1) / arc->b,
2993a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                     cos(lambda1) / arc->a);
3003a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   arc->eta2 = atan2(sin(lambda2) / arc->b,
3013a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                     cos(lambda2) / arc->a);
3023a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
3033a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   /* make sure we have eta1 <= eta2 <= eta1 + 2 PI */
3043a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   arc->eta2 -= two_pi * floor((arc->eta2 - arc->eta1) / two_pi);
3053a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
3063a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   /* the preceding correction fails if we have exactly et2 - eta1 = 2 PI
3073a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      it reduces the interval to zero length */
3083a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   if ((lambda2 - lambda1 > M_PI) && (arc->eta2 - arc->eta1 < M_PI)) {
3093a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      arc->eta2 += 2 * M_PI;
3103a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   }
3113a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#else
3123a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   arc->eta1 = lambda1;
3133a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   arc->eta2 = lambda2;
3143a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#endif
3153a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
3163a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   return VG_TRUE;
3173a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org}
3183a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
3193a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#if DEBUG_ARCS
3203a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgstatic void check_endpoints(struct arc *arc)
3213a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org{
3223a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   double x1, y1, x2, y2;
3233a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
3243a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   double a_cos_eta1 = arc->a * cos(arc->eta1);
3253a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   double b_sin_eta1 = arc->b * sin(arc->eta1);
3263a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   x1 = arc->cx + a_cos_eta1 * arc->cos_theta -
3273a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org        b_sin_eta1 * arc->sin_theta;
3283a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   y1 = arc->cy + a_cos_eta1 * arc->sin_theta +
3293a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org        b_sin_eta1 * arc->cos_theta;
3303a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
3313a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   double a_cos_eta2 = arc->a * cos(arc->eta2);
3323a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   double b_sin_eta2 = arc->b * sin(arc->eta2);
3333a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   x2 = arc->cx + a_cos_eta2 * arc->cos_theta -
3343a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org        b_sin_eta2 * arc->sin_theta;
3353a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   y2 = arc->cy + a_cos_eta2 * arc->sin_theta +
3363a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org        b_sin_eta2 * arc->cos_theta;
3373a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
3383a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   debug_printf("Computed (%f, %f), (%f, %f)\n",
3393a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                x1, y1, x2, y2);
3403a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   debug_printf("Real     (%f, %f), (%f, %f)\n",
3413a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                arc->x1, arc->y1,
3423a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                arc->x2, arc->y2);
3433a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org}
3443a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#endif
3453a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
3463a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgvoid arc_init(struct arc *arc,
3473a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org              VGPathSegment type,
3483a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org              VGfloat x1, VGfloat y1,
3493a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org              VGfloat x2, VGfloat y2,
3503a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org              VGfloat rh, VGfloat rv,
3513a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org              VGfloat rot)
3523a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org{
3533a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   assert(type == VG_SCCWARC_TO ||
3543a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org          type == VG_SCWARC_TO ||
3553a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org          type == VG_LCCWARC_TO ||
3563a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org          type == VG_LCWARC_TO);
3573a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   arc->type = type;
3583a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   arc->x1  = x1;
3593a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   arc->y1  = y1;
3603a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   arc->x2  = x2;
3613a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   arc->y2  = y2;
3623a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   arc->a   = rh;
3633a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   arc->b   = rv;
3643a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   arc->theta = rot;
3653a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   arc->cos_theta = cos(arc->theta);
3663a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   arc->sin_theta = sin(arc->theta);
3673a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   {
3683a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      double cx0, cy0, cx1, cy1;
3693a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      double cx, cy;
3703a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      arc->is_valid =  find_ellipses(rh, rv, rot, x1, y1, x2, y2,
3713a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                                     &cx0, &cy0, &cx1, &cy1);
3723a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
3733a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      if (!arc->is_valid && try_to_fix_radii(arc)) {
3743a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org         rh = arc->a;
3753a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org         rv = arc->b;
3763a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org         arc->is_valid =
3773a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org            find_ellipses(rh, rv, rot, x1, y1, x2, y2,
3783a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                          &cx0, &cy0, &cx1, &cy1);
3793a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      }
3803a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
3813a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      if (type == VG_SCWARC_TO ||
3823a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org          type == VG_LCCWARC_TO) {
3833a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org         cx = cx1;
3843a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org         cy = cy1;
3853a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      } else {
3863a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org         cx = cx0;
3873a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org         cy = cy0;
3883a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      }
3893a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#if DEBUG_ARCS
3903a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      debug_printf("Centers are : (%f, %f) , (%f, %f). Real (%f, %f)\n",
3913a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                   cx0, cy0, cx1, cy1, cx, cy);
3923a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#endif
3933a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      arc->cx = cx;
3943a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      arc->cy = cy;
3953a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      if (arc->is_valid) {
3963a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org         arc->is_valid = find_angles(arc);
3973a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#if DEBUG_ARCS
3983a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org         check_endpoints(arc);
3993a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#endif
4003a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org         /* remap a few points. find_angles requires
4013a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org          * rot in angles, the rest of the code
4023a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org          * will need them in radians. and find_angles
4033a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org          * modifies the center to match an identity
4043a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org          * circle so lets reset it */
4053a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org         arc->theta = DEGREES_TO_RADIANS(rot);
4063a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org         arc->cos_theta = cos(arc->theta);
4073a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org         arc->sin_theta = sin(arc->theta);
4083a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org         arc->cx = cx;
4093a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org         arc->cy = cy;
4103a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      }
4113a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   }
4123a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org}
4133a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
4143a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgstatic INLINE double rational_function(double x, const double *c)
4153a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org{
4163a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   return (x * (x * c[0] + c[1]) + c[2]) / (x + c[3]);
4173a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org}
4183a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
4193a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgstatic double estimate_error(struct arc *arc,
4203a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                             double etaA, double etaB)
4213a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org{
4223a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   double eta  = 0.5 * (etaA + etaB);
4233a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
4243a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   double x    = arc->b / arc->a;
4253a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   double dEta = etaB - etaA;
4263a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   double cos2 = cos(2 * eta);
4273a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   double cos4 = cos(4 * eta);
4283a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   double cos6 = cos(6 * eta);
4293a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   double c0, c1;
4303a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
4313a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   /* select the right coeficients set according to degree and b/a */
4323a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   const double (*coeffs)[4][4];
4333a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   const double *safety;
4343a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   coeffs = (x < 0.25) ? coeffs3Low : coeffs3High;
4353a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   safety = safety3;
4363a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
4373a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   c0 = rational_function(x, coeffs[0][0])
4383a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org        + cos2 * rational_function(x, coeffs[0][1])
4393a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org        + cos4 * rational_function(x, coeffs[0][2])
4403a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org        + cos6 * rational_function(x, coeffs[0][3]);
4413a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
4423a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   c1 = rational_function(x, coeffs[1][0])
4433a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org        + cos2 * rational_function(x, coeffs[1][1])
4443a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org        + cos4 * rational_function(x, coeffs[1][2])
4453a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org        + cos6 * rational_function(x, coeffs[1][3]);
4463a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
4473a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   return rational_function(x, safety) * arc->a * exp(c0 + c1 * dEta);
4483a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org}
4493a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
4503a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgstruct arc_cb {
4513a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   void (*move)(struct arc_cb *cb, VGfloat x, VGfloat y);
4523a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   void (*point)(struct arc_cb *cb, VGfloat x, VGfloat y);
4533a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   void (*bezier)(struct arc_cb *cb, struct bezier *bezier);
4543a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
4553a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   void *user_data;
4563a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org};
4573a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
4583a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgstatic void cb_null_move(struct arc_cb *cb, VGfloat x, VGfloat y)
4593a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org{
4603a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org}
4613a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
4623a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgstatic void polygon_point(struct arc_cb *cb, VGfloat x, VGfloat y)
4633a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org{
4643a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   struct polygon *poly = (struct polygon*)cb->user_data;
4653a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   polygon_vertex_append(poly, x, y);
4663a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org}
4673a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
4683a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgstatic void polygon_bezier(struct arc_cb *cb, struct bezier *bezier)
4693a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org{
4703a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   struct polygon *poly = (struct polygon*)cb->user_data;
4713a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   bezier_add_to_polygon(bezier, poly);
4723a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org}
4733a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
4743a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgstatic void stroke_point(struct arc_cb *cb, VGfloat x, VGfloat y)
4753a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org{
4763a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   struct stroker *stroker = (struct stroker*)cb->user_data;
4773a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   stroker_line_to(stroker, x, y);
4783a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org}
4793a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
4803a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgstatic void stroke_curve(struct arc_cb *cb, struct bezier *bezier)
4813a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org{
4823a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   struct stroker *stroker = (struct stroker*)cb->user_data;
4833a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   stroker_curve_to(stroker,
4843a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                    bezier->x2, bezier->y2,
4853a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                    bezier->x3, bezier->y3,
4863a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                    bezier->x4, bezier->y4);
4873a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org}
4883a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
4893a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgstatic void stroke_emit_point(struct arc_cb *cb, VGfloat x, VGfloat y)
4903a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org{
4913a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   struct stroker *stroker = (struct stroker*)cb->user_data;
4923a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   stroker_emit_line_to(stroker, x, y);
4933a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org}
4943a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
4953a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgstatic void stroke_emit_curve(struct arc_cb *cb, struct bezier *bezier)
4963a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org{
4973a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   struct stroker *stroker = (struct stroker*)cb->user_data;
4983a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   stroker_emit_curve_to(stroker,
4993a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                         bezier->x2, bezier->y2,
5003a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                         bezier->x3, bezier->y3,
5013a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                         bezier->x4, bezier->y4);
5023a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org}
5033a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
5043a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgstatic void arc_path_move(struct arc_cb *cb, VGfloat x, VGfloat y)
5053a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org{
5063a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   struct path *path = (struct path*)cb->user_data;
5073a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   path_move_to(path, x, y);
5083a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org}
5093a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
5103a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgstatic void arc_path_point(struct arc_cb *cb, VGfloat x, VGfloat y)
5113a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org{
5123a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   struct path *path = (struct path*)cb->user_data;
5133a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   path_line_to(path, x, y);
5143a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org}
5153a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
5163a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgstatic void arc_path_bezier(struct arc_cb *cb, struct bezier *bezier)
5173a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org{
5183a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   struct path *path = (struct path*)cb->user_data;
5193a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   path_cubic_to(path,
5203a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                 bezier->x2, bezier->y2,
5213a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                 bezier->x3, bezier->y3,
5223a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                 bezier->x4, bezier->y4);
5233a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org}
5243a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
5253a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgstatic INLINE int num_beziers_needed(struct arc *arc)
5263a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org{
5273a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   double threshold = 0.05;
5283a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   VGboolean found = VG_FALSE;
5293a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   int n = 1;
5303a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   double min_eta, max_eta;
5313a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
5323a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   min_eta = MIN2(arc->eta1, arc->eta2);
5333a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   max_eta = MAX2(arc->eta1, arc->eta2);
5343a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
5353a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   while ((! found) && (n < 1024)) {
5363a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      double d_eta = (max_eta - min_eta) / n;
5373a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      if (d_eta <= 0.5 * M_PI) {
5383a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org         double eta_b = min_eta;
539760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org         int i;
5403a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org         found = VG_TRUE;
5413a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org         for (i = 0; found && (i < n); ++i) {
5423a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org            double etaA = eta_b;
5433a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org            eta_b += d_eta;
5443a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org            found = (estimate_error(arc, etaA, eta_b) <= threshold);
5453a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org         }
5463a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      }
5473a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      n = n << 1;
5483a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   }
5493a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
5503a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   return n;
5513a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org}
5523a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
5533a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgstatic void arc_to_beziers(struct arc *arc,
5543a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                           struct arc_cb cb,
5553a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                           struct matrix *matrix)
5563a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org{
5573a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   int i;
5583a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   int n = 1;
5593a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   double d_eta, eta_b, cos_eta_b,
5603a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      sin_eta_b, a_cos_eta_b, b_sin_eta_b, a_sin_eta_b,
5613a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      b_cos_eta_b, x_b, y_b, x_b_dot, y_b_dot, lx, ly;
5623a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   double t, alpha;
5633a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
5643a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   { /* always move to the start of the arc */
5653a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      VGfloat x = arc->x1;
5663a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      VGfloat y = arc->y1;
5673a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      matrix_map_point(matrix, x, y, &x, &y);
5683a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      cb.move(&cb, x, y);
5693a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   }
5703a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
5713a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   if (!arc->is_valid) {
5723a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      VGfloat x = arc->x2;
5733a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      VGfloat y = arc->y2;
5743a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      matrix_map_point(matrix, x, y, &x, &y);
5753a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      cb.point(&cb, x, y);
5763a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      return;
5773a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   }
5783a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
5793a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   /* find the number of Bézier curves needed */
5803a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   n = num_beziers_needed(arc);
5813a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
5823a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   d_eta = (arc->eta2 - arc->eta1) / n;
5833a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   eta_b = arc->eta1;
5843a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
5853a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   cos_eta_b  = cos(eta_b);
5863a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   sin_eta_b  = sin(eta_b);
5873a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   a_cos_eta_b = arc->a * cos_eta_b;
5883a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   b_sin_eta_b = arc->b * sin_eta_b;
5893a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   a_sin_eta_b = arc->a * sin_eta_b;
5903a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   b_cos_eta_b = arc->b * cos_eta_b;
5913a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   x_b       = arc->cx + a_cos_eta_b * arc->cos_theta -
5923a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org               b_sin_eta_b * arc->sin_theta;
5933a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   y_b       = arc->cy + a_cos_eta_b * arc->sin_theta +
5943a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org               b_sin_eta_b * arc->cos_theta;
5953a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   x_b_dot    = -a_sin_eta_b * arc->cos_theta -
5963a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                b_cos_eta_b * arc->sin_theta;
5973a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   y_b_dot    = -a_sin_eta_b * arc->sin_theta +
5983a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                b_cos_eta_b * arc->cos_theta;
5993a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
6003a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   {
6013a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      VGfloat x = x_b, y = y_b;
6023a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      matrix_map_point(matrix, x, y, &x, &y);
6033a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      cb.point(&cb, x, y);
6043a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   }
6053a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   lx = x_b;
6063a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   ly = y_b;
6073a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
6083a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   t     = tan(0.5 * d_eta);
6093a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   alpha = sin(d_eta) * (sqrt(4 + 3 * t * t) - 1) / 3;
6103a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
6113a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   for (i = 0; i < n; ++i) {
6123a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      struct bezier bezier;
6133a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      double xA    = x_b;
6143a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      double yA    = y_b;
6153a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      double xADot = x_b_dot;
6163a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      double yADot = y_b_dot;
6173a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
6183a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      eta_b    += d_eta;
6193a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      cos_eta_b  = cos(eta_b);
6203a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      sin_eta_b  = sin(eta_b);
6213a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      a_cos_eta_b = arc->a * cos_eta_b;
6223a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      b_sin_eta_b = arc->b * sin_eta_b;
6233a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      a_sin_eta_b = arc->a * sin_eta_b;
6243a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      b_cos_eta_b = arc->b * cos_eta_b;
6253a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      x_b       = arc->cx + a_cos_eta_b * arc->cos_theta -
6263a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                  b_sin_eta_b * arc->sin_theta;
6273a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      y_b       = arc->cy + a_cos_eta_b * arc->sin_theta +
6283a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                  b_sin_eta_b * arc->cos_theta;
6293a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      x_b_dot    = -a_sin_eta_b * arc->cos_theta -
6303a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                   b_cos_eta_b * arc->sin_theta;
6313a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      y_b_dot    = -a_sin_eta_b * arc->sin_theta +
6323a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                   b_cos_eta_b * arc->cos_theta;
6333a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
6343a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      bezier_init(&bezier,
6353a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                  lx, ly,
6363a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                  (float) (xA + alpha * xADot), (float) (yA + alpha * yADot),
6373a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                  (float) (x_b - alpha * x_b_dot), (float) (y_b - alpha * y_b_dot),
6383a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                  (float) x_b,                   (float) y_b);
6393a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#if 0
6403a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      debug_printf("%d) Bezier (%f, %f), (%f, %f), (%f, %f), (%f, %f)\n",
6413a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                   i,
6423a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                   bezier.x1, bezier.y1,
6433a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                   bezier.x2, bezier.y2,
6443a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                   bezier.x3, bezier.y3,
6453a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                   bezier.x4, bezier.y4);
6463a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org#endif
6473a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      bezier_transform(&bezier, matrix);
6483a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      cb.bezier(&cb, &bezier);
6493a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      lx = x_b;
6503a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org      ly = y_b;
6513a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   }
6523a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org}
6533a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
6543a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
6553a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgvoid arc_add_to_polygon(struct arc *arc,
6563a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                        struct polygon *poly,
6573a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                        struct matrix *matrix)
6583a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org{
6593a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   struct arc_cb cb;
6603a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
6613a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   cb.move = cb_null_move;
6623a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   cb.point = polygon_point;
6633a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   cb.bezier = polygon_bezier;
6643a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   cb.user_data = poly;
6653a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
6663a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   arc_to_beziers(arc, cb, matrix);
6673a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org}
6683a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
6693a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgvoid arc_stroke_cb(struct arc *arc,
6703a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                   struct stroker *stroke,
6713a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                   struct matrix *matrix)
6723a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org{
6733a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   struct arc_cb cb;
6743a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
6753a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   cb.move = cb_null_move;
6763a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   cb.point = stroke_point;
6773a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   cb.bezier = stroke_curve;
6783a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   cb.user_data = stroke;
6793a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
6803a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   arc_to_beziers(arc, cb, matrix);
6813a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org}
6823a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
6833a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgvoid arc_stroker_emit(struct arc *arc,
6843a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                      struct stroker *stroker,
6853a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                      struct matrix *matrix)
6863a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org{
6873a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   struct arc_cb cb;
6883a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
6893a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   cb.move = cb_null_move;
6903a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   cb.point = stroke_emit_point;
6913a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   cb.bezier = stroke_emit_curve;
6923a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   cb.user_data = stroker;
6933a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
6943a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   arc_to_beziers(arc, cb, matrix);
6953a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org}
6963a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
6973a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.orgvoid arc_to_path(struct arc *arc,
6983a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                 struct path *path,
6993a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org                 struct matrix *matrix)
7003a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org{
7013a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   struct arc_cb cb;
7023a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
7033a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   cb.move = arc_path_move;
7043a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   cb.point = arc_path_point;
7053a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   cb.bezier = arc_path_bezier;
7063a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   cb.user_data = path;
7073a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org
7083a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org   arc_to_beziers(arc, cb, matrix);
7093a0db227ffe90888ad760c61a63226988c974e0apatrick@chromium.org}
710