1 /**************************************************************************
3 * Copyright 2009 VMware, Inc. All Rights Reserved.
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:
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
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.
25 **************************************************************************/
35 #include "util/u_debug.h"
36 #include "util/u_math.h"
39 #define M_PI 3.14159265358979323846
44 static const VGfloat two_pi
= M_PI
* 2;
47 static const double coeffs3Low
[2][4][4] = {
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 }
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 }
62 /* coefficients for error estimation
63 while using cubic Bézier curves for approximation
65 static const double coeffs3High
[2][4][4] = {
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 }
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 }
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
86 /* The code below is from the OpenVG 1.1 Spec
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)
94 find_unit_circles(double x0
, double y0
, double x1
, double y1
,
95 double *cx0
, double *cy0
,
96 double *cx1
, double *cy1
)
98 /* Compute differences and averages */
101 double xm
= (x0
+ x1
)/2;
102 double ym
= (y0
+ y1
)/2;
103 double dsq
, disc
, s
, sdx
, sdy
;
105 /* Solve for intersecting unit circles */
107 if (dsq
== 0.0) return VG_FALSE
; /* Points are coincident */
108 disc
= 1.0/dsq
- 1.0/4.0;
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
))
116 if (disc
< 0.0) return VG_FALSE
; /* Points are too far apart */
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)
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
)
138 double COS
, SIN
, x0p
, y0p
, x1p
, y1p
, pcx0
, pcy0
, pcx1
, pcy1
;
139 /* Convert rotation angle from degrees to radians */
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
)) {
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
;
164 static INLINE VGboolean
165 try_to_fix_radii(struct arc
*arc
)
167 double COS
, SIN
, rot
, x0p
, y0p
, x1p
, y1p
;
168 double dx
, dy
, dsq
, scale
;
170 /* Convert rotation angle from degrees to radians */
171 rot
= DEGREES_TO_RADIANS(arc
->theta
);
173 /* Pre-compute rotation matrix entries */
174 COS
= cos(rot
); SIN
= sin(rot
);
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 */
189 debug_printf("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaaaaa\n");
192 scale
= 1/(2/sqrt(dsq
));
198 static INLINE
double vector_normalize(double *v
)
200 double sq
= v
[0] * v
[0] + v
[1] * v
[1];
203 static INLINE
double vector_orientation(double *v
)
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
));
210 static INLINE
double vector_dot(double *v0
,
213 return v0
[0] * v1
[0] + v0
[1] * v1
[1];
216 static INLINE
double vector_angles(double *v0
,
219 double dot
= vector_dot(v0
, v1
);
220 double norm0
= vector_normalize(v0
);
221 double norm1
= vector_normalize(v1
);
223 return acos(dot
/ (norm0
* norm1
));
226 static VGboolean
find_angles(struct arc
*arc
)
228 double vec0
[2], vec1
[2];
229 double lambda1
, lambda2
;
231 struct matrix matrix
;
233 if (floatIsZero(arc
->a
) || floatIsZero(arc
->b
)) {
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
,
243 matrix_map_point(&matrix
,
246 matrix_map_point(&matrix
,
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
);
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
;
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
);
269 lambda1
= vector_orientation(vec0
);
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
);
287 if (arc
->type
== VG_SCWARC_TO
||
288 arc
->type
== VG_LCWARC_TO
)
289 lambda2
= lambda1
- angle
;
291 lambda2
= lambda1
+ angle
;
294 debug_printf("Angle is %f and (%f, %f)\n", angle
, lambda1
, lambda2
);
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
);
303 /* make sure we have eta1 <= eta2 <= eta1 + 2 PI */
304 arc
->eta2
-= two_pi
* floor((arc
->eta2
- arc
->eta1
) / two_pi
);
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
;
320 static void check_endpoints(struct arc
*arc
)
322 double x1
, y1
, x2
, y2
;
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
;
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
;
338 debug_printf("Computed (%f, %f), (%f, %f)\n",
340 debug_printf("Real (%f, %f), (%f, %f)\n",
346 void arc_init(struct arc
*arc
,
348 VGfloat x1
, VGfloat y1
,
349 VGfloat x2
, VGfloat y2
,
350 VGfloat rh
, VGfloat rv
,
353 assert(type
== VG_SCCWARC_TO
||
354 type
== VG_SCWARC_TO
||
355 type
== VG_LCCWARC_TO
||
356 type
== VG_LCWARC_TO
);
365 arc
->cos_theta
= cos(arc
->theta
);
366 arc
->sin_theta
= sin(arc
->theta
);
368 double cx0
, cy0
, cx1
, cy1
;
370 arc
->is_valid
= find_ellipses(rh
, rv
, rot
, x1
, y1
, x2
, y2
,
371 &cx0
, &cy0
, &cx1
, &cy1
);
373 if (!arc
->is_valid
&& try_to_fix_radii(arc
)) {
377 find_ellipses(rh
, rv
, rot
, x1
, y1
, x2
, y2
,
378 &cx0
, &cy0
, &cx1
, &cy1
);
381 if (type
== VG_SCWARC_TO
||
382 type
== VG_LCCWARC_TO
) {
390 debug_printf("Centers are : (%f, %f) , (%f, %f). Real (%f, %f)\n",
391 cx0
, cy0
, cx1
, cy1
, cx
, cy
);
396 arc
->is_valid
= find_angles(arc
);
398 check_endpoints(arc
);
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
);
414 static INLINE
double rational_function(double x
, const double *c
)
416 return (x
* (x
* c
[0] + c
[1]) + c
[2]) / (x
+ c
[3]);
419 static double estimate_error(struct arc
*arc
,
420 double etaA
, double etaB
)
422 double eta
= 0.5 * (etaA
+ etaB
);
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
);
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
;
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]);
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]);
447 return rational_function(x
, safety
) * arc
->a
* exp(c0
+ c1
* dEta
);
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
);
458 static void cb_null_move(struct arc_cb
*cb
, VGfloat x
, VGfloat y
)
462 static void polygon_point(struct arc_cb
*cb
, VGfloat x
, VGfloat y
)
464 struct polygon
*poly
= (struct polygon
*)cb
->user_data
;
465 polygon_vertex_append(poly
, x
, y
);
468 static void polygon_bezier(struct arc_cb
*cb
, struct bezier
*bezier
)
470 struct polygon
*poly
= (struct polygon
*)cb
->user_data
;
471 bezier_add_to_polygon(bezier
, poly
);
474 static void stroke_point(struct arc_cb
*cb
, VGfloat x
, VGfloat y
)
476 struct stroker
*stroker
= (struct stroker
*)cb
->user_data
;
477 stroker_line_to(stroker
, x
, y
);
480 static void stroke_curve(struct arc_cb
*cb
, struct bezier
*bezier
)
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
);
489 static void stroke_emit_point(struct arc_cb
*cb
, VGfloat x
, VGfloat y
)
491 struct stroker
*stroker
= (struct stroker
*)cb
->user_data
;
492 stroker_emit_line_to(stroker
, x
, y
);
495 static void stroke_emit_curve(struct arc_cb
*cb
, struct bezier
*bezier
)
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
);
504 static void arc_path_move(struct arc_cb
*cb
, VGfloat x
, VGfloat y
)
506 struct path
*path
= (struct path
*)cb
->user_data
;
507 path_move_to(path
, x
, y
);
510 static void arc_path_point(struct arc_cb
*cb
, VGfloat x
, VGfloat y
)
512 struct path
*path
= (struct path
*)cb
->user_data
;
513 path_line_to(path
, x
, y
);
516 static void arc_path_bezier(struct arc_cb
*cb
, struct bezier
*bezier
)
518 struct path
*path
= (struct path
*)cb
->user_data
;
520 bezier
->x2
, bezier
->y2
,
521 bezier
->x3
, bezier
->y3
,
522 bezier
->x4
, bezier
->y4
);
525 static INLINE
int num_beziers_needed(struct arc
*arc
)
527 double threshold
= 0.05;
528 VGboolean found
= VG_FALSE
;
530 double min_eta
, max_eta
;
532 min_eta
= MIN2(arc
->eta1
, arc
->eta2
);
533 max_eta
= MAX2(arc
->eta1
, arc
->eta2
);
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
;
541 for (i
= 0; found
&& (i
< n
); ++i
) {
544 found
= (estimate_error(arc
, etaA
, eta_b
) <= threshold
);
553 static void arc_to_beziers(struct arc
*arc
,
555 struct matrix
*matrix
)
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
;
564 { /* always move to the start of the arc */
567 matrix_map_point(matrix
, x
, y
, &x
, &y
);
571 if (!arc
->is_valid
) {
574 matrix_map_point(matrix
, x
, y
, &x
, &y
);
579 /* find the number of Bézier curves needed */
580 n
= num_beziers_needed(arc
);
582 d_eta
= (arc
->eta2
- arc
->eta1
) / n
;
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
;
601 VGfloat x
= x_b
, y
= y_b
;
602 matrix_map_point(matrix
, x
, y
, &x
, &y
);
608 t
= tan(0.5 * d_eta
);
609 alpha
= sin(d_eta
) * (sqrt(4 + 3 * t
* t
) - 1) / 3;
611 for (i
= 0; i
< n
; ++i
) {
612 struct bezier bezier
;
615 double xADot
= x_b_dot
;
616 double yADot
= y_b_dot
;
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
;
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
);
640 debug_printf("%d) Bezier (%f, %f), (%f, %f), (%f, %f), (%f, %f)\n",
642 bezier
.x1
, bezier
.y1
,
643 bezier
.x2
, bezier
.y2
,
644 bezier
.x3
, bezier
.y3
,
645 bezier
.x4
, bezier
.y4
);
647 bezier_transform(&bezier
, matrix
);
648 cb
.bezier(&cb
, &bezier
);
655 void arc_add_to_polygon(struct arc
*arc
,
656 struct polygon
*poly
,
657 struct matrix
*matrix
)
661 cb
.move
= cb_null_move
;
662 cb
.point
= polygon_point
;
663 cb
.bezier
= polygon_bezier
;
666 arc_to_beziers(arc
, cb
, matrix
);
669 void arc_stroke_cb(struct arc
*arc
,
670 struct stroker
*stroke
,
671 struct matrix
*matrix
)
675 cb
.move
= cb_null_move
;
676 cb
.point
= stroke_point
;
677 cb
.bezier
= stroke_curve
;
678 cb
.user_data
= stroke
;
680 arc_to_beziers(arc
, cb
, matrix
);
683 void arc_stroker_emit(struct arc
*arc
,
684 struct stroker
*stroker
,
685 struct matrix
*matrix
)
689 cb
.move
= cb_null_move
;
690 cb
.point
= stroke_emit_point
;
691 cb
.bezier
= stroke_emit_curve
;
692 cb
.user_data
= stroker
;
694 arc_to_beziers(arc
, cb
, matrix
);
697 void arc_to_path(struct arc
*arc
,
699 struct matrix
*matrix
)
703 cb
.move
= arc_path_move
;
704 cb
.point
= arc_path_point
;
705 cb
.bezier
= arc_path_bezier
;
708 arc_to_beziers(arc
, cb
, matrix
);