diff options
Diffstat (limited to 'doc/tutorial/src')
-rw-r--r-- | doc/tutorial/src/.gitignore | 8 | ||||
-rw-r--r-- | doc/tutorial/src/README | 66 | ||||
-rw-r--r-- | doc/tutorial/src/circle.c | 22 | ||||
-rw-r--r-- | doc/tutorial/src/include/cairo-tutorial-gtk.h | 133 | ||||
-rw-r--r-- | doc/tutorial/src/include/cairo-tutorial-pdf.h | 74 | ||||
-rw-r--r-- | doc/tutorial/src/include/cairo-tutorial-png.h | 74 | ||||
-rw-r--r-- | doc/tutorial/src/include/cairo-tutorial-xlib.h | 251 | ||||
-rw-r--r-- | doc/tutorial/src/include/cairo-tutorial.h | 40 | ||||
-rw-r--r-- | doc/tutorial/src/lca.c | 32 | ||||
-rw-r--r-- | doc/tutorial/src/singular.c | 162 | ||||
-rw-r--r-- | doc/tutorial/src/twin.c | 39 |
11 files changed, 901 insertions, 0 deletions
diff --git a/doc/tutorial/src/.gitignore b/doc/tutorial/src/.gitignore new file mode 100644 index 000000000..68af59e73 --- /dev/null +++ b/doc/tutorial/src/.gitignore @@ -0,0 +1,8 @@ +*-gtk +*-pdf +*-png +*-xlib +*.pdf +*.png +*.o +*~ diff --git a/doc/tutorial/src/README b/doc/tutorial/src/README new file mode 100644 index 000000000..a2738da4e --- /dev/null +++ b/doc/tutorial/src/README @@ -0,0 +1,66 @@ +Welcome to the cairo tutorial: + ++--------------------------------+ +| How to Recognize Ugly Graphics | +|(and what you can do about them)| ++--------------------------------+ + +This directory is your personal playground for following along with +the examples. In order for you to make use of these files you will +need to have cairo and its header files installed. You can find +instructions for doing this at: + + http://cairographics.org/tutorial + +Notice that there are a few .c files in this directory. + +You should start out by just typing "make" which will turn each .c +file into several different programs. Go ahead and run each of the +programs and see what they do. Some of them will open up new X windows +while others will simply write their output to files (such .png or +.pdf). + +After you play with those a bit, go ahead and take a look at the +contents of the .c files. You'll see that each file contains a draw() +function that does all of the drawing. + +You might be surprised to notice that there is no main() function in +any of the files. Instead, main is hidden away by means of +cairo-tutorial.h. This rather non-conventional style is used to allow +you to focus on the actual drawing code involved in using cairo, while +not having to worry about the setup semantics. We don't recommend that +you follow this style for real projects. + +As you follow along during the tutorial and get some ideas for things +to draw, you'll want to start making your own .c files. You can copy +an existing file or make your own by following this simple minimal +template: + + #include "cairo-tutorial.h" + + static void + draw (cairo_t *cr, int width, int height) + { + /* Put your drawing code here. */ + } + +Any new file you create will automatically get picked up by the +Makefile so that "make" will compile your file into several different +programs, just like the existing examples. + +If you'd like to control the initial size of the output, you may +define WIDTH and HEIGHT before including cairo-tutorial.h like so: + + #define WIDTH 100 + #define HEIGHT 100 + + #include "cairo-tutorial.h" + +If you would like to change the set of cairo-backend target programs +that are compiled, you may edit the "all" target in the Makefile. + +Have fun! + +-Carl Worth + +cworth@redhat.com diff --git a/doc/tutorial/src/circle.c b/doc/tutorial/src/circle.c new file mode 100644 index 000000000..6bd02e8ba --- /dev/null +++ b/doc/tutorial/src/circle.c @@ -0,0 +1,22 @@ +#include "cairo-tutorial.h" + +static void +draw (cairo_t *cr, int width, int height) +{ + int radius; + + if (width < height) + radius = width/2 - 4; + else + radius = height/2 - 4; + + cairo_move_to (cr, width/2 + radius, height/2); + cairo_arc (cr, width/2, height/2, radius, + 0.0, 2 * M_PI); + + cairo_set_source_rgb (cr, 0.6, 0.8, 1.0); + cairo_fill_preserve (cr); + + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + cairo_stroke (cr); +} diff --git a/doc/tutorial/src/include/cairo-tutorial-gtk.h b/doc/tutorial/src/include/cairo-tutorial-gtk.h new file mode 100644 index 000000000..60516a356 --- /dev/null +++ b/doc/tutorial/src/include/cairo-tutorial-gtk.h @@ -0,0 +1,133 @@ +/* cairo-tutorial-gtk.h - a tutorial framework for cairo with gtk+ + * + * Copyright © 2005, Carl Worth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. + */ + +#include <gtk/gtk.h> +#include <gdk/gdkkeysyms.h> + +#include <cairo.h> + +#ifndef WIDTH +#define WIDTH 400 +#endif + +#ifndef HEIGHT +#define HEIGHT 400 +#endif + +static void +draw (cairo_t *cr, int width, int height); + +#if ! GTK_CHECK_VERSION(2,7,0) +/* copied from gtk+/gdk/gdkcairo.c and gtk+/gdk/x11/gdkdrawable-x11.c + * gdk_cairo_create() which is available in 2.7.0 and later. + */ +static cairo_t * +gdk_cairo_create (GdkDrawable *drawable) +{ + int width, height; + cairo_t *cr = NULL; + cairo_surface_t *surface = NULL; + GdkVisual *visual = gdk_drawable_get_visual (drawable); + + gdk_drawable_get_size (drawable, &width, &height); + if (visual) + surface = cairo_xlib_surface_create (GDK_DRAWABLE_XDISPLAY (drawable), + GDK_DRAWABLE_XID (drawable), + GDK_VISUAL_XVISUAL (visual), + width, height); + else if (gdk_drawable_get_depth (drawable) == 1) + surface = cairo_xlib_surface_create_for_bitmap + (GDK_PIXMAP_XDISPLAY (drawable), + GDK_PIXMAP_XID (drawable), + GDK_SCREEN_XSCREEN (gdk_drawable_get_screen (drawable)), + width, height); + else { + g_warning ("Using Cairo rendering requires the drawable argument to\n" + "have a specified colormap. All windows have a colormap,\n" + "however, pixmaps only have colormap by default if they\n" + "were created with a non-NULL window argument. Otherwise\n" + "a colormap must be set on them with " + "gdk_drawable_set_colormap"); + return NULL; + } + if (surface) { + cr = cairo_create (surface); + cairo_surface_destroy (surface); + } + return cr; +} +#endif + +static gboolean +handle_expose (GtkWidget *widget, + GdkEventExpose *event, + gpointer data) +{ + cairo_t *cr; + + cr = gdk_cairo_create (widget->window); + + draw (cr, widget->allocation.width, widget->allocation.height); + + cairo_destroy (cr); + + return FALSE; +} + +static gboolean +handle_key_press (GtkWidget *widget, + GdkEventKey *event, + gpointer data) +{ + if ((event->keyval == GDK_Q || + event->keyval == GDK_q) && (event->state & GDK_CONTROL_MASK)) + gtk_main_quit (); + + return FALSE; +} + +int +main (int argc, char **argv) +{ + GtkWidget *window, *drawing_area; + + gtk_init (&argc, &argv); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_window_set_default_size (GTK_WINDOW (window), WIDTH, HEIGHT); + gtk_window_set_title (GTK_WINDOW (window), "cairo demo"); + + g_signal_connect (window, "destroy", + G_CALLBACK (gtk_main_quit), NULL); + + drawing_area = gtk_drawing_area_new (); + gtk_container_add (GTK_CONTAINER (window), drawing_area); + + g_signal_connect (drawing_area, "expose-event", + G_CALLBACK (handle_expose), NULL); + + g_signal_connect (window, "key-press-event", + G_CALLBACK (handle_key_press), NULL); + + gtk_widget_show_all (window); + + gtk_main (); + + return 0; +} diff --git a/doc/tutorial/src/include/cairo-tutorial-pdf.h b/doc/tutorial/src/include/cairo-tutorial-pdf.h new file mode 100644 index 000000000..00d0f188e --- /dev/null +++ b/doc/tutorial/src/include/cairo-tutorial-pdf.h @@ -0,0 +1,74 @@ +/* cairo-tutorial-png.h - a tutorial framework for cairo to write a PNG image + * + * Copyright © 2005, Carl Worth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. + */ + +#include <cairo.h> +#include <cairo-pdf.h> + +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include <string.h> + +#ifndef WIDTH +#define WIDTH 400 +#endif + +#ifndef HEIGHT +#define HEIGHT 400 +#endif + +static void +draw (cairo_t *cr, int width, int height); + +int +main (int argc, char **argv) +{ + cairo_surface_t *surface; + cairo_t *cr; + char *filename, *dash; + + filename = strdup (argv[0]); + assert (filename != NULL); + + dash = strrchr (filename, '-'); + + if (strcmp (dash, "-pdf") == 0) { + *dash = '.'; + } else { + char *new_filename; + new_filename = malloc (strlen (filename) + 5); + sprintf (new_filename, "%s.pdf", filename); + free (filename); + filename = new_filename; + } + + surface = cairo_pdf_surface_create (filename, WIDTH, HEIGHT); + + cr = cairo_create (surface); + + draw (cr, WIDTH, HEIGHT); + + cairo_show_page (cr); + + cairo_surface_destroy (surface); + cairo_destroy (cr); + + free (filename); + + return 0; +} diff --git a/doc/tutorial/src/include/cairo-tutorial-png.h b/doc/tutorial/src/include/cairo-tutorial-png.h new file mode 100644 index 000000000..428baf294 --- /dev/null +++ b/doc/tutorial/src/include/cairo-tutorial-png.h @@ -0,0 +1,74 @@ +/* cairo-tutorial-png.h - a tutorial framework for cairo to write a PNG image + * + * Copyright © 2005, Carl Worth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. + */ + +#include <cairo.h> + +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include <string.h> + +#ifndef WIDTH +#define WIDTH 400 +#endif + +#ifndef HEIGHT +#define HEIGHT 400 +#endif + +static void +draw (cairo_t *cr, int width, int height); + +int +main (int argc, char **argv) +{ + cairo_surface_t *surface; + cairo_t *cr; + char *filename, *dash; + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + WIDTH, HEIGHT); + + cr = cairo_create (surface); + + draw (cr, WIDTH, HEIGHT); + + filename = strdup (argv[0]); + assert (filename != NULL); + + dash = strrchr (filename, '-'); + + if (strcmp (dash, "-png") == 0) { + *dash = '.'; + } else { + char *new_filename; + new_filename = malloc (strlen (filename) + 5); + sprintf (new_filename, "%s.png", filename); + free (filename); + filename = new_filename; + } + + cairo_surface_write_to_png (surface, filename); + + free (filename); + + cairo_surface_destroy (surface); + cairo_destroy (cr); + + return 0; +} diff --git a/doc/tutorial/src/include/cairo-tutorial-xlib.h b/doc/tutorial/src/include/cairo-tutorial-xlib.h new file mode 100644 index 000000000..5e78d0354 --- /dev/null +++ b/doc/tutorial/src/include/cairo-tutorial-xlib.h @@ -0,0 +1,251 @@ +/* cairo-tutorial-xlib.h - a tutorial framework for cairo with xlib + * + * Copyright © 2005, Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <strings.h> +#include <X11/Xos.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/Xatom.h> +#include <cairo.h> +#include <cairo-xlib.h> + +#ifndef WIDTH +#define WIDTH 400 +#endif + +#ifndef HEIGHT +#define HEIGHT 400 +#endif + +#ifndef DEFAULT_VISUAL +#define DEFAULT_VISUAL 0 +#endif + +static void +Usage (char *program) +{ + fprintf (stderr, "Usage: %s\n", program); + fprintf (stderr, "\t-display <display-name>\n"); + fprintf (stderr, "\t-geometry <geometry>\n"); + exit (1); +} + +char *dpy_name; +VisualID vid = DEFAULT_VISUAL; +Colormap colormap; +Visual *visual; +int depth; +unsigned int width = WIDTH, height = HEIGHT; +Window win; +Pixmap pix; +GC gc; + +static void +draw (cairo_t *cr, int width, int height); + +static void +draw_to_pixmap (Display *dpy, Pixmap pix) +{ + cairo_surface_t *surface; + cairo_t *cr; + + surface = cairo_xlib_surface_create (dpy, pix, visual, + width, height); + cr = cairo_create (surface); + + draw (cr, width, height); + + cairo_destroy (cr); + cairo_surface_destroy (surface); +} + +static void +handle_configure (Display *dpy, XConfigureEvent *cev) +{ + width = cev->width; + height = cev->height; + + XFreePixmap(dpy, pix); + pix = XCreatePixmap(dpy, win, width, height, depth); + XFillRectangle(dpy, pix, gc, 0, 0, width, height); + draw_to_pixmap (dpy, pix); +} + +static void +handle_expose (Display *dpy, XExposeEvent *eev) +{ + XCopyArea (dpy, pix, win, gc, + eev->x, eev->y, + eev->width, eev->height, + eev->x, eev->y); +} + +int +main (argc, argv) + int argc; + char **argv; +{ + Display *dpy; + Window root = 0; + char **init_argv = argv; + XSetWindowAttributes attr; + int scr; + int x = 0, y = 0; + int geometryMask; + int border_width = 1; + XSizeHints sizeHints; + XWMHints wmHints; + XClassHint classHints; + XEvent ev; + XEvent eev; + int HasExpose = 0; + int sync = 0; + XTextProperty wm_name, icon_name; + Atom wm_delete_window; + unsigned long gc_mask; + XGCValues gcv; + char quit_string[10]; + unsigned long window_mask; + int has_colormap = 0; + + wm_name.value = (unsigned char *) argv[0]; + wm_name.encoding = XA_STRING; + wm_name.format = 8; + wm_name.nitems = strlen (argv[0]) + 1; + icon_name = wm_name; + gc_mask = 0; + while (*++argv) { + if (!strcmp (*argv, "-display")) + dpy_name = *++argv; + else if (!strcmp (*argv, "-visual")) + vid = strtol(*++argv, NULL, 0); + else if (!strcmp (*argv, "-geometry")) + geometryMask = XParseGeometry (*++argv, &x, &y, &width, &height); + else if (!strcmp (*argv, "-sync")) + sync = 1; + else if (!strcmp (*argv, "-bw")) + border_width = strtol(*++argv, NULL, 0); + else if (!strcmp (*argv, "-root")) + root = strtol (*++argv, NULL, 0); + else + Usage (*init_argv); + } + sizeHints.flags = 0; + wmHints.flags = InputHint; + wmHints.input = True; + classHints.res_name = init_argv[0]; + classHints.res_class = init_argv[0]; + dpy = XOpenDisplay (dpy_name); + if (!dpy) { + fprintf (stderr, "Error: failed to open display: %s\n", + XDisplayName (dpy_name)); + exit (1); + } + if (sync) + XSynchronize (dpy, sync); + scr = DefaultScreen (dpy); + if (!root) + root = RootWindow (dpy, scr); + window_mask = CWBackPixel|CWBorderPixel|CWEventMask; + if (!has_colormap) + colormap = DefaultColormap (dpy, scr); + else + { + window_mask |= CWColormap; + attr.colormap = colormap; + } + visual = DefaultVisual (dpy, scr); + depth = DefaultDepth (dpy, scr); + if (vid) + { + XVisualInfo vi, *vi_ret; + int n; + + vi.visualid = vid; + vi.screen = scr; + vi_ret = XGetVisualInfo (dpy, VisualIDMask|VisualScreenMask, + &vi, &n); + if (vi_ret) + { + visual = vi_ret->visual; + if (!has_colormap) + { + colormap = XCreateColormap (dpy, root, visual, AllocNone); + window_mask |= CWColormap; + attr.colormap = colormap; + } + depth = vi_ret->depth; + } + } + attr.background_pixel = WhitePixel (dpy, scr); + attr.border_pixel = 0; + attr.event_mask = ExposureMask|KeyPressMask|KeyReleaseMask|StructureNotifyMask; + wm_delete_window = XInternAtom(dpy, "WM_DELETE_WINDOW", False); + win = XCreateWindow (dpy, root, x, y, width, height, border_width, + depth, InputOutput, + visual, + window_mask, + &attr); + pix = XCreatePixmap (dpy, win, width, height, depth); + gcv.foreground = WhitePixel (dpy, scr); + gc = XCreateGC (dpy, pix, GCForeground, &gcv); + XFillRectangle(dpy, pix, gc, 0, 0, width, height); + draw_to_pixmap (dpy, pix); + XSetWMProperties (dpy, win, + &wm_name, &icon_name, + init_argv, argc, + &sizeHints, &wmHints, 0); + XSetWMProtocols (dpy, win, &wm_delete_window, 1); + XMapWindow (dpy, win); + for (;;) { + XNextEvent (dpy, &ev); + if (HasExpose && ev.type != Expose) { + HasExpose = 0; + handle_expose (dpy, &eev.xexpose); + } + switch (ev.type) { + case ConfigureNotify: + handle_configure (dpy, &ev.xconfigure); + break; + case Expose: + if (QLength(dpy)) { + eev = ev; + HasExpose = 1; + } else if (ev.xexpose.count == 0) { + handle_expose (dpy, &ev.xexpose); + } + break; + case KeyPress: + if (XLookupString ((XKeyEvent *) &ev, quit_string, sizeof (quit_string), 0, 0) == 1) { + switch (quit_string[0]) { + case 'q': + exit (0); + case 'c': + XClearArea (dpy, ev.xkey.window, 0, 0, 0, 0, True); + break; + } + } + break; + case ClientMessage: + exit (0); + } + } +} diff --git a/doc/tutorial/src/include/cairo-tutorial.h b/doc/tutorial/src/include/cairo-tutorial.h new file mode 100644 index 000000000..ec738e915 --- /dev/null +++ b/doc/tutorial/src/include/cairo-tutorial.h @@ -0,0 +1,40 @@ +/* cairo-tutorial-gtk.h - a tutorial framework for cairo + * + * Copyright © 2005, Carl Worth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. + */ + +#include <cairo.h> +#include <math.h> + +/* The application program may override these before including + * cairo-tutorial.h in order to get a window of a different size. */ +#ifndef WIDTH +#define WIDTH 400 +#endif + +#ifndef HEIGHT +#define HEIGHT 400 +#endif + +#ifdef CAIRO_TUTORIAL_GTK +#include "cairo-tutorial-gtk.h" +#elif CAIRO_TUTORIAL_XLIB +#include "cairo-tutorial-xlib.h" +#elif CAIRO_TUTORIAL_PDF +#include "cairo-tutorial-pdf.h" +#elif CAIRO_TUTORIAL_PNG +#include "cairo-tutorial-png.h" +#endif diff --git a/doc/tutorial/src/lca.c b/doc/tutorial/src/lca.c new file mode 100644 index 000000000..0b131afaf --- /dev/null +++ b/doc/tutorial/src/lca.c @@ -0,0 +1,32 @@ +#define WIDTH 750 +#define HEIGHT 360 + +#include "cairo-tutorial.h" + +static void +draw (cairo_t *cr, int width, int height) +{ + cairo_save (cr); + + cairo_translate (cr, 60, 60); + cairo_scale (cr, 3, 3); + + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND); + cairo_set_line_width (cr, 20); + + /* L */ + cairo_move_to (cr, 0, 0); + cairo_line_to (cr, 0, 80); + cairo_line_to (cr, 50, 80); + + /* C */ + cairo_move_to (cr, 110 + 40 * cos (M_PI / 3), 40 + 40 * sin(M_PI / 3)); + cairo_arc (cr, 110, 40, 40, M_PI / 3, -M_PI / 3); + + /* A */ + cairo_move_to (cr, 160, 80); + cairo_curve_to (cr, 160, -30, 210, -30, 210, 80); + + cairo_stroke (cr); +} diff --git a/doc/tutorial/src/singular.c b/doc/tutorial/src/singular.c new file mode 100644 index 000000000..958b2b047 --- /dev/null +++ b/doc/tutorial/src/singular.c @@ -0,0 +1,162 @@ +/** + * Uses Singular values of transformation matrix to find the length of the + * major and minor axes of the scaled pen. + * + * Put this file in cairo/doc/tutorial/src and type "make" + */ + +#define WIDTH 300 +#define HEIGHT 300 + +#include "cairo-tutorial.h" + +#include <math.h> + +/* + * Finds the singular values of the non-translation part of matrix. + * + * Let M be the cairo transformation matrix in question: + * + * ⌈xx xy⌉ + * M = |yx yy| + * ⌊x0 y0⌋ + * + * The non-translation part is: + * + * A = ⌈xx xy⌉ + * ⌊yx yy⌋ + * + * The non-zero singular values of A are the square roots of the non-zero + * eigenvalues of A⁺ A, where A⁺ is A-transpose. + * + * A⁺ A = ⌈xx yx⌉⌈xx xy⌉ = ⌈xx²+yx² xx*xy+yx*yy⌉ + * ⌊xy yy⌋⌊yx yy⌋ ⌊xx*xy+yx*yy xy²+yy²⌋ + * + * Name those: + * + * B = A⁺ A = ⌈a k⌉ + * ⌊k b⌋ + * + * The eigenvalues of B satisfy: + * + * λ² - (a+b).λ + a.b - k² = 0 + * + * The eigenvalues are: + * __________________ + * (a+b) ± √(a+b)² - 4(a.b-k²) + * λ = --------------------------- + * 2 + * that simplifies to: + * _______________ + * λ = (a+b)/2 ± √((a-b)/2)² + k² + * + * And the Singular values are the root of λs. + * + */ +static void +get_singular_values (const cairo_matrix_t *matrix, + double *major, + double *minor) +{ + double xx = matrix->xx, xy = matrix->xy; + double yx = matrix->yx, yy = matrix->yy; + + double a = xx*xx+yx*yx; + double b = xy*xy+yy*yy; + double k = xx*xy+yx*yy; + + double f = (a+b) * .5; + double g = (a-b) * .5; + double delta = sqrt (g*g + k*k); + + if (major) + *major = sqrt (f + delta); + if (minor) + *minor = sqrt (f - delta); +} + +/* + * Finds the length of the major and minor axes of the pen for a cairo_t, + * identified by the current transformation matrix and line width. + * + * Returned values are in device units. + */ +static void +get_pen_axes (cairo_t *cr, + double *major, + double *minor) +{ + double width; + cairo_matrix_t matrix; + + width = cairo_get_line_width (cr); + cairo_get_matrix (cr, &matrix); + + get_singular_values (&matrix, major, minor); + + if (major) + *major *= width; + if (minor) + *minor *= width; +} + +static void +draw (cairo_t *cr, int width, int height) +{ + double major_width, minor_width; + + /* clear background */ + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + +#define W width +#define H height +#define B ((width+height)/16) + + /* the spline we want to stroke */ + cairo_move_to (cr, W-B, B); + cairo_curve_to (cr, -W, B, + 2*W, H-B, + B, H-B); + + /* the effect is show better with round caps */ + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + + /* set the skewed pen */ + cairo_rotate (cr, +.7); + cairo_scale (cr, .5, 2.); + cairo_rotate (cr, -.7); + cairo_set_line_width (cr, B); + + get_pen_axes (cr, &major_width, &minor_width); + + /* stroke with "major" pen in translucent red */ + cairo_save (cr); + cairo_identity_matrix (cr); + cairo_set_line_width (cr, major_width); + cairo_set_source_rgba (cr, 1.0, 0.0, 0.0, .9); + cairo_stroke_preserve (cr); + cairo_restore (cr); + + /* stroke with skewed pen in translucent black */ + cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, .9); + cairo_stroke_preserve (cr); + + /* stroke with "minor" pen in translucent yellow */ + cairo_save (cr); + cairo_identity_matrix (cr); + cairo_set_line_width (cr, minor_width); + cairo_set_source_rgba (cr, 1.0, 1.0, 0.0, .9); + cairo_stroke_preserve (cr); + cairo_restore (cr); + + /* stroke with hairline in black */ + cairo_save (cr); + cairo_identity_matrix (cr); + cairo_set_line_width (cr, 1); + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + cairo_stroke_preserve (cr); + cairo_restore (cr); + + cairo_new_path (cr); +} diff --git a/doc/tutorial/src/twin.c b/doc/tutorial/src/twin.c new file mode 100644 index 000000000..14347bac2 --- /dev/null +++ b/doc/tutorial/src/twin.c @@ -0,0 +1,39 @@ +/** + * Put this file in cairo/doc/tutorial/src and type "make" + */ + +#define WIDTH 1350 +#define HEIGHT 900 + +#include "cairo-tutorial.h" + + +static void +draw (cairo_t *cr, int width, int height) +{ + int i, j, h; + unsigned char s[2] = {0, 0}; + + /* clear background */ + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_select_font_face (cr, + "@cairo:", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + + h = 2; + for (i = 8; i < 48; i >= 24 ? i+=3 : i++) { + cairo_set_font_size (cr, i); + for (j = 33; j < 128; j++) { + if (j == 33 || (j == 80 && i > 24)) { + h += i + 2; + cairo_move_to (cr, 10, h); + } + s[0] = j; + cairo_show_text (cr, (const char *) s); + } + } +} |