/* * model-display.c * * Display atomic models * * (c) 2006-2007 Thomas White * * synth2d - Two-Dimensional Crystallographic Fourier Synthesis * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #if HAVE_CAIRO #include #include #endif #include "model.h" #include "elements.h" #include "symmetry.h" #if HAVE_CAIRO static double model_oblique_x(double x, double y, int height, double gamma, int ny) { double offs; if ( gamma <= M_PI_2 ) { offs = 0; } else { offs = (height*ny)*(-cos(gamma)); } return 20.0 + offs + x + (y*cos(gamma)); } static double model_oblique_y(double x, double y, double gamma) { return 20.0 + y * sin(gamma); } static void model_display_draw_atoms(cairo_t *dctx, AtomicModel *model, int width, int height, double gamma, int nx, int ny, double h, int names, int heights) { cairo_surface_t *surface; size_t i; cairo_font_extents_t ext; surface = cairo_get_target(dctx); for ( i=0; in_atoms; i++ ) { AtomicModel *equivalents; size_t j; double x, y; if ( !model->atoms[i].active ) continue; equivalents = symmetry_generate_equivalent_atoms(model, i, MODEL_TARGET_DISPLAY); for ( j=0; jn_atoms; j++ ) { double R; int xp, yp; x = width*(double)equivalents->atoms[j].x; y = height*(double)equivalents->atoms[j].y; R = sqrt(elements[equivalents->atoms[j].ref].z); for ( xp=0; xpatoms[i].occ < 1.0 ) { cairo_set_source_rgb(dctx, 0.4, 0.4, 0.4); } else if ( model->atoms[i].occ > 1.0 ) { cairo_set_source_rgb(dctx, 0.4, 0, 0); } else { cairo_set_source_rgb(dctx, 0, 0, 0); } cairo_arc(dctx, model_oblique_x(x+(width*xp), y+(height*yp), height, gamma, ny), h-model_oblique_y(x+(width*xp), y+(height*yp), gamma), R, 0, 2*M_PI); cairo_fill(dctx); } } } model_free(equivalents); cairo_set_source_rgb(dctx, 0, 0, 1); cairo_select_font_face(dctx, "Sans", CAIRO_FONT_SLANT_ITALIC, CAIRO_FONT_WEIGHT_NORMAL); cairo_font_extents(dctx, &ext); /* Only the unique atoms are labelled */ x = 5 + width*(double)model->atoms[i].x + sqrt(elements[model->atoms[i].ref].z); y = height*(double)model->atoms[i].y; cairo_move_to(dctx, model_oblique_x(x,y,height,gamma, ny), h-model_oblique_y(x,y,gamma)); if ( names ) { cairo_show_text(dctx, elements[model->atoms[i].ref].element_name); y -= ext.height; } x = 5 + width*(double)model->atoms[i].x + sqrt(elements[model->atoms[i].ref].z); if ( heights ) { char tmp[32]; cairo_move_to(dctx, model_oblique_x(x,y,height,gamma, ny), h-model_oblique_y(x,y,gamma)); cairo_show_text(dctx, "z="); snprintf(tmp, 31, "%.3f", model->atoms[i].z); cairo_show_text(dctx, tmp); y -= ext.height; } if ( model->atoms[i].occ != 1.0 ) { char tmp[32]; cairo_move_to(dctx, model_oblique_x(x,y,height,gamma, ny), h-model_oblique_y(x,y,gamma)); cairo_show_text(dctx, "occ: "); snprintf(tmp, 31, "%.2f", model->atoms[i].occ); cairo_show_text(dctx, tmp); y -= ext.height; } } } static void model_display_draw_diad(cairo_t *dctx, double x, double y) { cairo_matrix_t matrix; cairo_get_matrix(dctx, &matrix); cairo_new_path(dctx); cairo_set_source_rgb(dctx, 1, 0, 0); cairo_translate(dctx, x, y); cairo_scale(dctx, 1.0, 2.0); cairo_arc(dctx, 0.0, 0.0, 3, 0, 2*M_PI); cairo_fill(dctx); cairo_set_matrix(dctx, &matrix); } static void model_display_draw_glide(cairo_t *dctx, double x1, double y1, double x2, double y2, int height, double gamma, int ny, double h) { double dash; cairo_new_path(dctx); cairo_set_source_rgb(dctx, 1, 0, 0); cairo_set_line_width(dctx, 1.0); dash = 3.0; cairo_set_dash(dctx, &dash, 1, 0); cairo_move_to(dctx, model_oblique_x(x1, y1, height, gamma, ny), h-model_oblique_y(x1, y1, gamma)); cairo_line_to(dctx, model_oblique_x(x2, y2, height, gamma, ny), h-model_oblique_y(x2, y2, gamma)); cairo_stroke(dctx); dash = 0.0; cairo_set_dash(dctx, &dash, 0, 0); } static void model_display_draw_mirror(cairo_t *dctx, double x1, double y1, double x2, double y2, int height, double gamma, int ny, double h) { cairo_new_path(dctx); cairo_set_source_rgb(dctx, 1, 0, 0); cairo_set_line_width(dctx, 1.0); cairo_move_to(dctx, model_oblique_x(x1, y1, height, gamma, ny), h-model_oblique_y(x1, y1, gamma)); cairo_line_to(dctx, model_oblique_x(x2, y2, height, gamma, ny), h-model_oblique_y(x2, y2, gamma)); cairo_stroke(dctx); } static void model_display_draw_symmetry(cairo_t *dctx, Symmetry sym, int width, int height, double gamma, int nx, int ny, double h) { cairo_surface_t *surface; surface = cairo_get_target(dctx); if ( sym & SYMMETRY_CENTRE ) { int x, y; for ( x=0; xsym, width, height, gamma, nx, ny, h); return dctx; } static void model_display_free_data(guchar *image_data, cairo_t *dctx) { cairo_surface_finish(cairo_get_target(dctx)); cairo_destroy(dctx); } #endif GdkPixbuf *model_display_render_pixbuf(AtomicModel *model, int width, int height, double gamma, int names, int heights, int nx, int ny) { #if HAVE_CAIRO cairo_surface_t *surface; cairo_t *dctx; GdkPixbuf *pixbuf; unsigned char *data; surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, model_display_surface_width(nx*width, ny*height, gamma), model_display_surface_height(nx*width, ny*height, gamma)); if ( cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS ) { fprintf(stderr, "Couldn't create Cairo surface\n"); cairo_surface_destroy(surface); return NULL; } dctx = cairo_create(surface); model_display_do_cairo(dctx, model, width, height, gamma, nx, ny, cairo_image_surface_get_height(surface), names, heights); cairo_surface_flush(surface); data = cairo_image_surface_get_data(surface); model_display_swizzle_data(data, cairo_image_surface_get_width(surface) * cairo_image_surface_get_height(surface)); pixbuf = gdk_pixbuf_new_from_data(data, GDK_COLORSPACE_RGB, TRUE, 8, cairo_image_surface_get_width(surface), cairo_image_surface_get_height(surface), cairo_image_surface_get_stride(surface), (GdkPixbufDestroyNotify)model_display_free_data, dctx); return pixbuf; #else return NULL; #endif } int model_display_render_pdf(AtomicModel *model, int width, int height, double gamma, const char *filename, int names, int heights, int nx, int ny) { #if HAVE_CAIRO cairo_surface_t *surface; cairo_t *dctx; surface = cairo_pdf_surface_create(filename, model_display_surface_width(nx*width, ny*height, gamma), model_display_surface_height(nx*width, ny*height, gamma)); if ( cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS ) { fprintf(stderr, "Couldn't create Cairo surface\n"); cairo_surface_destroy(surface); return -1; } dctx = cairo_create(surface); model_display_do_cairo(dctx, model, width, height, gamma, nx, ny, model_display_surface_height(nx*width, ny*height, gamma), names, heights); cairo_surface_finish(surface); cairo_destroy(dctx); #endif return 0; }