Re: Shouldn't Cairo use/offer degrees rather than radians?

David Kastrup <[email protected]>
Newsgroups gmane.comp.lib.cairo
Organization Organization?!?
Message-ID <[email protected]>
Lawrence D'Oliveiro <[email protected]> writes:

> On Thu, 29 Jun 2017 08:08:04 +0200, David Kastrup wrote:
>
>> Lawrence D'Oliveiro <[email protected]> writes:
>> 
>>> You realize that, by introducing this distortion, you are reducing
>>> the accuracy of the computation?  
>> 
>> It replaces a sin(x)/cos(x) pair by a sin(x)/sin(pi/2-x) pair.  The
>> largest cumulative effect is at pi/4.
>
> So you introduce a kink at π/4. How is this any better, again?

There is no kink.  None at all.  The handover between different
functions happens at sin(pi/2) where there is a large stretch of 1.0.
At pi/4, there is no discontinuity but the sin/cos pair is taken as
(sin(pi/4), sin(pi/4)) instead of (sin(pi/4), cos(pi/4)).  Since pi/4
has no actual numeric representation, getting an exact angle of 45
degree in the transformation matrix may come at the cost of a larger
magnitude jitter of the determinant _iff_ you have a very, very accurate
sin/cos implementation.  Mind you: that jitter is still less than 2ulp
so you need a very good sin/cos implementation to even measure it.

Square the transform matrix for 45 degrees 20 times or so with the
degree function and the radian function and compare the results and see
which you like better.

I'll append the patch to Cairo to make it easier for you.

>>> I wonder what the term is, for deliberately producing inaccurate
>>> answers just to look good...  
>> 
>> A very well-considered tradeoff and solid engineering?
>
> “Engineering” is not the term that comes to mind. Try “marketing” or
> “management”.

Please compare the results.

> You do realize that your claim about Cairo’s “inability to reliably
> draw a half circle that seamlessly connects with another half circle
> under any rasterization” is complete nonsense, right?

Sigh.  If you cannot specify an angle for pi for which sin(angle)==0,
you will have rasterizations of half circle arcs that won't line up
perfectly because you then cannot make the half circles butt up
perfectly, and "too small to be noticeable" becomes a statistic rather
than a static feature under rasterization.

--
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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.