The Cairo graphics tutorial -------Transformations
来源:互联网 发布:基金产品经理 知乎 编辑:程序博客网 时间:2024/05/19 04:51
In this part of the Cairo graphics programming tutorial, we will talk about transformations.
An affine transform is composed of zero or more linear transformations (rotation, scaling or shear) and translation (shift). Several linear transformations can be combined into a single matrix.Arotation is a transformation that moves a rigid body around a fixed point.Ascaling is a transformation that enlarges or diminishes objects. The scale factor is the same in all directions.Atranslation is a transformation that moves every point a constant distance in a specified direction.Ashear is a transformation that moves an object perpendicular to agiven axis, with greater value on one side of the axis than the other.
sources: (wikipedia.org, freedictionary.com)
Translation
The following example describes a simple translation.
#include <cairo.h>#include <gtk/gtk.h>static gbooleanon_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data){ cairo_t *cr; cr = gdk_cairo_create (widget->window); cairo_set_source_rgb(cr, 0.6, 0.6, 0.6); cairo_rectangle(cr, 20, 20, 80, 50); cairo_stroke_preserve(cr); cairo_set_source_rgb(cr, 1, 1, 1); cairo_fill(cr); cairo_translate(cr, 100, 100); cairo_set_source_rgb(cr, 0.6, 0.6, 0.6); cairo_rectangle(cr, 20, 20, 80, 50); cairo_stroke_preserve(cr); cairo_set_source_rgb(cr, 1, 1, 1); cairo_fill(cr); cairo_destroy(cr); return FALSE;}int main(int argc, char *argv[]){ GtkWidget *window; gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); g_signal_connect(window, "expose-event", G_CALLBACK (on_expose_event), NULL); g_signal_connect(window, "destroy", G_CALLBACK (gtk_main_quit), NULL); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); gtk_window_set_default_size(GTK_WINDOW(window), 300, 230); gtk_widget_set_app_paintable(window, TRUE); gtk_widget_show_all(window); gtk_main(); return 0;}
The examle draws a rectangle. Then we do a translation and draw the same rectangle again.
cairo_translate(cr, 100, 100);
The cairo_translate() function modifies the current transormation matrix by tranlating the user space origin.In our case we shift the origin by 100 units in both directions.
Rotation
The next example demonstrates a rotation.
#include <cairo.h>#include <gtk/gtk.h>#include <math.h>static gbooleanon_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data){ cairo_t *cr; cr = gdk_cairo_create (widget->window); cairo_set_source_rgb(cr, 0.6, 0.6, 0.6); cairo_rectangle(cr, 20, 20, 80, 50); cairo_stroke_preserve(cr); cairo_set_source_rgb(cr, 1, 1, 1); cairo_fill(cr); cairo_translate(cr, 150, 100); cairo_rotate(cr, M_PI/2); cairo_set_source_rgb(cr, 0.6, 0.6, 0.6); cairo_rectangle(cr, 20, 20, 80, 50); cairo_stroke_preserve(cr); cairo_set_source_rgb(cr, 1, 1, 1); cairo_fill(cr); cairo_destroy(cr); return FALSE;}int main(int argc, char *argv[]){ GtkWidget *window; gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); g_signal_connect(window, "expose-event", G_CALLBACK (on_expose_event), NULL); g_signal_connect(window, "destroy", G_CALLBACK (gtk_main_quit), NULL); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); gtk_window_set_default_size(GTK_WINDOW(window), 300, 230); gtk_widget_set_app_paintable(window, TRUE); gtk_widget_show_all(window); gtk_main(); return 0;}
The example draws a rectangle, performs a translation and a rotation and draws the same rectangle again.
cairo_translate(cr, 150, 100); cairo_rotate(cr, M_PI/2);
First we shift the user space origin. Then we rotate it by 180°. Notice that we specify the angle in radians, not degrees.2M_PI = 360°.
Scale
The next example demonstrates a scaling of an object.
#include <cairo.h>#include <gtk/gtk.h>static gbooleanon_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data){ cairo_t *cr; cr = gdk_cairo_create (widget->window); cairo_save(cr); cairo_set_source_rgb(cr, 0.6, 0.6, 0.6); cairo_rectangle(cr, 20, 30, 80, 50); cairo_stroke_preserve(cr); cairo_set_source_rgb(cr, 1, 1, 1); cairo_fill(cr); cairo_restore(cr); cairo_save(cr); cairo_translate(cr, 130, 30); cairo_scale(cr, 0.7, 0.7); cairo_set_source_rgb(cr, 0.6, 0.6, 0.6); cairo_rectangle(cr, 0, 0, 80, 50); cairo_stroke_preserve(cr); cairo_set_source_rgb(cr, 1, 1, 1); cairo_fill(cr); cairo_restore(cr); cairo_save(cr); cairo_translate(cr, 220, 30); cairo_scale(cr, 1.5, 1.5); cairo_set_source_rgb(cr, 0.6, 0.6, 0.6); cairo_rectangle(cr, 0, 0, 80, 50); cairo_stroke_preserve(cr); cairo_set_source_rgb(cr, 1, 1, 1); cairo_fill(cr); cairo_restore(cr); cairo_destroy(cr); return FALSE;}int main(int argc, char *argv[]){ GtkWidget *window; gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); g_signal_connect(window, "expose-event", G_CALLBACK (on_expose_event), NULL); g_signal_connect(window, "destroy", G_CALLBACK (gtk_main_quit), NULL); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); gtk_window_set_default_size(GTK_WINDOW(window), 360, 140); gtk_widget_set_app_paintable(window, TRUE); gtk_widget_show_all(window); gtk_main(); return 0;}
This time the example makes the initial rectangle smaller and then bigger by a specific scale factor.
cairo_save(cr); ... cairo_restore(cr);
We want to perform two scaling operations on the initial rectangle. Therefore, we need to save the initial transformation matrix. This is done by a pair ofcairo_save()
and cairo_restore()
functions.
cairo_translate(cr, 130, 30); cairo_scale(cr, 0.7, 0.7);
Here we shift the user space origin an scale it by a factor of 0.7.
Shear
In the following example we perform shearing.
#include <cairo.h>#include <gtk/gtk.h>static gbooleanon_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data){ cairo_t *cr; cairo_matrix_t matrix; cr = gdk_cairo_create (widget->window); cairo_save(cr); cairo_set_source_rgb(cr, 0.6, 0.6, 0.6); cairo_rectangle(cr, 20, 30, 80, 50); cairo_stroke_preserve(cr); cairo_set_source_rgb(cr, 1, 1, 1); cairo_fill(cr); cairo_restore(cr); cairo_save(cr); cairo_translate(cr, 130, 30); cairo_matrix_init(&matrix, 1.0, 0.5, 0.0, 1.0, 0.0, 0.0); cairo_transform (cr, &matrix); cairo_set_source_rgb(cr, 0.6, 0.6, 0.6); cairo_rectangle(cr, 0, 0, 80, 50); cairo_stroke_preserve(cr); cairo_set_source_rgb(cr, 1, 1, 1); cairo_fill(cr); cairo_restore(cr); cairo_save(cr); cairo_translate(cr, 220, 30); cairo_matrix_init(&matrix, 1.0, 0.0, 0.7, 1.0, 0.0, 0.0); cairo_transform(cr, &matrix); cairo_set_source_rgb(cr, 0.6, 0.6, 0.6); cairo_rectangle(cr, 0, 0, 80, 50); cairo_stroke_preserve(cr); cairo_set_source_rgb(cr, 1, 1, 1); cairo_fill(cr); cairo_restore(cr); cairo_destroy(cr); return FALSE;}int main(int argc, char *argv[]){ GtkWidget *window; gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); g_signal_connect(window, "expose-event", G_CALLBACK(on_expose_event), NULL); g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); gtk_window_set_default_size(GTK_WINDOW(window), 360, 140); gtk_widget_set_app_paintable(window, TRUE); gtk_widget_show_all(window); gtk_main(); return 0;}
In this code example, we perform two shear transformations. For a shear transformation, we do not have a special function. We must use matrices.
cairo_matrix_t matrix;
The cairo_matrix_t
is a structure that holds an affine transformation.
cairo_matrix_init(&matrix, 1.0, 0.5, 0.0, 1.0, 0.0, 0.0); cairo_transform (cr, &matrix);
This transformation shears y values by 0.5 of the x values.
cairo_matrix_init(&matrix, 1.0, 0.0, 0.7, 1.0, 0.0, 0.0); cairo_transform(cr, &matrix);
And this transformation multiplies the x value of each coordinate by 0.7 of the y.
Ellipses
In the following example we create an complex shape by rotating a bunch of ellipses.
#include <cairo.h>#include <gtk/gtk.h>static gbooleanon_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data){ cairo_t *cr; cr = gdk_cairo_create(widget->window); gint width, height; gtk_window_get_size(GTK_WINDOW(widget), &width, &height); cairo_set_line_width(cr, 0.5); cairo_translate(cr, width/2, height/2); cairo_arc(cr, 0, 0, 120, 0, 2 * M_PI); cairo_stroke(cr); gint i; cairo_save(cr); for ( i = 0; i < 36; i++) { cairo_rotate(cr, i*M_PI/36); cairo_scale(cr, 0.3, 1); cairo_arc(cr, 0, 0, 120, 0, 2 * M_PI); cairo_restore(cr); cairo_stroke(cr); cairo_save(cr); } cairo_destroy(cr); return FALSE;}int main(int argc, char *argv[]){ GtkWidget *window; gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); g_signal_connect(G_OBJECT(window), "expose-event", G_CALLBACK(on_expose_event), NULL); g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); gtk_window_set_default_size(GTK_WINDOW(window), 350, 250); gtk_widget_set_app_paintable(window, TRUE); gtk_widget_show_all(window); gtk_main(); return 0;}
cairo_translate(cr, width/2, height/2); cairo_arc(cr, 0, 0, 120, 0, 2 * M_PI); cairo_stroke(cr);
In the middle of the GTK+ window, we create a circle. This will be a bounding circle for our ellipses.
cairo_save(cr); for ( i = 0; i < 36; i++) { cairo_rotate(cr, i*M_PI/36); cairo_scale(cr, 0.3, 1); cairo_arc(cr, 0, 0, 120, 0, 2 * M_PI); cairo_restore(cr); cairo_stroke(cr); cairo_save(cr); }
We create 36 ellipses along the path of our bounding circle. An ellipse is a scaled circle. We rotate the ellipses. Thus we create an interesting shape.
Star
The next example shows a rotating and scaling star.
#include <cairo.h>#include <gtk/gtk.h>#include <math.h>int points[11][2] = { { 0, 85 }, { 75, 75 }, { 100, 10 }, { 125, 75 }, { 200, 85 }, { 150, 125 }, { 160, 190 }, { 100, 150 }, { 40, 190 }, { 50, 125 }, { 0, 85 } };static gbooleanon_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data){ cairo_t *cr; static gdouble angle = 0; static gdouble scale = 1; static gdouble delta = 0.01; gint width, height; gtk_window_get_size(GTK_WINDOW(widget), &width, &height); cr = gdk_cairo_create(widget->window); cairo_set_source_rgb(cr, 0, 0.44, 0.7); cairo_set_line_width(cr, 1); cairo_translate(cr, width / 2, height / 2 ); cairo_rotate(cr, angle); cairo_scale(cr, scale, scale); gint i; for ( i = 0; i < 10; i++ ) { cairo_line_to(cr, points[i][0], points[i][1]); } cairo_close_path(cr); cairo_fill(cr); cairo_stroke(cr); if ( scale < 0.01 ) { delta = -delta; } else if (scale > 0.99) { delta = -delta; } scale += delta; angle += 0.01; cairo_destroy(cr); return FALSE;}static gbooleantime_handler (GtkWidget *widget){ if (widget->window == NULL) return FALSE; gtk_widget_queue_draw(widget); return TRUE;}int main(int argc, char *argv[]){ GtkWidget *window; gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_widget_add_events (window, GDK_BUTTON_PRESS_MASK); g_signal_connect(window, "expose-event", G_CALLBACK(on_expose_event), NULL); g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); gtk_window_set_title(GTK_WINDOW(window), "star"); gtk_window_set_default_size(GTK_WINDOW(window), 400, 300); gtk_widget_set_app_paintable(window, TRUE); g_timeout_add(10, (GSourceFunc) time_handler, (gpointer) window); gtk_widget_show_all(window); gtk_main(); return 0;}
In this example, we create a star object. We will translate it, rotate it and scale it.
cairo_translate(cr, width / 2, height / 2 ); cairo_rotate(cr, angle); cairo_scale(cr, scale, scale
We shift the star into the middle of the window. Rotate it and scale it.
for ( i = 0; i < 10; i++ ) { cairo_line_to(cr, points[i][0], points[i][1]); } cairo_close_path(cr); cairo_fill(cr); cairo_stroke(cr);
Here we draw the star object.
if ( scale < 0.01 ) { delta = -delta; } else if (scale > 0.99) { delta = -delta; }
These line control the growing or shrinking of the star object.
In this part of the Cairo graphics tutorial, we talked about transformations.
- The Cairo graphics tutorial -------Transformations
- The Cairo graphics tutorial -------Cairo definitions
- The Cairo graphics tutorial -------Cairo backends
- The Cairo graphics tutorial -------Text in Cairo
- The Cairo graphics tutorial -------Images in Cairo
- The Cairo graphics tutorial -------Introduction
- The Cairo graphics tutorial -------Transparency
- The Cairo graphics tutorial -------Compositing
- The Cairo graphics tutorial -------Clipping and masking
- The Cairo graphics tutorial -------Custom GTK widget
- The Cairo graphics tutorial -------Basic drawing in Cairo
- The Cairo graphics tutorial -------Shapes and fills in Cairo
- Tutorial 11 - Concatenating Transformations
- Cairo Tutorial for Python Programmers
- Cairo Tutorial for Python Programmers
- The Cg Tutorial: The Definitive Guide to Programmable Real-Time Graphics
- 关于《Cairo Tutorial for Python Programmers 》
- cairo
- 反正切函数的应用解题报告
- The Cairo graphics tutorial -------Transparency
- The Cairo graphics tutorial -------Compositing
- java/基础知识
- The Cairo graphics tutorial -------Clipping and masking
- The Cairo graphics tutorial -------Transformations
- input 数组
- 如何装载带有时间戳的数据
- csv和Excel文件互转
- The Cairo graphics tutorial -------Text in Cairo
- The Cairo graphics tutorial -------Images in Cairo
- ANDROID音频系统散记之四:4.0音频系统HAL初探
- uboot nor flash驱动移植(基于am29lv160bt)之环境变量没法保存的办法
- JavaEE开发学习笔记(2)