[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