diff options
author | Thomas White <taw@physics.org> | 2020-08-01 15:13:49 +0200 |
---|---|---|
committer | Thomas White <taw@physics.org> | 2020-08-01 15:19:26 +0200 |
commit | 189da15810deabd739d7c11c6e95fea55739fe60 (patch) | |
tree | e86e43fcbbf8278b792a74daf684cde3bd6e2bbf /src/model-display.c |
Initial import from archive
Diffstat (limited to 'src/model-display.c')
-rw-r--r-- | src/model-display.c | 411 |
1 files changed, 411 insertions, 0 deletions
diff --git a/src/model-display.c b/src/model-display.c new file mode 100644 index 0000000..4eeb83a --- /dev/null +++ b/src/model-display.c @@ -0,0 +1,411 @@ +/* + * model-display.c + * + * Display atomic models + * + * (c) 2006-2007 Thomas White <taw27@cam.ac.uk> + * + * synth2d - Two-Dimensional Crystallographic Fourier Synthesis + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <gtk/gtk.h> +#include <math.h> +#include <inttypes.h> + +#if HAVE_CAIRO +#include <cairo.h> +#include <cairo-pdf.h> +#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; i<model->n_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; j<equivalents->n_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; xp<nx; xp++ ) { + for ( yp=0; yp<ny; yp++ ) { + cairo_new_path(dctx); + + if ( model->atoms[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; x<nx; x++ ) { + for ( y=0; y<ny; y++ ) { + model_display_draw_diad(dctx, model_oblique_x(0.0, 0.0, height, gamma, ny), + h-model_oblique_y(0.0, 0.0, gamma)); + model_display_draw_diad(dctx, model_oblique_x((x*width)+width/2, 0.0, height, gamma, ny), + h-model_oblique_y((x*width)+width/2, 0.0, gamma)); + model_display_draw_diad(dctx, model_oblique_x((x*width)+width, 0.0, height, gamma, ny), + h-model_oblique_y((x*width)+width, 0.0, gamma)); + model_display_draw_diad(dctx, model_oblique_x(0.0, (y*height)+height/2, height, gamma, ny), + h-model_oblique_y(0.0, (y*height)+height/2, gamma)); + model_display_draw_diad(dctx, model_oblique_x((x*width)+width/2, (y*height)+height/2, height, gamma, ny), + h-model_oblique_y((x*width)+width/2, (y*height)+height/2, gamma)); + model_display_draw_diad(dctx, model_oblique_x((x*width)+width, (y*height)+height/2, height, gamma, ny), + h-model_oblique_y((x*width)+width, (y*height)+height/2, gamma)); + model_display_draw_diad(dctx, model_oblique_x(0.0, (y+1)*height, height, gamma, ny), + h-model_oblique_y(0.0, (y+1)*height, gamma)); + model_display_draw_diad(dctx, model_oblique_x((x*width)+width/2, (y*height)+height, height, gamma, ny), + h-model_oblique_y((x*width)+width/2, (y*height)+height, gamma)); + model_display_draw_diad(dctx, model_oblique_x((x*width)+width, (y*height)+height, height, gamma, ny), + h-model_oblique_y((x*width)+width, (y*height)+height, gamma)); + } + } + } + + if ( sym & SYMMETRY_GLIDE_VERTICAL_QUARTER ) { + int x; + for ( x=0; x<nx; x++ ) { + model_display_draw_glide(dctx, (x*width)+width/4, 0.0, (x*width)+width/4, height*ny, height, gamma, ny, h); + model_display_draw_glide(dctx, (x*width)+3*width/4, 0.0, (x*width)+3*width/4, height*ny, height, gamma, ny, h); + } + } + + if ( sym & SYMMETRY_GLIDE_HORIZONTAL_QUARTER ) { + int y; + for ( y=0; y<ny; y++ ) { + model_display_draw_glide(dctx, 0.0, (height*y)+height/4, nx*width, (height*y)+height/4, height, gamma, ny, h); + model_display_draw_glide(dctx, 0.0, (height*y)+3*height/4, nx*width, (height*y)+3*height/4, height, gamma, ny, h); + } + } + + if ( sym & SYMMETRY_GLIDE_HORIZONTAL ) { + int y; + model_display_draw_glide(dctx, 0.0, 0.0, nx*width, 0.0, height, gamma, ny, h); + for ( y=0; y<ny; y++ ) { + model_display_draw_glide(dctx, 0.0, (height*y)+height/2, nx*width, (height*y)+height/2, height, gamma, ny, h); + model_display_draw_glide(dctx, 0.0, (height*y)+height, nx*width, (height*y)+height, height, gamma, ny, h); + } + } + + if ( sym & SYMMETRY_GLIDE_VERTICAL ) { + int x; + model_display_draw_glide(dctx, 0.0, 0.0, 0.0, height*ny, height, gamma, ny, h); + for ( x=0; x<nx; x++ ) { + model_display_draw_glide(dctx, (x*width)+width/2, 0.0, (x*width)+width/2, ny*height, height, gamma, ny, h); + model_display_draw_glide(dctx, (x*width)+width, 0.0, (x*width)+width, ny*height, height, gamma, ny, h); + } + } + + if ( sym & SYMMETRY_MIRROR_HORIZONTAL ) { + int y; + model_display_draw_mirror(dctx, 0.0, 0.0, nx*width, 0.0, height, gamma, ny, h); + for ( y=0; y<ny; y++ ) { + model_display_draw_mirror(dctx, 0.0, (height*y)+height/2, nx*width, (height*y)+height/2, height, gamma, ny, h); + model_display_draw_mirror(dctx, 0.0, (height*y)+height, nx*width, (height*y)+height, height, gamma, ny, h); + } + } + + if ( sym & SYMMETRY_MIRROR_VERTICAL ) { + int x; + model_display_draw_mirror(dctx, 0.0, 0.0, 0.0, height*ny, height, gamma, ny, h); + for ( x=0; x<nx; x++ ) { + model_display_draw_mirror(dctx, (x*width)+width/2, 0.0, (x*width)+width/2, ny*height, height, gamma, ny, h); + model_display_draw_mirror(dctx, (x*width)+width, 0.0, (x*width)+width, ny*height, height, gamma, ny, h); + } + } + + if ( sym & SYMMETRY_MIRROR_VERTICAL_QUARTER ) { + int x; + for ( x=0; x<nx; x++ ) { + model_display_draw_mirror(dctx, (width*x)+width/4, 0.0, (width*x)+width/4, ny*height, height, gamma, ny, h); + model_display_draw_mirror(dctx, (width*x)+3*width/4, 0.0, (width*x)+3*width/4, ny*height, height, gamma, ny, h); + } + } + + if ( sym & SYMMETRY_MIRROR_HORIZONTAL_QUARTER ) { + int y; + for ( y=0; y<ny; y++ ) { + model_display_draw_mirror(dctx, 0.0, (height*y)+height/4, nx*width, (height*y)+height/4, height, gamma, ny, h); + model_display_draw_mirror(dctx, 0, (height*y)+3*height/4, nx*width, (height*y)+3*height/4, height, gamma, ny, h); + } + } + +} + +static void model_display_swizzle_data(unsigned char *data, size_t n) { + + size_t i; + + for ( i=0; i<4*n; i+=4 ) { + unsigned char a, r, g, b; + r = data[i]; g = data[i+1]; b = data[i+2]; a = data[i+3]; + data[i] = b; data[i+1] = g; data[i+2] = r; data[i+3] = a; + } + +} + +static double model_display_surface_width(int width_o, int height_o, double gamma) { + if ( gamma <= M_PI_2 ) { + return 40+width_o+height_o*cos(gamma); + } else { + return 40+width_o-height_o*cos(gamma); + } +} + +static double model_display_surface_height(int width_o, int height_o, double gamma) { + return 40+height_o*sin(gamma); +} + +static cairo_t *model_display_do_cairo(cairo_t *dctx, AtomicModel *model, int width, int height, double gamma, int nx, int ny, double h, int names, int heights) { + + int x, y; + + cairo_rectangle(dctx, 0.0, 0.0, model_display_surface_width(nx*width, ny*height, gamma), + model_display_surface_height(nx*width, ny*height, gamma)); + cairo_set_source_rgb(dctx, 1.0, 1.0, 1.0); + cairo_fill(dctx); + + cairo_set_line_width(dctx, 0.5); + + for ( x=0; x<nx; x++ ) { + for ( y=0; y<ny; y++ ) { + cairo_move_to(dctx, model_oblique_x(width*x, height*y, height, gamma, ny), + h-model_oblique_y(width*x, height*y, gamma)); + cairo_line_to(dctx, model_oblique_x(width*(x+1), height*y, height, gamma, ny), + h-model_oblique_y(width*(x+1), height*y, gamma)); + cairo_line_to(dctx, model_oblique_x(width*(x+1), height*(y+1), height, gamma, ny), + h-model_oblique_y(width*(x+1), height*(y+1), gamma)); + cairo_line_to(dctx, model_oblique_x(width*x, height*(y+1), height, gamma, ny), + h-model_oblique_y(width*x, height*(y+1), gamma)); + cairo_line_to(dctx, model_oblique_x(width*x, height*y, height, gamma, ny), + h-model_oblique_y(width*x, height*y, gamma)); + } + } + cairo_set_source_rgb(dctx, 0.8, 0.8, 0.8); + cairo_stroke(dctx); + + model_display_draw_atoms(dctx, model, width, height, gamma, nx, ny, h, names, heights); + model_display_draw_symmetry(dctx, model->sym, 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; + +} + |