Re: Shouldn't Cairo use/offer degrees rather than radians?
David Kastrup <[email protected]>
| Newsgroups | gmane.comp.lib.cairo |
|---|---|
| Message-ID | <[email protected]> |
Bill Spitzak <[email protected]> writes: > On Fri, Jun 30, 2017 at 1:44 PM, David Kastrup <[email protected]> wrote: > >> I am not calling any atan2d. > > Your code copied and pasted from the previous email. If this is not > your code please explain where the code you want to use is: Appended again. Sorry for the atan2d thing: I should have checked for completeness, and quoting vector->angle code with respect to Cairo was rather pointless in the first place. The missing code unsurprisingly was static inline Real atan2d (Real y, Real x) { return atan2 (y, x) * (180.0 / M_PI); } but with regard to Cairo, the direction vector->angle is hardly relevant, with angle->vector being the seminal API in question. I'll append the proposed patch again (at the bottom) David Kastrup -- cairo mailing list [email protected] https://lists.cairographics.org/mailman/listinfo/cairo
0001-Implement-cairo_matrix_init_rotate_deg-and-cairo_mat.patch
(text/x-diff, 5.8 KB)
From a057b17b5018000435cc011d7a2d20072457badb Mon Sep 17 00:00:00 2001 From: David Kastrup <[email protected]> Date: Fri, 30 Jun 2017 07:01:26 +0200 Subject: [PATCH] Implement cairo_matrix_init_rotate_deg and cairo_matrix_rotate_deg Those offer variants of cairo_matrix_init_rotate and cairo_matrix_rotate that are numerically perfect at right angles without introducing discontinuities. --- doc/public/cairo-sections.txt | 2 + src/cairo-matrix.c | 92 +++++++++++++++++++++++++++++++++++++++++++ src/cairo.h | 7 ++++ src/cairoint.h | 1 + 4 files changed, 102 insertions(+) diff --git a/doc/public/cairo-sections.txt b/doc/public/cairo-sections.txt index 7b04ae7b3..ac5e566a0 100644 --- a/doc/public/cairo-sections.txt +++ b/doc/public/cairo-sections.txt @@ -430,9 +430,11 @@ cairo_matrix_init_identity cairo_matrix_init_translate cairo_matrix_init_scale cairo_matrix_init_rotate +cairo_matrix_init_rotate_deg cairo_matrix_translate cairo_matrix_scale cairo_matrix_rotate +cairo_matrix_rotate_deg cairo_matrix_invert cairo_matrix_multiply cairo_matrix_transform_distance diff --git a/src/cairo-matrix.c b/src/cairo-matrix.c index ae498f515..8728bcdee 100644 --- a/src/cairo-matrix.c +++ b/src/cairo-matrix.c @@ -312,6 +312,98 @@ cairo_matrix_rotate (cairo_matrix_t *matrix, double radians) } /** + * cairo_matrix_init_rotate_deg: + * @matrix: a #cairo_matrix_t + * @degrees: angle of rotation, in degrees. The direction of rotation + * is defined such that positive angles rotate in the direction from + * the positive X axis toward the positive Y axis. With the default + * axis orientation of cairo, positive angles rotate in a clockwise + * direction. + * For angles that are multiples of 90 degrees, the transformation + * matrix is numerically exact. + * + * Initializes @matrix to a + * transformation that rotates by @degrees. + * + * Since: 1.16 + **/ +void +cairo_matrix_init_rotate_deg (cairo_matrix_t *matrix, + double degrees) +{ + double s; + double c; + + if (unlikely (degrees <= -540.0 || degrees >= 540.0)) + degrees = fmod (degrees, 360.0); + /* Now |degrees| < 540.0, and the absolute size is not larger than + before, so we haven't lost precision. */ + if (unlikely (degrees <= -180.0)) + degrees += 360.0; + else if (unlikely (degrees > 180.0)) + degrees -= 360.0; + /* Now -180.0 < degrees <= 180.0 and we still haven't lost + precision. We don't work with angles greater than 90 degrees + absolute in order to minimize how rounding errors of M_PI/180 + affect the result. The "handover" between one sine expression + to the next happens at angles of +-90 degrees where + sin(pi/2+eps) is about (1-eps^2/2). Since the difference to + pi/2 should be quite small, the sine will be numerically 1 here. + + Sign of the sine is chosen to avoid -0.0 in results. This + version delivers exactly equal magnitude on x/y for odd + multiples of 45 degrees. */ + + if (degrees >= 0) { + c = sin ((90 - degrees) * (M_PI/180.0)); + if (degrees > 90) + s = sin ((180 - degrees) * (M_PI/180.0)); + else + s = sin (degrees * (M_PI/180.0)); + } else { + c = sin ((90 + degrees) * (M_PI/180.0)); + if (degrees < -90) + s = sin ((-180 - degrees) * (M_PI/180.0)); + else + s = sin (degrees * (M_PI/180.0)); + } + + cairo_matrix_init (matrix, + c, s, + -s, c, + 0, 0); +} +slim_hidden_def(cairo_matrix_init_rotate_deg); + +/** + * cairo_matrix_rotate_deg: + * @matrix: a #cairo_matrix_t + * @degrees: angle of rotation, in degrees. The direction of rotation + * is defined such that positive angles rotate in the direction from + * the positive X axis toward the positive Y axis. With the default + * axis orientation of cairo, positive angles rotate in a clockwise + * direction. + * For angles that are multiples of 90 degrees, the change to the + * transformation matrix is numerically exact. + * + * Applies rotation by @degrees to the transformation in + * @matrix. The effect of the new transformation is to first rotate the + * coordinates by @degrees, then apply the original transformation + * to the coordinates. + * + * Since: 1.16 + **/ +void +cairo_matrix_rotate_deg (cairo_matrix_t *matrix, double degrees) +{ + cairo_matrix_t tmp; + + cairo_matrix_init_rotate_deg (&tmp, degrees); + + cairo_matrix_multiply (matrix, &tmp, matrix); +} + +/** * cairo_matrix_multiply: * @result: a #cairo_matrix_t in which to store the result * @a: a #cairo_matrix_t diff --git a/src/cairo.h b/src/cairo.h index 32fc88b17..310f4c6d5 100644 --- a/src/cairo.h +++ b/src/cairo.h @@ -3026,6 +3026,10 @@ cairo_matrix_init_rotate (cairo_matrix_t *matrix, double radians); cairo_public void +cairo_matrix_init_rotate_deg (cairo_matrix_t *matrix, + double degrees); + +cairo_public void cairo_matrix_translate (cairo_matrix_t *matrix, double tx, double ty); cairo_public void @@ -3034,6 +3038,9 @@ cairo_matrix_scale (cairo_matrix_t *matrix, double sx, double sy); cairo_public void cairo_matrix_rotate (cairo_matrix_t *matrix, double radians); +cairo_public void +cairo_matrix_rotate_deg (cairo_matrix_t *matrix, double degrees); + cairo_public cairo_status_t cairo_matrix_invert (cairo_matrix_t *matrix); diff --git a/src/cairoint.h b/src/cairoint.h index 4fedf861d..f04e81131 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -1941,6 +1941,7 @@ slim_hidden_proto (cairo_mask); slim_hidden_proto (cairo_matrix_init); slim_hidden_proto (cairo_matrix_init_identity); slim_hidden_proto (cairo_matrix_init_rotate); +slim_hidden_proto (cairo_matrix_init_rotate_deg); slim_hidden_proto (cairo_matrix_init_scale); slim_hidden_proto (cairo_matrix_init_translate); slim_hidden_proto (cairo_matrix_invert); -- 2.11.0