/* * dpsynth.c * * Draw synthetic diffraction patterns * * (c) 2006-2009 Thomas White * (c) 2007-2008 Alex Eggeman * * synth2d - Two-Dimensional Crystallographic Fourier Synthesis * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #if HAVE_CAIRO #include #endif #include #include "reflist.h" #include "data.h" #include "displaywindow.h" #include "colwheel.h" #include "gsf.h" #include "normalise.h" typedef struct { GtkWidget *image_widget; GdkPixbuf *pixbuf; GtkWidget *window; unsigned int width; unsigned int height; unsigned int colour; } DPSynthWindow; #if HAVE_CAIRO static void dpsynth_swizzle_data(unsigned char *data, size_t width, size_t height) { size_t i, x, y; uint32_t *dataw; for ( i=0; i<4*width*height; 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; } /* Now make it be the right way up */ dataw = (uint32_t *)data; for ( y=0; ywidth, dpsynth->height); 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); /* Black background */ cairo_rectangle(dctx, 0.0, 0.0, dpsynth->width, dpsynth->height); cairo_set_source_rgb(dctx, 0.0, 0.0, 0.0); cairo_fill(dctx); max_u = 0.0; max_v = 0.0; max_intensity = 0.0; max_res = 0.0; /* NB This isn't really "the angle between a* and b*" */ theta = data_gamma()-M_PI_2; as = 1/(data_a() * cos(theta)); bs = 1/(data_b() * cos(theta)); for ( i=0; in_reflections; i++ ) { double u, v, intensity, ph, res; /* Convert to intensity */ intensity = pow(reflections->refs[i].amplitude, 2.0); ph = reflections->refs[i].phase_known; res = resolution(reflections->refs[i].h, reflections->refs[i].k, reflections->refs[i].l, data_a(), data_b(), data_c(), data_gamma()); if ( res > max_res ) max_res = res; if ( intensity != 0 ) { u = (double)reflections->refs[i].h * as * cos(theta); v = (double)reflections->refs[i].h * as * sin(theta) + reflections->refs[i].k * bs; if ( fabs(u) > fabs(max_u) ) max_u = fabs(u); if ( fabs(v) > fabs(max_v) ) max_v = fabs(v); if ( fabs(intensity) > fabs(max_intensity) ) max_intensity = fabs(intensity); } } max_u *= 2.5; max_v *= 2.5; printf("DP: Maximum resolution is %f nm^-1\n", max_res); if ( max_intensity > 0 ) { scale = ((double)dpsynth->width-50.0) / (2*max_u); if ( ((double)dpsynth->height-50.0) / (2*max_v) < scale ) scale = ((double)dpsynth->height-50.0) / (2*max_v); sep_u = as * scale * cos(theta); sep_v = bs * scale; max_r = ((sep_u < sep_v)?sep_u:sep_v) / 2; for ( i=0; in_reflections; i++ ) { double u, v, intensity, ph, val; intensity = pow(reflections->refs[i].amplitude, 2.0); ph = reflections->refs[i].phase_known; val = 2.0*intensity/max_intensity; if ( intensity != 0 ) { u = (double)reflections->refs[i].h * as * cos(theta); v = (double)reflections->refs[i].h * as * sin(theta) + reflections->refs[i].k * bs; cairo_arc(dctx, ((double)dpsynth->width/2) +u*scale*2, ((double)dpsynth->height/2) +v*scale*2, max_r, 0, 2*M_PI); if ( dpsynth->colour == 0 ) { cairo_set_source_rgb(dctx, val, val, val); } else { cairo_set_source_rgb(dctx, colwheel_red(val, ph), colwheel_green(val, ph), colwheel_blue(val, ph) ); } cairo_fill(dctx); } } } else { max_r = 4.0; } /* Centre marker */ cairo_arc(dctx, (double)dpsynth->width/2, (double)dpsynth->height/2, max_r, 0, 2*M_PI); cairo_set_source_rgb(dctx, 1.0, 0.0, 0.0); cairo_fill(dctx); cairo_surface_flush(surface); data = cairo_image_surface_get_data(surface); dpsynth_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)dpsynth_free_data, dctx); return pixbuf; #else /* Cannot do this without Cairo */ return NULL; #endif } static void dpsynth_close(GtkWidget *widget, DPSynthWindow *dpsynth) { free(dpsynth); } void dpsynth_update(DPSynthWindow *dpsynth, ReflectionList *reflections) { if ( dpsynth->pixbuf ) gdk_pixbuf_unref(dpsynth->pixbuf); dpsynth->pixbuf = dpsynth_render_pixbuf(dpsynth, reflections); if ( !dpsynth->pixbuf ) return; if ( dpsynth->image_widget ) { g_object_set(G_OBJECT(dpsynth->image_widget), "pixbuf", dpsynth->pixbuf, NULL); } else { dpsynth->image_widget = gtk_image_new_from_pixbuf( dpsynth->pixbuf); gtk_container_add(GTK_CONTAINER(dpsynth->window), GTK_WIDGET(dpsynth->image_widget)); gtk_widget_show(dpsynth->image_widget); } } DPSynthWindow *dpsynth_open(ReflectionList *reflections, const char *title, int colour) { DPSynthWindow *dpsynth; dpsynth = malloc(sizeof(DPSynthWindow)); dpsynth->width = 512; dpsynth->height = 512; dpsynth->pixbuf = NULL; dpsynth->image_widget = NULL; dpsynth->colour = colour; dpsynth->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(dpsynth->window), title); g_signal_connect(GTK_OBJECT(dpsynth->window), "destroy", G_CALLBACK(dpsynth_close), dpsynth); gtk_widget_show_all(dpsynth->window); dpsynth_update(dpsynth, reflections); return dpsynth; } /* "Glue" - to be removed eventually... */ DPSynthWindow *dpsynth_main_dpsynth = NULL; static void dpsynth_main_close(GtkWidget *widget, DPSynthWindow *dpsynth) { dpsynth_main_dpsynth = NULL; } void dpsynth_main_update(ReflectionList *reflections) { if ( !dpsynth_main_dpsynth ) return; dpsynth_update(dpsynth_main_dpsynth, reflections); } void dpsynth_main_open(ReflectionList *reflections) { if ( dpsynth_main_dpsynth ) return; dpsynth_main_dpsynth = dpsynth_open(reflections, "Diffraction Pattern", 0); g_signal_connect(GTK_OBJECT(dpsynth_main_dpsynth->window), "destroy", G_CALLBACK(dpsynth_main_close), dpsynth_main_dpsynth); } DPSynthWindow *dpsynth_sim_dpsynth = NULL; static void dpsynth_simdp_close(GtkWidget *widget, DPSynthWindow *dpsynth) { dpsynth_sim_dpsynth = NULL; } void dpsynth_simdp_update(ReflectionList *reflections) { if ( !dpsynth_sim_dpsynth ) return; dpsynth_update(dpsynth_sim_dpsynth, reflections); } void dpsynth_simdp_open(ReflectionList *reflections) { if ( dpsynth_sim_dpsynth ) return; dpsynth_sim_dpsynth = dpsynth_open(reflections, "Simulated Diffraction Pattern", 0); g_signal_connect(GTK_OBJECT(dpsynth_sim_dpsynth->window), "destroy", G_CALLBACK(dpsynth_simdp_close), dpsynth_sim_dpsynth); }