1544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin/**************************************************************************
2544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin *
3544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin * Copyright 2009 VMware, Inc.  All Rights Reserved.
4544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin *
5544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin * Permission is hereby granted, free of charge, to any person obtaining a
6544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin * copy of this software and associated documentation files (the
7544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin * "Software"), to deal in the Software without restriction, including
8544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin * without limitation the rights to use, copy, modify, merge, publish,
9544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin * distribute, sub license, and/or sell copies of the Software, and to
10544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin * permit persons to whom the Software is furnished to do so, subject to
11544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin * the following conditions:
12544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin *
13544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin * The above copyright notice and this permission notice (including the
14544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin * next paragraph) shall be included in all copies or substantial portions
15544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin * of the Software.
16544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin *
17544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
21544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin *
25544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin **************************************************************************/
26544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
27544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#include "arc.h"
28544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
29544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#include "matrix.h"
30544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#include "bezier.h"
31544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#include "polygon.h"
32544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#include "stroker.h"
33544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#include "path.h"
34544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
35544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#include "util/u_debug.h"
36e5b5d84e8a87a5603a84f8c4625592a278bcf9afChia-I Wu#include "util/u_math.h"
37544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
38544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#ifndef M_PI
39544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#define M_PI 3.14159265358979323846
40544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#endif
41544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
42544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#define DEBUG_ARCS 0
43544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
44544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic const VGfloat two_pi = M_PI * 2;
45544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
46544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
47544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic const double coeffs3Low[2][4][4] = {
48544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   {
49544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      {  3.85268,   -21.229,      -0.330434,    0.0127842  },
50544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      { -1.61486,     0.706564,    0.225945,    0.263682   },
51544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      { -0.910164,    0.388383,    0.00551445,  0.00671814 },
52544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      { -0.630184,    0.192402,    0.0098871,   0.0102527  }
53544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   },
54544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   {
55544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      { -0.162211,    9.94329,     0.13723,     0.0124084  },
56544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      { -0.253135,    0.00187735,  0.0230286,   0.01264    },
57544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      { -0.0695069,  -0.0437594,   0.0120636,   0.0163087  },
58544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      { -0.0328856,  -0.00926032, -0.00173573,  0.00527385 }
59544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
60544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin};
61544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
62544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin/* coefficients for error estimation
63544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   while using cubic Bézier curves for approximation
64544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   1/4 <= b/a <= 1 */
65544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic const double coeffs3High[2][4][4] = {
66544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   {
67544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      {  0.0899116, -19.2349,     -4.11711,     0.183362   },
68544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      {  0.138148,   -1.45804,     1.32044,     1.38474    },
69544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      {  0.230903,   -0.450262,    0.219963,    0.414038   },
70544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      {  0.0590565,  -0.101062,    0.0430592,   0.0204699  }
71544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   },
72544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   {
73544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      {  0.0164649,   9.89394,     0.0919496,   0.00760802 },
74544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      {  0.0191603,  -0.0322058,   0.0134667,  -0.0825018  },
75544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      {  0.0156192,  -0.017535,    0.00326508, -0.228157   },
76544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      { -0.0236752,   0.0405821,  -0.0173086,   0.176187   }
77544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
78544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin};
79544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
80544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin/* safety factor to convert the "best" error approximation
81544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   into a "max bound" error */
82544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic const double safety3[] = {
83544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   0.001, 4.98, 0.207, 0.0067
84544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin};
85544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
86544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin/* The code below is from the OpenVG 1.1 Spec
87544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin * Section 18.4 */
88544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
89544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin/* Given: Points (x0, y0) and (x1, y1)
90544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin * Return: TRUE if a solution exists, FALSE otherwise
91544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin *         Circle centers are written to (cx0, cy0) and (cx1, cy1)
92544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin */
93544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic VGboolean
94544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinfind_unit_circles(double x0, double y0, double x1, double y1,
95544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                  double *cx0, double *cy0,
96544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                  double *cx1, double *cy1)
97544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
98544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   /* Compute differences and averages */
99544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   double dx = x0 - x1;
100544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   double dy = y0 - y1;
101544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   double xm = (x0 + x1)/2;
102544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   double ym = (y0 + y1)/2;
103544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   double dsq, disc, s, sdx, sdy;
104544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
105544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   /* Solve for intersecting unit circles */
106544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   dsq = dx*dx + dy*dy;
107544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (dsq == 0.0) return VG_FALSE; /* Points are coincident */
108544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   disc = 1.0/dsq - 1.0/4.0;
109544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
110544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   /* the precision we care about here is around float so if we're
111544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin    * around the float defined zero then make it official to avoid
112544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin    * precision problems later on */
113544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (floatIsZero(disc))
114544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      disc = 0.0;
115544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
116544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (disc < 0.0) return VG_FALSE; /* Points are too far apart */
117544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   s = sqrt(disc);
118544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   sdx = s*dx;
119544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   sdy = s*dy;
120544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   *cx0 = xm + sdy;
121544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   *cy0 = ym - sdx;
122544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   *cx1 = xm - sdy;
123544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   *cy1 = ym + sdx;
124544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   return VG_TRUE;
125544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
126544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
127544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
128544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin/* Given:  Ellipse parameters rh, rv, rot (in degrees),
129544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin *         endpoints (x0, y0) and (x1, y1)
130544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin * Return: TRUE if a solution exists, FALSE otherwise
131544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin *         Ellipse centers are written to (cx0, cy0) and (cx1, cy1)
132544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin */
133544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic VGboolean
134544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinfind_ellipses(double rh, double rv, double rot,
135544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin              double x0, double y0, double x1, double y1,
136544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin              double *cx0, double *cy0, double *cx1, double *cy1)
137544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
138544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   double COS, SIN, x0p, y0p, x1p, y1p, pcx0, pcy0, pcx1, pcy1;
139544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   /* Convert rotation angle from degrees to radians */
140544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   rot *= M_PI/180.0;
141544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   /* Pre-compute rotation matrix entries */
142544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   COS = cos(rot); SIN = sin(rot);
143544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   /* Transform (x0, y0) and (x1, y1) into unit space */
144544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   /* using (inverse) rotate, followed by (inverse) scale   */
145544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   x0p = (x0*COS + y0*SIN)/rh;
146544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   y0p = (-x0*SIN + y0*COS)/rv;
147544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   x1p = (x1*COS + y1*SIN)/rh;
148544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   y1p = (-x1*SIN + y1*COS)/rv;
149544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (!find_unit_circles(x0p, y0p, x1p, y1p,
150544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                          &pcx0, &pcy0, &pcx1, &pcy1)) {
151544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return VG_FALSE;
152544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
153544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   /* Transform back to original coordinate space */
154544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   /* using (forward) scale followed by (forward) rotate */
155544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   pcx0 *= rh; pcy0 *= rv;
156544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   pcx1 *= rh; pcy1 *= rv;
157544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   *cx0 = pcx0*COS - pcy0*SIN;
158544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   *cy0 = pcx0*SIN + pcy0*COS;
159544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   *cx1 = pcx1*COS - pcy1*SIN;
160544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   *cy1 = pcx1*SIN + pcy1*COS;
161544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   return VG_TRUE;
162544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
163544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
164544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic INLINE VGboolean
165544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusintry_to_fix_radii(struct arc *arc)
166544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
167544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   double COS, SIN, rot, x0p, y0p, x1p, y1p;
168544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   double dx, dy, dsq, scale;
169544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
170544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   /* Convert rotation angle from degrees to radians */
171544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   rot = DEGREES_TO_RADIANS(arc->theta);
172544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
173544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   /* Pre-compute rotation matrix entries */
174544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   COS = cos(rot); SIN = sin(rot);
175544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
176544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   /* Transform (x0, y0) and (x1, y1) into unit space */
177544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   /* using (inverse) rotate, followed by (inverse) scale   */
178544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   x0p = (arc->x1*COS + arc->y1*SIN)/arc->a;
179544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   y0p = (-arc->x1*SIN + arc->y1*COS)/arc->b;
180544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   x1p = (arc->x2*COS + arc->y2*SIN)/arc->a;
181544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   y1p = (-arc->x2*SIN + arc->y2*COS)/arc->b;
182544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   /* Compute differences and averages */
183544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   dx = x0p - x1p;
184544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   dy = y0p - y1p;
185544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
186544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   dsq = dx*dx + dy*dy;
187544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#if 0
188544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (dsq <= 0.001) {
189544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      debug_printf("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaaaaa\n");
190544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
191544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#endif
192544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   scale = 1/(2/sqrt(dsq));
193544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   arc->a *= scale;
194544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   arc->b *= scale;
195544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   return VG_TRUE;
196544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
197544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
198544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic INLINE double vector_normalize(double *v)
199544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
200544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   double sq = v[0] * v[0] + v[1] * v[1];
201544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   return sqrt(sq);
202544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
203544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic INLINE double vector_orientation(double *v)
204544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
205544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   double norm = vector_normalize(v);
206544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   double cosa = v[0] / norm;
207544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   double sina = v[1] / norm;
208544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   return (sina>=0 ? acos(cosa) : 2*M_PI - acos(cosa));
209544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
210544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic INLINE double vector_dot(double *v0,
211544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                double *v1)
212544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
213544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   return v0[0] * v1[0] + v0[1] * v1[1];
214544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
215544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
216544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic INLINE double vector_angles(double *v0,
217544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                   double *v1)
218544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
219544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   double dot = vector_dot(v0, v1);
220544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   double norm0 = vector_normalize(v0);
221544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   double norm1 = vector_normalize(v1);
222544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
223544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   return acos(dot / (norm0 * norm1));
224544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
225544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
226544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic VGboolean find_angles(struct arc *arc)
227544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
228544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   double vec0[2], vec1[2];
229544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   double lambda1, lambda2;
230544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   double angle;
231544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct matrix matrix;
232544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
233544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (floatIsZero(arc->a) || floatIsZero(arc->b)) {
234544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return VG_FALSE;
235544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
236544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   /* map the points to an identity circle */
237544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   matrix_load_identity(&matrix);
238544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   matrix_scale(&matrix, 1.f, arc->a/arc->b);
239544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   matrix_rotate(&matrix, -arc->theta);
240544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   matrix_map_point(&matrix,
241544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                    arc->x1, arc->y1,
242544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                    &arc->x1, &arc->y1);
243544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   matrix_map_point(&matrix,
244544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                    arc->x2, arc->y2,
245544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                    &arc->x2, &arc->y2);
246544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   matrix_map_point(&matrix,
247544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                    arc->cx, arc->cy,
248544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                    &arc->cx, &arc->cy);
249544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
250544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#if DEBUG_ARCS
251544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   debug_printf("Matrix 3 [%f, %f, %f| %f, %f, %f| %f, %f, %f]\n",
252544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                matrix.m[0], matrix.m[1], matrix.m[2],
253544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                matrix.m[3], matrix.m[4], matrix.m[5],
254544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                matrix.m[6], matrix.m[7], matrix.m[8]);
255544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   debug_printf("Endpoints [%f, %f], [%f, %f]\n",
256544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                arc->x1, arc->y1, arc->x2, arc->y2);
257544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#endif
258544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
259544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   vec0[0] = arc->x1 - arc->cx;
260544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   vec0[1] = arc->y1 - arc->cy;
261544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   vec1[0] = arc->x2 - arc->cx;
262544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   vec1[1] = arc->y2 - arc->cy;
263544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
264544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#if DEBUG_ARCS
265544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   debug_printf("Vec is [%f, %f], [%f, %f], [%f, %f]\n",
266544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                vec0[0], vec0[1], vec1[0], vec1[1], arc->cx, arc->cy);
267544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#endif
268544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
269544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   lambda1 = vector_orientation(vec0);
270544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
271544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (isnan(lambda1))
272544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      lambda1 = 0.f;
273544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
274544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (arc->type == VG_SCWARC_TO ||
275544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin       arc->type == VG_SCCWARC_TO)
276544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      angle = vector_angles(vec0, vec1);
277544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   else if (arc->type == VG_LCWARC_TO ||
278544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            arc->type == VG_LCCWARC_TO) {
279544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      angle = 2*M_PI - vector_angles(vec0, vec1);
280544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   } else
281544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      abort();
282544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
283544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (isnan(angle))
284544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      angle = M_PI;
285544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
286544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
287544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (arc->type == VG_SCWARC_TO ||
288544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin       arc->type == VG_LCWARC_TO)
289544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      lambda2 = lambda1 - angle;
290544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   else
291544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      lambda2 = lambda1 + angle;
292544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
293544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#if DEBUG_ARCS
294544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   debug_printf("Angle is %f and (%f, %f)\n", angle, lambda1, lambda2);
295544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#endif
296544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
297544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#if 0
298544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   arc->eta1 = atan2(sin(lambda1) / arc->b,
299544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                     cos(lambda1) / arc->a);
300544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   arc->eta2 = atan2(sin(lambda2) / arc->b,
301544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                     cos(lambda2) / arc->a);
302544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
303544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   /* make sure we have eta1 <= eta2 <= eta1 + 2 PI */
304544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   arc->eta2 -= two_pi * floor((arc->eta2 - arc->eta1) / two_pi);
305544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
306544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   /* the preceding correction fails if we have exactly et2 - eta1 = 2 PI
307544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      it reduces the interval to zero length */
308544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if ((lambda2 - lambda1 > M_PI) && (arc->eta2 - arc->eta1 < M_PI)) {
309544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      arc->eta2 += 2 * M_PI;
310544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
311544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#else
312544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   arc->eta1 = lambda1;
313544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   arc->eta2 = lambda2;
314544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#endif
315544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
316544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   return VG_TRUE;
317544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
318544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
319544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#if DEBUG_ARCS
320544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic void check_endpoints(struct arc *arc)
321544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
322544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   double x1, y1, x2, y2;
323544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
324544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   double a_cos_eta1 = arc->a * cos(arc->eta1);
325544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   double b_sin_eta1 = arc->b * sin(arc->eta1);
326544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   x1 = arc->cx + a_cos_eta1 * arc->cos_theta -
327544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin        b_sin_eta1 * arc->sin_theta;
328544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   y1 = arc->cy + a_cos_eta1 * arc->sin_theta +
329544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin        b_sin_eta1 * arc->cos_theta;
330544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
331544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   double a_cos_eta2 = arc->a * cos(arc->eta2);
332544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   double b_sin_eta2 = arc->b * sin(arc->eta2);
333544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   x2 = arc->cx + a_cos_eta2 * arc->cos_theta -
334544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin        b_sin_eta2 * arc->sin_theta;
335544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   y2 = arc->cy + a_cos_eta2 * arc->sin_theta +
336544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin        b_sin_eta2 * arc->cos_theta;
337544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
338544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   debug_printf("Computed (%f, %f), (%f, %f)\n",
339544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                x1, y1, x2, y2);
340544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   debug_printf("Real     (%f, %f), (%f, %f)\n",
341544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                arc->x1, arc->y1,
342544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                arc->x2, arc->y2);
343544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
344544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#endif
345544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
346544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinvoid arc_init(struct arc *arc,
347544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin              VGPathSegment type,
348544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin              VGfloat x1, VGfloat y1,
349544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin              VGfloat x2, VGfloat y2,
350544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin              VGfloat rh, VGfloat rv,
351544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin              VGfloat rot)
352544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
353544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   assert(type == VG_SCCWARC_TO ||
354544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin          type == VG_SCWARC_TO ||
355544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin          type == VG_LCCWARC_TO ||
356544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin          type == VG_LCWARC_TO);
357544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   arc->type = type;
358544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   arc->x1  = x1;
359544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   arc->y1  = y1;
360544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   arc->x2  = x2;
361544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   arc->y2  = y2;
362544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   arc->a   = rh;
363544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   arc->b   = rv;
364544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   arc->theta = rot;
365544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   arc->cos_theta = cos(arc->theta);
366544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   arc->sin_theta = sin(arc->theta);
367544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   {
368544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      double cx0, cy0, cx1, cy1;
369544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      double cx, cy;
370544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      arc->is_valid =  find_ellipses(rh, rv, rot, x1, y1, x2, y2,
371544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                     &cx0, &cy0, &cx1, &cy1);
372544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
373544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      if (!arc->is_valid && try_to_fix_radii(arc)) {
374544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         rh = arc->a;
375544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         rv = arc->b;
376544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         arc->is_valid =
377544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            find_ellipses(rh, rv, rot, x1, y1, x2, y2,
378544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                          &cx0, &cy0, &cx1, &cy1);
379544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
380544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
381544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      if (type == VG_SCWARC_TO ||
382544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin          type == VG_LCCWARC_TO) {
383544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         cx = cx1;
384544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         cy = cy1;
385544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      } else {
386544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         cx = cx0;
387544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         cy = cy0;
388544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
389544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#if DEBUG_ARCS
390544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      debug_printf("Centers are : (%f, %f) , (%f, %f). Real (%f, %f)\n",
391544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                   cx0, cy0, cx1, cy1, cx, cy);
392544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#endif
393544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      arc->cx = cx;
394544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      arc->cy = cy;
395544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      if (arc->is_valid) {
396544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         arc->is_valid = find_angles(arc);
397544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#if DEBUG_ARCS
398544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         check_endpoints(arc);
399544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#endif
400544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         /* remap a few points. find_angles requires
401544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin          * rot in angles, the rest of the code
402544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin          * will need them in radians. and find_angles
403544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin          * modifies the center to match an identity
404544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin          * circle so lets reset it */
405544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         arc->theta = DEGREES_TO_RADIANS(rot);
406544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         arc->cos_theta = cos(arc->theta);
407544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         arc->sin_theta = sin(arc->theta);
408544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         arc->cx = cx;
409544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         arc->cy = cy;
410544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
411544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
412544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
413544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
414544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic INLINE double rational_function(double x, const double *c)
415544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
416544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   return (x * (x * c[0] + c[1]) + c[2]) / (x + c[3]);
417544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
418544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
419544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic double estimate_error(struct arc *arc,
420544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                             double etaA, double etaB)
421544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
422544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   double eta  = 0.5 * (etaA + etaB);
423544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
424544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   double x    = arc->b / arc->a;
425544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   double dEta = etaB - etaA;
426544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   double cos2 = cos(2 * eta);
427544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   double cos4 = cos(4 * eta);
428544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   double cos6 = cos(6 * eta);
429544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   double c0, c1;
430544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
431544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   /* select the right coeficients set according to degree and b/a */
432544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   const double (*coeffs)[4][4];
433544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   const double *safety;
434544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   coeffs = (x < 0.25) ? coeffs3Low : coeffs3High;
435544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   safety = safety3;
436544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
437544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   c0 = rational_function(x, coeffs[0][0])
438544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin        + cos2 * rational_function(x, coeffs[0][1])
439544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin        + cos4 * rational_function(x, coeffs[0][2])
440544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin        + cos6 * rational_function(x, coeffs[0][3]);
441544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
442544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   c1 = rational_function(x, coeffs[1][0])
443544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin        + cos2 * rational_function(x, coeffs[1][1])
444544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin        + cos4 * rational_function(x, coeffs[1][2])
445544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin        + cos6 * rational_function(x, coeffs[1][3]);
446544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
447544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   return rational_function(x, safety) * arc->a * exp(c0 + c1 * dEta);
448544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
449544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
450544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstruct arc_cb {
451544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   void (*move)(struct arc_cb *cb, VGfloat x, VGfloat y);
452544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   void (*point)(struct arc_cb *cb, VGfloat x, VGfloat y);
453544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   void (*bezier)(struct arc_cb *cb, struct bezier *bezier);
454544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
455544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   void *user_data;
456544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin};
457544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
458544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic void cb_null_move(struct arc_cb *cb, VGfloat x, VGfloat y)
459544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
460544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
461544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
462544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic void polygon_point(struct arc_cb *cb, VGfloat x, VGfloat y)
463544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
464544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct polygon *poly = (struct polygon*)cb->user_data;
465544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   polygon_vertex_append(poly, x, y);
466544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
467544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
468544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic void polygon_bezier(struct arc_cb *cb, struct bezier *bezier)
469544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
470544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct polygon *poly = (struct polygon*)cb->user_data;
471544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   bezier_add_to_polygon(bezier, poly);
472544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
473544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
474544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic void stroke_point(struct arc_cb *cb, VGfloat x, VGfloat y)
475544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
476544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct stroker *stroker = (struct stroker*)cb->user_data;
477544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker_line_to(stroker, x, y);
478544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
479544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
480544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic void stroke_curve(struct arc_cb *cb, struct bezier *bezier)
481544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
482544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct stroker *stroker = (struct stroker*)cb->user_data;
483544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker_curve_to(stroker,
484544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                    bezier->x2, bezier->y2,
485544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                    bezier->x3, bezier->y3,
486544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                    bezier->x4, bezier->y4);
487544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
488544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
489544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic void stroke_emit_point(struct arc_cb *cb, VGfloat x, VGfloat y)
490544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
491544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct stroker *stroker = (struct stroker*)cb->user_data;
492544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker_emit_line_to(stroker, x, y);
493544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
494544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
495544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic void stroke_emit_curve(struct arc_cb *cb, struct bezier *bezier)
496544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
497544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct stroker *stroker = (struct stroker*)cb->user_data;
498544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker_emit_curve_to(stroker,
499544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                         bezier->x2, bezier->y2,
500544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                         bezier->x3, bezier->y3,
501544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                         bezier->x4, bezier->y4);
502544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
503544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
504544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic void arc_path_move(struct arc_cb *cb, VGfloat x, VGfloat y)
505544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
506544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct path *path = (struct path*)cb->user_data;
507544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   path_move_to(path, x, y);
508544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
509544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
510544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic void arc_path_point(struct arc_cb *cb, VGfloat x, VGfloat y)
511544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
512544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct path *path = (struct path*)cb->user_data;
513544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   path_line_to(path, x, y);
514544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
515544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
516544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic void arc_path_bezier(struct arc_cb *cb, struct bezier *bezier)
517544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
518544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct path *path = (struct path*)cb->user_data;
519544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   path_cubic_to(path,
520544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                 bezier->x2, bezier->y2,
521544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                 bezier->x3, bezier->y3,
522544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                 bezier->x4, bezier->y4);
523544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
524544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
525544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic INLINE int num_beziers_needed(struct arc *arc)
526544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
527544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   double threshold = 0.05;
528544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGboolean found = VG_FALSE;
529544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   int n = 1;
530544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   double min_eta, max_eta;
531544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
532544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   min_eta = MIN2(arc->eta1, arc->eta2);
533544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   max_eta = MAX2(arc->eta1, arc->eta2);
534544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
535544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   while ((! found) && (n < 1024)) {
536544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      double d_eta = (max_eta - min_eta) / n;
537544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      if (d_eta <= 0.5 * M_PI) {
538544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         double eta_b = min_eta;
53915ecd0337e4e4d9d33449bdff014a634e368c7d6Vinson Lee         int i;
540544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         found = VG_TRUE;
541910b58039a3980d9857380cf367bdbe2395d791fAlan Hourihane         for (i = 0; found && (i < n); ++i) {
542544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            double etaA = eta_b;
543544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            eta_b += d_eta;
544544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            found = (estimate_error(arc, etaA, eta_b) <= threshold);
545544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         }
546544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
547544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      n = n << 1;
548544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
549544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
550544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   return n;
551544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
552544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
553544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic void arc_to_beziers(struct arc *arc,
554544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                           struct arc_cb cb,
555544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                           struct matrix *matrix)
556544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
557910b58039a3980d9857380cf367bdbe2395d791fAlan Hourihane   int i;
558544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   int n = 1;
559544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   double d_eta, eta_b, cos_eta_b,
560544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      sin_eta_b, a_cos_eta_b, b_sin_eta_b, a_sin_eta_b,
561544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      b_cos_eta_b, x_b, y_b, x_b_dot, y_b_dot, lx, ly;
562544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   double t, alpha;
563544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
564544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   { /* always move to the start of the arc */
565544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGfloat x = arc->x1;
566544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGfloat y = arc->y1;
567544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      matrix_map_point(matrix, x, y, &x, &y);
568544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      cb.move(&cb, x, y);
569544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
570544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
571544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (!arc->is_valid) {
572544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGfloat x = arc->x2;
573544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGfloat y = arc->y2;
574544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      matrix_map_point(matrix, x, y, &x, &y);
575544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      cb.point(&cb, x, y);
576544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return;
577544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
578544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
579544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   /* find the number of Bézier curves needed */
580544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   n = num_beziers_needed(arc);
581544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
582544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   d_eta = (arc->eta2 - arc->eta1) / n;
583544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   eta_b = arc->eta1;
584544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
585544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   cos_eta_b  = cos(eta_b);
586544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   sin_eta_b  = sin(eta_b);
587544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   a_cos_eta_b = arc->a * cos_eta_b;
588544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   b_sin_eta_b = arc->b * sin_eta_b;
589544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   a_sin_eta_b = arc->a * sin_eta_b;
590544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   b_cos_eta_b = arc->b * cos_eta_b;
591544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   x_b       = arc->cx + a_cos_eta_b * arc->cos_theta -
592544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin               b_sin_eta_b * arc->sin_theta;
593544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   y_b       = arc->cy + a_cos_eta_b * arc->sin_theta +
594544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin               b_sin_eta_b * arc->cos_theta;
595544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   x_b_dot    = -a_sin_eta_b * arc->cos_theta -
596544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                b_cos_eta_b * arc->sin_theta;
597544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   y_b_dot    = -a_sin_eta_b * arc->sin_theta +
598544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                b_cos_eta_b * arc->cos_theta;
599544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
600544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   {
601544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGfloat x = x_b, y = y_b;
602544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      matrix_map_point(matrix, x, y, &x, &y);
603544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      cb.point(&cb, x, y);
604544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
605544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   lx = x_b;
606544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   ly = y_b;
607544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
608544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   t     = tan(0.5 * d_eta);
609544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   alpha = sin(d_eta) * (sqrt(4 + 3 * t * t) - 1) / 3;
610544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
611910b58039a3980d9857380cf367bdbe2395d791fAlan Hourihane   for (i = 0; i < n; ++i) {
612544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      struct bezier bezier;
613544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      double xA    = x_b;
614544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      double yA    = y_b;
615544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      double xADot = x_b_dot;
616544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      double yADot = y_b_dot;
617544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
618544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      eta_b    += d_eta;
619544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      cos_eta_b  = cos(eta_b);
620544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      sin_eta_b  = sin(eta_b);
621544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      a_cos_eta_b = arc->a * cos_eta_b;
622544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      b_sin_eta_b = arc->b * sin_eta_b;
623544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      a_sin_eta_b = arc->a * sin_eta_b;
624544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      b_cos_eta_b = arc->b * cos_eta_b;
625544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      x_b       = arc->cx + a_cos_eta_b * arc->cos_theta -
626544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                  b_sin_eta_b * arc->sin_theta;
627544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      y_b       = arc->cy + a_cos_eta_b * arc->sin_theta +
628544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                  b_sin_eta_b * arc->cos_theta;
629544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      x_b_dot    = -a_sin_eta_b * arc->cos_theta -
630544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                   b_cos_eta_b * arc->sin_theta;
631544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      y_b_dot    = -a_sin_eta_b * arc->sin_theta +
632544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                   b_cos_eta_b * arc->cos_theta;
633544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
634544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      bezier_init(&bezier,
635544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                  lx, ly,
636544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                  (float) (xA + alpha * xADot), (float) (yA + alpha * yADot),
637544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                  (float) (x_b - alpha * x_b_dot), (float) (y_b - alpha * y_b_dot),
638544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                  (float) x_b,                   (float) y_b);
639544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#if 0
640544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      debug_printf("%d) Bezier (%f, %f), (%f, %f), (%f, %f), (%f, %f)\n",
641544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                   i,
642544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                   bezier.x1, bezier.y1,
643544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                   bezier.x2, bezier.y2,
644544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                   bezier.x3, bezier.y3,
645544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                   bezier.x4, bezier.y4);
646544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#endif
647544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      bezier_transform(&bezier, matrix);
648544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      cb.bezier(&cb, &bezier);
649544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      lx = x_b;
650544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      ly = y_b;
651544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
652544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
653544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
654544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
655544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinvoid arc_add_to_polygon(struct arc *arc,
656544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                        struct polygon *poly,
657544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                        struct matrix *matrix)
658544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
659544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct arc_cb cb;
660544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
661544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   cb.move = cb_null_move;
662544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   cb.point = polygon_point;
663544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   cb.bezier = polygon_bezier;
664544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   cb.user_data = poly;
665544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
666544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   arc_to_beziers(arc, cb, matrix);
667544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
668544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
669544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinvoid arc_stroke_cb(struct arc *arc,
670544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                   struct stroker *stroke,
671544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                   struct matrix *matrix)
672544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
673544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct arc_cb cb;
674544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
675544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   cb.move = cb_null_move;
676544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   cb.point = stroke_point;
677544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   cb.bezier = stroke_curve;
678544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   cb.user_data = stroke;
679544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
680544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   arc_to_beziers(arc, cb, matrix);
681544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
682544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
683544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinvoid arc_stroker_emit(struct arc *arc,
684544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                      struct stroker *stroker,
685544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                      struct matrix *matrix)
686544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
687544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct arc_cb cb;
688544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
689544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   cb.move = cb_null_move;
690544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   cb.point = stroke_emit_point;
691544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   cb.bezier = stroke_emit_curve;
692544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   cb.user_data = stroker;
693544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
694544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   arc_to_beziers(arc, cb, matrix);
695544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
696544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
697544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinvoid arc_to_path(struct arc *arc,
698544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                 struct path *path,
699544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                 struct matrix *matrix)
700544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
701544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct arc_cb cb;
702544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
703544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   cb.move = arc_path_move;
704544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   cb.point = arc_path_point;
705544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   cb.bezier = arc_path_bezier;
706544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   cb.user_data = path;
707544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
708544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   arc_to_beziers(arc, cb, matrix);
709544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
710