In this part of the Cairo graphics programming tutorial, we will talk about transformations:
An affine transform
rotation
translation
shear
translation.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | #include <cairo.h>
#include <gtk/gtk.h>
/*
The following example describes a simple translation.
*/
/*
The example draws a rectangle. Then we do a translation and draw the same rectangle again.
*/
static gboolean on_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data);
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), 300, 230);
gtk_window_set_title(GTK_WINDOW(window), "translation");
gtk_widget_set_app_paintable(window, TRUE);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
static gboolean on_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);
/*
The cairo_translate() function modifies the current transformation matrix by translating the use space origin.
In our case we shift the origin by 100 units in both directions.
*/
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;
}
|
translation.c の実行結果は:
The next example demonstrates a rotation.
rotation.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | #include <cairo.h>
#include <gtk/gtk.h>
#include <math.h>
/*
The example draws a rectangle, performs a translation and a rotation and draws the same rectangle again.
*/
static gboolean on_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data);
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), 300, 230);
gtk_window_set_title(GTK_WINDOW(window), "rotation");
gtk_widget_set_app_paintable(window, TRUE);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
static gboolean on_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);
/*
First we shift the user space origin. Then we rotate it by 180°.
Notice that we specify the angle in radians, not degrees.
2*M_PI = 360°.
*/
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;
}
|
rotation.c の実行結果は:
The next exmaple demonstrates a scaling of an object.
scale.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | #include <cairo.h>
#include <gtk/gtk.h>
/*
This time the example makes the initial rectangle smaller and then bigger by a specific scale factor.
*/
static gboolean on_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data);
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), 360, 140);
gtk_window_set_title(GTK_WINDOW(window), "scale");
gtk_widget_set_app_paintable(window, TRUE);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
static gboolean on_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data){
cairo_t *cr;
cr = gdk_cairo_create(widget->window);
/*
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 of cairo_save() and cairo_restore() functions.
*/
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);
/*
Here we shift the user space origin an scale it by a factor of 0.7.
*/
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;
}
|
scale.c の実行結果は:
In the following examples we perform shearing.
shear.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | #include <cairo.h>
#include <gtk/gtk.h>
/*
In this code example, we perform two shear transformations. For a shear transformation, we do not have a special function.
We must use matrices.
*/
static gboolean on_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data);
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), 360, 140);
gtk_window_set_title(GTK_WINDOW(window), "shear");
gtk_widget_set_app_paintable(window, TRUE);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
static gboolean on_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data){
cairo_t *cr;
/* The cairo_matrix_t is a structure that holds an affine transformation */
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);
/*
This transformation shears y values by 0.5 of the x values.
*/
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);
/*
This transformation multiplies the x value of each coordinate by 0.7 of the y.
*/
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;
}
|
shear.c の実行結果は:
In the following example we create an complex shape by