1 /************************************************************************** 2 * 3 * Copyright 2009 VMware, Inc. All Rights Reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the 7 * "Software"), to deal in the Software without restriction, including 8 * without limitation the rights to use, copy, modify, merge, publish, 9 * distribute, sub license, and/or sell copies of the Software, and to 10 * permit persons to whom the Software is furnished to do so, subject to 11 * the following conditions: 12 * 13 * The above copyright notice and this permission notice (including the 14 * next paragraph) shall be included in all copies or substantial portions 15 * of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 20 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 21 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 * 25 **************************************************************************/ 26 27 #include "arc.h" 28 29 #include "matrix.h" 30 #include "bezier.h" 31 #include "polygon.h" 32 #include "stroker.h" 33 #include "path.h" 34 35 #include "util/u_debug.h" 36 #include "util/u_math.h" 37 38 #ifndef M_PI 39 #define M_PI 3.14159265358979323846 40 #endif 41 42 #define DEBUG_ARCS 0 43 44 static const VGfloat two_pi = M_PI * 2; 45 46 47 static const double coeffs3Low[2][4][4] = { 48 { 49 { 3.85268, -21.229, -0.330434, 0.0127842 }, 50 { -1.61486, 0.706564, 0.225945, 0.263682 }, 51 { -0.910164, 0.388383, 0.00551445, 0.00671814 }, 52 { -0.630184, 0.192402, 0.0098871, 0.0102527 } 53 }, 54 { 55 { -0.162211, 9.94329, 0.13723, 0.0124084 }, 56 { -0.253135, 0.00187735, 0.0230286, 0.01264 }, 57 { -0.0695069, -0.0437594, 0.0120636, 0.0163087 }, 58 { -0.0328856, -0.00926032, -0.00173573, 0.00527385 } 59 } 60 }; 61 62 /* coefficients for error estimation 63 while using cubic Bzier curves for approximation 64 1/4 <= b/a <= 1 */ 65 static const double coeffs3High[2][4][4] = { 66 { 67 { 0.0899116, -19.2349, -4.11711, 0.183362 }, 68 { 0.138148, -1.45804, 1.32044, 1.38474 }, 69 { 0.230903, -0.450262, 0.219963, 0.414038 }, 70 { 0.0590565, -0.101062, 0.0430592, 0.0204699 } 71 }, 72 { 73 { 0.0164649, 9.89394, 0.0919496, 0.00760802 }, 74 { 0.0191603, -0.0322058, 0.0134667, -0.0825018 }, 75 { 0.0156192, -0.017535, 0.00326508, -0.228157 }, 76 { -0.0236752, 0.0405821, -0.0173086, 0.176187 } 77 } 78 }; 79 80 /* safety factor to convert the "best" error approximation 81 into a "max bound" error */ 82 static const double safety3[] = { 83 0.001, 4.98, 0.207, 0.0067 84 }; 85 86 /* The code below is from the OpenVG 1.1 Spec 87 * Section 18.4 */ 88 89 /* Given: Points (x0, y0) and (x1, y1) 90 * Return: TRUE if a solution exists, FALSE otherwise 91 * Circle centers are written to (cx0, cy0) and (cx1, cy1) 92 */ 93 static VGboolean 94 find_unit_circles(double x0, double y0, double x1, double y1, 95 double *cx0, double *cy0, 96 double *cx1, double *cy1) 97 { 98 /* Compute differences and averages */ 99 double dx = x0 - x1; 100 double dy = y0 - y1; 101 double xm = (x0 + x1)/2; 102 double ym = (y0 + y1)/2; 103 double dsq, disc, s, sdx, sdy; 104 105 /* Solve for intersecting unit circles */ 106 dsq = dx*dx + dy*dy; 107 if (dsq == 0.0) return VG_FALSE; /* Points are coincident */ 108 disc = 1.0/dsq - 1.0/4.0; 109 110 /* the precision we care about here is around float so if we're 111 * around the float defined zero then make it official to avoid 112 * precision problems later on */ 113 if (floatIsZero(disc)) 114 disc = 0.0; 115 116 if (disc < 0.0) return VG_FALSE; /* Points are too far apart */ 117 s = sqrt(disc); 118 sdx = s*dx; 119 sdy = s*dy; 120 *cx0 = xm + sdy; 121 *cy0 = ym - sdx; 122 *cx1 = xm - sdy; 123 *cy1 = ym + sdx; 124 return VG_TRUE; 125 } 126 127 128 /* Given: Ellipse parameters rh, rv, rot (in degrees), 129 * endpoints (x0, y0) and (x1, y1) 130 * Return: TRUE if a solution exists, FALSE otherwise 131 * Ellipse centers are written to (cx0, cy0) and (cx1, cy1) 132 */ 133 static VGboolean 134 find_ellipses(double rh, double rv, double rot, 135 double x0, double y0, double x1, double y1, 136 double *cx0, double *cy0, double *cx1, double *cy1) 137 { 138 double COS, SIN, x0p, y0p, x1p, y1p, pcx0, pcy0, pcx1, pcy1; 139 /* Convert rotation angle from degrees to radians */ 140 rot *= M_PI/180.0; 141 /* Pre-compute rotation matrix entries */ 142 COS = cos(rot); SIN = sin(rot); 143 /* Transform (x0, y0) and (x1, y1) into unit space */ 144 /* using (inverse) rotate, followed by (inverse) scale */ 145 x0p = (x0*COS + y0*SIN)/rh; 146 y0p = (-x0*SIN + y0*COS)/rv; 147 x1p = (x1*COS + y1*SIN)/rh; 148 y1p = (-x1*SIN + y1*COS)/rv; 149 if (!find_unit_circles(x0p, y0p, x1p, y1p, 150 &pcx0, &pcy0, &pcx1, &pcy1)) { 151 return VG_FALSE; 152 } 153 /* Transform back to original coordinate space */ 154 /* using (forward) scale followed by (forward) rotate */ 155 pcx0 *= rh; pcy0 *= rv; 156 pcx1 *= rh; pcy1 *= rv; 157 *cx0 = pcx0*COS - pcy0*SIN; 158 *cy0 = pcx0*SIN + pcy0*COS; 159 *cx1 = pcx1*COS - pcy1*SIN; 160 *cy1 = pcx1*SIN + pcy1*COS; 161 return VG_TRUE; 162 } 163 164 static INLINE VGboolean 165 try_to_fix_radii(struct arc *arc) 166 { 167 double COS, SIN, rot, x0p, y0p, x1p, y1p; 168 double dx, dy, dsq, scale; 169 170 /* Convert rotation angle from degrees to radians */ 171 rot = DEGREES_TO_RADIANS(arc->theta); 172 173 /* Pre-compute rotation matrix entries */ 174 COS = cos(rot); SIN = sin(rot); 175 176 /* Transform (x0, y0) and (x1, y1) into unit space */ 177 /* using (inverse) rotate, followed by (inverse) scale */ 178 x0p = (arc->x1*COS + arc->y1*SIN)/arc->a; 179 y0p = (-arc->x1*SIN + arc->y1*COS)/arc->b; 180 x1p = (arc->x2*COS + arc->y2*SIN)/arc->a; 181 y1p = (-arc->x2*SIN + arc->y2*COS)/arc->b; 182 /* Compute differences and averages */ 183 dx = x0p - x1p; 184 dy = y0p - y1p; 185 186 dsq = dx*dx + dy*dy; 187 #if 0 188 if (dsq <= 0.001) { 189 debug_printf("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaaaaa\n"); 190 } 191 #endif 192 scale = 1/(2/sqrt(dsq)); 193 arc->a *= scale; 194 arc->b *= scale; 195 return VG_TRUE; 196 } 197 198 static INLINE double vector_normalize(double *v) 199 { 200 double sq = v[0] * v[0] + v[1] * v[1]; 201 return sqrt(sq); 202 } 203 static INLINE double vector_orientation(double *v) 204 { 205 double norm = vector_normalize(v); 206 double cosa = v[0] / norm; 207 double sina = v[1] / norm; 208 return (sina>=0 ? acos(cosa) : 2*M_PI - acos(cosa)); 209 } 210 static INLINE double vector_dot(double *v0, 211 double *v1) 212 { 213 return v0[0] * v1[0] + v0[1] * v1[1]; 214 } 215 216 static INLINE double vector_angles(double *v0, 217 double *v1) 218 { 219 double dot = vector_dot(v0, v1); 220 double norm0 = vector_normalize(v0); 221 double norm1 = vector_normalize(v1); 222 223 return acos(dot / (norm0 * norm1)); 224 } 225 226 static VGboolean find_angles(struct arc *arc) 227 { 228 double vec0[2], vec1[2]; 229 double lambda1, lambda2; 230 double angle; 231 struct matrix matrix; 232 233 if (floatIsZero(arc->a) || floatIsZero(arc->b)) { 234 return VG_FALSE; 235 } 236 /* map the points to an identity circle */ 237 matrix_load_identity(&matrix); 238 matrix_scale(&matrix, 1.f, arc->a/arc->b); 239 matrix_rotate(&matrix, -arc->theta); 240 matrix_map_point(&matrix, 241 arc->x1, arc->y1, 242 &arc->x1, &arc->y1); 243 matrix_map_point(&matrix, 244 arc->x2, arc->y2, 245 &arc->x2, &arc->y2); 246 matrix_map_point(&matrix, 247 arc->cx, arc->cy, 248 &arc->cx, &arc->cy); 249 250 #if DEBUG_ARCS 251 debug_printf("Matrix 3 [%f, %f, %f| %f, %f, %f| %f, %f, %f]\n", 252 matrix.m[0], matrix.m[1], matrix.m[2], 253 matrix.m[3], matrix.m[4], matrix.m[5], 254 matrix.m[6], matrix.m[7], matrix.m[8]); 255 debug_printf("Endpoints [%f, %f], [%f, %f]\n", 256 arc->x1, arc->y1, arc->x2, arc->y2); 257 #endif 258 259 vec0[0] = arc->x1 - arc->cx; 260 vec0[1] = arc->y1 - arc->cy; 261 vec1[0] = arc->x2 - arc->cx; 262 vec1[1] = arc->y2 - arc->cy; 263 264 #if DEBUG_ARCS 265 debug_printf("Vec is [%f, %f], [%f, %f], [%f, %f]\n", 266 vec0[0], vec0[1], vec1[0], vec1[1], arc->cx, arc->cy); 267 #endif 268 269 lambda1 = vector_orientation(vec0); 270 271 if (isnan(lambda1)) 272 lambda1 = 0.f; 273 274 if (arc->type == VG_SCWARC_TO || 275 arc->type == VG_SCCWARC_TO) 276 angle = vector_angles(vec0, vec1); 277 else if (arc->type == VG_LCWARC_TO || 278 arc->type == VG_LCCWARC_TO) { 279 angle = 2*M_PI - vector_angles(vec0, vec1); 280 } else 281 abort(); 282 283 if (isnan(angle)) 284 angle = M_PI; 285 286 287 if (arc->type == VG_SCWARC_TO || 288 arc->type == VG_LCWARC_TO) 289 lambda2 = lambda1 - angle; 290 else 291 lambda2 = lambda1 + angle; 292 293 #if DEBUG_ARCS 294 debug_printf("Angle is %f and (%f, %f)\n", angle, lambda1, lambda2); 295 #endif 296 297 #if 0 298 arc->eta1 = atan2(sin(lambda1) / arc->b, 299 cos(lambda1) / arc->a); 300 arc->eta2 = atan2(sin(lambda2) / arc->b, 301 cos(lambda2) / arc->a); 302 303 /* make sure we have eta1 <= eta2 <= eta1 + 2 PI */ 304 arc->eta2 -= two_pi * floor((arc->eta2 - arc->eta1) / two_pi); 305 306 /* the preceding correction fails if we have exactly et2 - eta1 = 2 PI 307 it reduces the interval to zero length */ 308 if ((lambda2 - lambda1 > M_PI) && (arc->eta2 - arc->eta1 < M_PI)) { 309 arc->eta2 += 2 * M_PI; 310 } 311 #else 312 arc->eta1 = lambda1; 313 arc->eta2 = lambda2; 314 #endif 315 316 return VG_TRUE; 317 } 318 319 #if DEBUG_ARCS 320 static void check_endpoints(struct arc *arc) 321 { 322 double x1, y1, x2, y2; 323 324 double a_cos_eta1 = arc->a * cos(arc->eta1); 325 double b_sin_eta1 = arc->b * sin(arc->eta1); 326 x1 = arc->cx + a_cos_eta1 * arc->cos_theta - 327 b_sin_eta1 * arc->sin_theta; 328 y1 = arc->cy + a_cos_eta1 * arc->sin_theta + 329 b_sin_eta1 * arc->cos_theta; 330 331 double a_cos_eta2 = arc->a * cos(arc->eta2); 332 double b_sin_eta2 = arc->b * sin(arc->eta2); 333 x2 = arc->cx + a_cos_eta2 * arc->cos_theta - 334 b_sin_eta2 * arc->sin_theta; 335 y2 = arc->cy + a_cos_eta2 * arc->sin_theta + 336 b_sin_eta2 * arc->cos_theta; 337 338 debug_printf("Computed (%f, %f), (%f, %f)\n", 339 x1, y1, x2, y2); 340 debug_printf("Real (%f, %f), (%f, %f)\n", 341 arc->x1, arc->y1, 342 arc->x2, arc->y2); 343 } 344 #endif 345 346 void arc_init(struct arc *arc, 347 VGPathSegment type, 348 VGfloat x1, VGfloat y1, 349 VGfloat x2, VGfloat y2, 350 VGfloat rh, VGfloat rv, 351 VGfloat rot) 352 { 353 assert(type == VG_SCCWARC_TO || 354 type == VG_SCWARC_TO || 355 type == VG_LCCWARC_TO || 356 type == VG_LCWARC_TO); 357 arc->type = type; 358 arc->x1 = x1; 359 arc->y1 = y1; 360 arc->x2 = x2; 361 arc->y2 = y2; 362 arc->a = rh; 363 arc->b = rv; 364 arc->theta = rot; 365 arc->cos_theta = cos(arc->theta); 366 arc->sin_theta = sin(arc->theta); 367 { 368 double cx0, cy0, cx1, cy1; 369 double cx, cy; 370 arc->is_valid = find_ellipses(rh, rv, rot, x1, y1, x2, y2, 371 &cx0, &cy0, &cx1, &cy1); 372 373 if (!arc->is_valid && try_to_fix_radii(arc)) { 374 rh = arc->a; 375 rv = arc->b; 376 arc->is_valid = 377 find_ellipses(rh, rv, rot, x1, y1, x2, y2, 378 &cx0, &cy0, &cx1, &cy1); 379 } 380 381 if (type == VG_SCWARC_TO || 382 type == VG_LCCWARC_TO) { 383 cx = cx1; 384 cy = cy1; 385 } else { 386 cx = cx0; 387 cy = cy0; 388 } 389 #if DEBUG_ARCS 390 debug_printf("Centers are : (%f, %f) , (%f, %f). Real (%f, %f)\n", 391 cx0, cy0, cx1, cy1, cx, cy); 392 #endif 393 arc->cx = cx; 394 arc->cy = cy; 395 if (arc->is_valid) { 396 arc->is_valid = find_angles(arc); 397 #if DEBUG_ARCS 398 check_endpoints(arc); 399 #endif 400 /* remap a few points. find_angles requires 401 * rot in angles, the rest of the code 402 * will need them in radians. and find_angles 403 * modifies the center to match an identity 404 * circle so lets reset it */ 405 arc->theta = DEGREES_TO_RADIANS(rot); 406 arc->cos_theta = cos(arc->theta); 407 arc->sin_theta = sin(arc->theta); 408 arc->cx = cx; 409 arc->cy = cy; 410 } 411 } 412 } 413 414 static INLINE double rational_function(double x, const double *c) 415 { 416 return (x * (x * c[0] + c[1]) + c[2]) / (x + c[3]); 417 } 418 419 static double estimate_error(struct arc *arc, 420 double etaA, double etaB) 421 { 422 double eta = 0.5 * (etaA + etaB); 423 424 double x = arc->b / arc->a; 425 double dEta = etaB - etaA; 426 double cos2 = cos(2 * eta); 427 double cos4 = cos(4 * eta); 428 double cos6 = cos(6 * eta); 429 double c0, c1; 430 431 /* select the right coeficients set according to degree and b/a */ 432 const double (*coeffs)[4][4]; 433 const double *safety; 434 coeffs = (x < 0.25) ? coeffs3Low : coeffs3High; 435 safety = safety3; 436 437 c0 = rational_function(x, coeffs[0][0]) 438 + cos2 * rational_function(x, coeffs[0][1]) 439 + cos4 * rational_function(x, coeffs[0][2]) 440 + cos6 * rational_function(x, coeffs[0][3]); 441 442 c1 = rational_function(x, coeffs[1][0]) 443 + cos2 * rational_function(x, coeffs[1][1]) 444 + cos4 * rational_function(x, coeffs[1][2]) 445 + cos6 * rational_function(x, coeffs[1][3]); 446 447 return rational_function(x, safety) * arc->a * exp(c0 + c1 * dEta); 448 } 449 450 struct arc_cb { 451 void (*move)(struct arc_cb *cb, VGfloat x, VGfloat y); 452 void (*point)(struct arc_cb *cb, VGfloat x, VGfloat y); 453 void (*bezier)(struct arc_cb *cb, struct bezier *bezier); 454 455 void *user_data; 456 }; 457 458 static void cb_null_move(struct arc_cb *cb, VGfloat x, VGfloat y) 459 { 460 } 461 462 static void polygon_point(struct arc_cb *cb, VGfloat x, VGfloat y) 463 { 464 struct polygon *poly = (struct polygon*)cb->user_data; 465 polygon_vertex_append(poly, x, y); 466 } 467 468 static void polygon_bezier(struct arc_cb *cb, struct bezier *bezier) 469 { 470 struct polygon *poly = (struct polygon*)cb->user_data; 471 bezier_add_to_polygon(bezier, poly); 472 } 473 474 static void stroke_point(struct arc_cb *cb, VGfloat x, VGfloat y) 475 { 476 struct stroker *stroker = (struct stroker*)cb->user_data; 477 stroker_line_to(stroker, x, y); 478 } 479 480 static void stroke_curve(struct arc_cb *cb, struct bezier *bezier) 481 { 482 struct stroker *stroker = (struct stroker*)cb->user_data; 483 stroker_curve_to(stroker, 484 bezier->x2, bezier->y2, 485 bezier->x3, bezier->y3, 486 bezier->x4, bezier->y4); 487 } 488 489 static void stroke_emit_point(struct arc_cb *cb, VGfloat x, VGfloat y) 490 { 491 struct stroker *stroker = (struct stroker*)cb->user_data; 492 stroker_emit_line_to(stroker, x, y); 493 } 494 495 static void stroke_emit_curve(struct arc_cb *cb, struct bezier *bezier) 496 { 497 struct stroker *stroker = (struct stroker*)cb->user_data; 498 stroker_emit_curve_to(stroker, 499 bezier->x2, bezier->y2, 500 bezier->x3, bezier->y3, 501 bezier->x4, bezier->y4); 502 } 503 504 static void arc_path_move(struct arc_cb *cb, VGfloat x, VGfloat y) 505 { 506 struct path *path = (struct path*)cb->user_data; 507 path_move_to(path, x, y); 508 } 509 510 static void arc_path_point(struct arc_cb *cb, VGfloat x, VGfloat y) 511 { 512 struct path *path = (struct path*)cb->user_data; 513 path_line_to(path, x, y); 514 } 515 516 static void arc_path_bezier(struct arc_cb *cb, struct bezier *bezier) 517 { 518 struct path *path = (struct path*)cb->user_data; 519 path_cubic_to(path, 520 bezier->x2, bezier->y2, 521 bezier->x3, bezier->y3, 522 bezier->x4, bezier->y4); 523 } 524 525 static INLINE int num_beziers_needed(struct arc *arc) 526 { 527 double threshold = 0.05; 528 VGboolean found = VG_FALSE; 529 int n = 1; 530 double min_eta, max_eta; 531 532 min_eta = MIN2(arc->eta1, arc->eta2); 533 max_eta = MAX2(arc->eta1, arc->eta2); 534 535 while ((! found) && (n < 1024)) { 536 double d_eta = (max_eta - min_eta) / n; 537 if (d_eta <= 0.5 * M_PI) { 538 double eta_b = min_eta; 539 int i; 540 found = VG_TRUE; 541 for (i = 0; found && (i < n); ++i) { 542 double etaA = eta_b; 543 eta_b += d_eta; 544 found = (estimate_error(arc, etaA, eta_b) <= threshold); 545 } 546 } 547 n = n << 1; 548 } 549 550 return n; 551 } 552 553 static void arc_to_beziers(struct arc *arc, 554 struct arc_cb cb, 555 struct matrix *matrix) 556 { 557 int i; 558 int n = 1; 559 double d_eta, eta_b, cos_eta_b, 560 sin_eta_b, a_cos_eta_b, b_sin_eta_b, a_sin_eta_b, 561 b_cos_eta_b, x_b, y_b, x_b_dot, y_b_dot, lx, ly; 562 double t, alpha; 563 564 { /* always move to the start of the arc */ 565 VGfloat x = arc->x1; 566 VGfloat y = arc->y1; 567 matrix_map_point(matrix, x, y, &x, &y); 568 cb.move(&cb, x, y); 569 } 570 571 if (!arc->is_valid) { 572 VGfloat x = arc->x2; 573 VGfloat y = arc->y2; 574 matrix_map_point(matrix, x, y, &x, &y); 575 cb.point(&cb, x, y); 576 return; 577 } 578 579 /* find the number of Bzier curves needed */ 580 n = num_beziers_needed(arc); 581 582 d_eta = (arc->eta2 - arc->eta1) / n; 583 eta_b = arc->eta1; 584 585 cos_eta_b = cos(eta_b); 586 sin_eta_b = sin(eta_b); 587 a_cos_eta_b = arc->a * cos_eta_b; 588 b_sin_eta_b = arc->b * sin_eta_b; 589 a_sin_eta_b = arc->a * sin_eta_b; 590 b_cos_eta_b = arc->b * cos_eta_b; 591 x_b = arc->cx + a_cos_eta_b * arc->cos_theta - 592 b_sin_eta_b * arc->sin_theta; 593 y_b = arc->cy + a_cos_eta_b * arc->sin_theta + 594 b_sin_eta_b * arc->cos_theta; 595 x_b_dot = -a_sin_eta_b * arc->cos_theta - 596 b_cos_eta_b * arc->sin_theta; 597 y_b_dot = -a_sin_eta_b * arc->sin_theta + 598 b_cos_eta_b * arc->cos_theta; 599 600 { 601 VGfloat x = x_b, y = y_b; 602 matrix_map_point(matrix, x, y, &x, &y); 603 cb.point(&cb, x, y); 604 } 605 lx = x_b; 606 ly = y_b; 607 608 t = tan(0.5 * d_eta); 609 alpha = sin(d_eta) * (sqrt(4 + 3 * t * t) - 1) / 3; 610 611 for (i = 0; i < n; ++i) { 612 struct bezier bezier; 613 double xA = x_b; 614 double yA = y_b; 615 double xADot = x_b_dot; 616 double yADot = y_b_dot; 617 618 eta_b += d_eta; 619 cos_eta_b = cos(eta_b); 620 sin_eta_b = sin(eta_b); 621 a_cos_eta_b = arc->a * cos_eta_b; 622 b_sin_eta_b = arc->b * sin_eta_b; 623 a_sin_eta_b = arc->a * sin_eta_b; 624 b_cos_eta_b = arc->b * cos_eta_b; 625 x_b = arc->cx + a_cos_eta_b * arc->cos_theta - 626 b_sin_eta_b * arc->sin_theta; 627 y_b = arc->cy + a_cos_eta_b * arc->sin_theta + 628 b_sin_eta_b * arc->cos_theta; 629 x_b_dot = -a_sin_eta_b * arc->cos_theta - 630 b_cos_eta_b * arc->sin_theta; 631 y_b_dot = -a_sin_eta_b * arc->sin_theta + 632 b_cos_eta_b * arc->cos_theta; 633 634 bezier_init(&bezier, 635 lx, ly, 636 (float) (xA + alpha * xADot), (float) (yA + alpha * yADot), 637 (float) (x_b - alpha * x_b_dot), (float) (y_b - alpha * y_b_dot), 638 (float) x_b, (float) y_b); 639 #if 0 640 debug_printf("%d) Bezier (%f, %f), (%f, %f), (%f, %f), (%f, %f)\n", 641 i, 642 bezier.x1, bezier.y1, 643 bezier.x2, bezier.y2, 644 bezier.x3, bezier.y3, 645 bezier.x4, bezier.y4); 646 #endif 647 bezier_transform(&bezier, matrix); 648 cb.bezier(&cb, &bezier); 649 lx = x_b; 650 ly = y_b; 651 } 652 } 653 654 655 void arc_add_to_polygon(struct arc *arc, 656 struct polygon *poly, 657 struct matrix *matrix) 658 { 659 struct arc_cb cb; 660 661 cb.move = cb_null_move; 662 cb.point = polygon_point; 663 cb.bezier = polygon_bezier; 664 cb.user_data = poly; 665 666 arc_to_beziers(arc, cb, matrix); 667 } 668 669 void arc_stroke_cb(struct arc *arc, 670 struct stroker *stroke, 671 struct matrix *matrix) 672 { 673 struct arc_cb cb; 674 675 cb.move = cb_null_move; 676 cb.point = stroke_point; 677 cb.bezier = stroke_curve; 678 cb.user_data = stroke; 679 680 arc_to_beziers(arc, cb, matrix); 681 } 682 683 void arc_stroker_emit(struct arc *arc, 684 struct stroker *stroker, 685 struct matrix *matrix) 686 { 687 struct arc_cb cb; 688 689 cb.move = cb_null_move; 690 cb.point = stroke_emit_point; 691 cb.bezier = stroke_emit_curve; 692 cb.user_data = stroker; 693 694 arc_to_beziers(arc, cb, matrix); 695 } 696 697 void arc_to_path(struct arc *arc, 698 struct path *path, 699 struct matrix *matrix) 700 { 701 struct arc_cb cb; 702 703 cb.move = arc_path_move; 704 cb.point = arc_path_point; 705 cb.bezier = arc_path_bezier; 706 cb.user_data = path; 707 708 arc_to_beziers(arc, cb, matrix); 709 } 710