[cairo-commit] [cairo-www] src/cookbook src/cookbook.mdwn

Bryce Harrington bryce at freedesktop.org
Fri Jan 15 13:29:12 PST 2016


 src/cookbook.mdwn                       |    1 
 src/cookbook/ellipses.mdwn              |  114 ++++++++++++++++++++++++++++++++
 src/cookbook/ellipses/ellipse_right.png |binary
 src/cookbook/ellipses/ellipse_wrong.png |binary
 4 files changed, 115 insertions(+)

New commits:
commit 32153d821ad1ec87c37afe869bb2db2e61b9db74
Author: Lawrence D'Oliveiro <ldo at geek-central.gen.nz>
Date:   Wed Dec 23 03:11:00 2015 +0000

    add ellipses cookbook example

diff --git a/src/cookbook.mdwn b/src/cookbook.mdwn
index f164bca..9e5471b 100644
--- a/src/cookbook.mdwn
+++ b/src/cookbook.mdwn
@@ -4,6 +4,7 @@
 
 + General Drawing
     * [[Rounded_rectangles|roundedrectangles]]
+    * [[Ellipses With Uniform Stroke Width|ellipses]]
     * [[A_description_of_compositing_operators_in_Cairo|operators]]
 
 + Matrix Transformations
diff --git a/src/cookbook/ellipses.mdwn b/src/cookbook/ellipses.mdwn
new file mode 100644
index 0000000..8779e47
--- /dev/null
+++ b/src/cookbook/ellipses.mdwn
@@ -0,0 +1,114 @@
+[[!meta title="Ellipses With Uniform Stroke Width"]]
+
+Cairo has built-in calls for drawing arcs of circles. The following discusses how to use them
+to draw ellipses.
+
+##Common Setup
+
+The following examples will be drawing an ellipse within an image area defined as follows:
+
+    const int img_width = 256;
+    const int img_height = 256;
+    cairo_surface_t * const pix = cairo_image_surface_create
+      (
+        /*format =*/ CAIRO_FORMAT_RGB24,
+        /*width =*/ img_width,
+        /*height =*/ img_height
+      );
+    cairo_t * const cr = cairo_create(pix);
+
+The ellipse will be drawn as a circle centred within the drawing area. Before the circle
+is drawn, the following scaling is applied:
+
+    cairo_translate(cr, img_width / 2.0, img_height / 2.0);
+    cairo_scale(cr, 0.5, 1);
+    cairo_translate(cr, - img_width / 2.0, - img_height / 2.0);
+
+This shrinks subsequent drawing operations (including path
+construction) horizontally by a factor of 0.5 [about the
+image centre](../transform_about_point), to turn the circle into an
+ellipse. The ellipse itself is then constructed very simply:
+
+    cairo_arc
+      (
+        /*cr =*/ cr,
+        /*xc =*/ img_width / 2.0,
+        /*yc =*/ img_height / 2.0,
+        /*radius =*/ img_width / 3.0,
+        /*angle1 =*/ 0,
+        /*angle2 =*/ 2 * M_PI
+      );
+
+The following examples use a thick line width (20 units) to make the problem
+(and its solution) clearer.
+
+##The Wrong Way
+
+The obvious way to turn a circle into an ellipse is to apply non-uniform scaling to it.
+This works, but is prone to an interesting side-effect:
+
+    cairo_set_source_rgb(cr, 1, 1, 1);
+    cairo_paint(cr);
+    cairo_set_source_rgb(cr, 0, 0, 0);
+    cairo_translate(cr, img_width / 2.0, img_height / 2.0);
+    cairo_scale(cr, 0.5, 1);
+    cairo_translate(cr, - img_width / 2.0, - img_height / 2.0);
+    cairo_new_path(cr);
+    cairo_arc
+      (
+        /*cr =*/ cr,
+        /*xc =*/ img_width / 2.0,
+        /*yc =*/ img_height / 2.0,
+        /*radius =*/ img_width / 3.0,
+        /*angle1 =*/ 0,
+        /*angle2 =*/ 2 * M_PI
+      );
+    cairo_set_line_width(cr, 20.0);
+    cairo_stroke(cr);
+
+Example output:
+
+[[!img "ellipse_wrong.png" link="no"]]
+
+The problem is that the CTM also affects the `cairo_stroke` call. Thus, where the
+curve is narrow, the stroke gets narrow as well. This is probably not what you want.
+
+##The Right Way
+
+The answer is to apply the non-uniform scaling *only during the path construction*,
+and remove it before calling `cairo_stroke`. Here the CTM is saved before path
+construction, and restored after it:
+
+    cairo_set_source_rgb(cr, 1, 1, 1);
+    cairo_paint(cr);
+    cairo_set_source_rgb(cr, 0, 0, 0);
+      {
+        cairo_matrix_t save_matrix;
+        cairo_get_matrix(cr, &save_matrix);
+        cairo_translate(cr, img_width / 2.0, img_height / 2.0);
+        cairo_scale(cr, 0.5, 1);
+        cairo_translate(cr, - img_width / 2.0, - img_height / 2.0);
+        cairo_new_path(cr);
+        cairo_arc
+          (
+            /*cr =*/ cr,
+            /*xc =*/ img_width / 2.0,
+            /*yc =*/ img_height / 2.0,
+            /*radius =*/ img_width / 3.0,
+            /*angle1 =*/ 0,
+            /*angle2 =*/ 2 * M_PI
+          );
+        cairo_set_matrix(cr, &save_matrix);
+      }
+    cairo_set_line_width(cr, 20.0);
+    cairo_stroke(cr);
+
+Example output:
+
+[[!img "ellipse_right.png" link="no"]]
+
+Much better, don’t you think?
+
+Alternatively you may call `cairo_save` to save the entire graphics state before
+the path construction, and `cairo_restore` afterwards, before the `cairo_stroke`
+call. Cairo’s saved graphics state includes the CTM, but not the current path itself.
diff --git a/src/cookbook/ellipses/ellipse_right.png b/src/cookbook/ellipses/ellipse_right.png
new file mode 100644
index 0000000..e2041bf
Binary files /dev/null and b/src/cookbook/ellipses/ellipse_right.png differ
diff --git a/src/cookbook/ellipses/ellipse_wrong.png b/src/cookbook/ellipses/ellipse_wrong.png
new file mode 100644
index 0000000..720eaf8
Binary files /dev/null and b/src/cookbook/ellipses/ellipse_wrong.png differ


More information about the cairo-commit mailing list