diff options
author | Thomas White <taw@physics.org> | 2020-02-28 17:18:07 +0100 |
---|---|---|
committer | Thomas White <taw@physics.org> | 2020-07-29 18:42:24 +0200 |
commit | b125f044e10d4834b460abda857a93388788bc8e (patch) | |
tree | 88dfdd311df5554ad8b4345ff4fcb78afdb4130e | |
parent | 2524e53def770933bc684b3e3762a02603273496 (diff) |
Panel drawing
-rw-r--r-- | src/crystfelimageview.c | 252 | ||||
-rw-r--r-- | src/crystfelimageview.h | 17 |
2 files changed, 225 insertions, 44 deletions
diff --git a/src/crystfelimageview.c b/src/crystfelimageview.c index d675e7bb..9504a942 100644 --- a/src/crystfelimageview.c +++ b/src/crystfelimageview.c @@ -38,6 +38,9 @@ #include <glib-object.h> #include <utils.h> +#include <detgeom.h> +#include <render.h> +#include <colscale.h> #include "crystfelimageview.h" @@ -63,6 +66,15 @@ G_DEFINE_TYPE_WITH_CODE(CrystFELImageView, crystfel_image_view, scroll_interface_init)) +static void redraw(CrystFELImageView *iv) +{ + gint w, h; + w = gtk_widget_get_allocated_width(GTK_WIDGET(iv)); + h = gtk_widget_get_allocated_height(GTK_WIDGET(iv)); + gtk_widget_queue_draw_area(GTK_WIDGET(iv), 0, 0, w, h); +} + + static gint destroy_sig(GtkWidget *window, CrystFELImageView *iv) { return FALSE; @@ -75,68 +87,151 @@ static gint realise_sig(GtkWidget *window, CrystFELImageView *iv) } -static gint button_press_sig(GtkWidget *window, GdkEventButton *event, - CrystFELImageView *iv) +static void configure_scroll_adjustments(CrystFELImageView *iv) { - return FALSE; + if ( iv->hadj != NULL ) { + double pos = gtk_adjustment_get_value(iv->hadj); + double vis_size = iv->visible_width / iv->zoom; + gtk_adjustment_configure(iv->hadj, pos, + -2*iv->detector_w, 2*iv->detector_w, + 0.0001, 0.1, vis_size); + } + if ( iv->vadj != NULL ) { + double pos = gtk_adjustment_get_value(iv->vadj); + double vis_size = iv->visible_height / iv->zoom; + gtk_adjustment_configure(iv->vadj, pos, + -2*iv->detector_h, 2*iv->detector_h, + 0.0001, 0.1, vis_size); + } } -static gint motion_sig(GtkWidget *window, GdkEventMotion *event, +static gint scroll_sig(GtkWidget *window, GdkEventScroll *event, CrystFELImageView *iv) { + if ( event->direction == GDK_SCROLL_UP ) { + double offs; + offs = (iv->visible_width/iv->zoom)*(1.0/1.1 - 1.0); + iv->zoom *= 1.1; + gtk_adjustment_set_value(iv->hadj, + gtk_adjustment_get_value(iv->hadj)-offs); + configure_scroll_adjustments(iv); + redraw(iv); + return TRUE; + } + if ( event->direction == GDK_SCROLL_DOWN ) { + iv->zoom *= 0.9; + configure_scroll_adjustments(iv); + redraw(iv); + return TRUE; + } return FALSE; } - -static gint resize_sig(GtkWidget *window, GdkEventConfigure *event, - CrystFELImageView *iv) +static gint button_press_sig(GtkWidget *window, GdkEventButton *event, + CrystFELImageView *iv) { + iv->drag_start_x = event->x; + iv->drag_start_y = event->y; + iv->drag_start_sp_x = gtk_adjustment_get_value(iv->hadj); + iv->drag_start_sp_y = gtk_adjustment_get_value(iv->vadj); return FALSE; } -static gint draw_sig(GtkWidget *window, cairo_t *cr, CrystFELImageView *iv) +static gint motion_sig(GtkWidget *window, GdkEventMotion *event, + CrystFELImageView *iv) { - cairo_set_source_rgb(cr, 1.0, 0.0, 0.0); - cairo_paint(cr); + double ddx, ddy; + ddx = event->x - iv->drag_start_x; + ddy = event->y - iv->drag_start_y; + gtk_adjustment_set_value(iv->hadj, iv->drag_start_sp_x - ddx/iv->zoom); + gtk_adjustment_set_value(iv->vadj, iv->drag_start_sp_y - ddy/iv->zoom); + redraw(iv); return FALSE; } -static void redraw(CrystFELImageView *iv) +static gint resize_sig(GtkWidget *window, GdkRectangle *rec, + CrystFELImageView *iv) { + iv->visible_width = rec->width; + iv->visible_height = rec->height; + configure_scroll_adjustments(iv); + return FALSE; } -static void horizontal_adjust(GtkAdjustment *adj, CrystFELImageView *iv) +static void draw_panel_rectangle(cairo_t *cr, CrystFELImageView *iv, int i) { - iv->x_scroll_pos = gtk_adjustment_get_value(adj); - redraw(iv); + struct detgeom_panel p = iv->image->detgeom->panels[i]; + cairo_matrix_t m; + cairo_pattern_t *patt; + + /* Move to the right location */ + cairo_translate(cr, p.cnx*p.pixel_pitch, p.cny*p.pixel_pitch); + + /* Twiddle directions according to matrix */ + cairo_matrix_init(&m, rint(p.fsx), rint(p.fsy), rint(p.ssx), rint(p.ssy), + 0.0, 0.0); + cairo_transform(cr, &m); + + gdk_cairo_set_source_pixbuf(cr, iv->pixbufs[i], 0.0, 0.0); + patt = cairo_get_source(cr); + cairo_pattern_set_filter(patt, CAIRO_FILTER_NEAREST); + cairo_matrix_init_identity(&m); + cairo_pattern_set_matrix(patt, &m); + cairo_rectangle(cr, 0.0, 0.0, p.w*p.pixel_pitch, p.h*p.pixel_pitch); } -static void set_horizontal_params(CrystFELImageView *iv) +static gint draw_sig(GtkWidget *window, cairo_t *cr, CrystFELImageView *iv) { - if ( iv->hadj == NULL ) return; - gtk_adjustment_configure(iv->hadj, iv->x_scroll_pos, 0, iv->w, 100, - iv->visible_width, iv->visible_width); -} + cairo_save(cr); + /* Overall background (light grey) */ + cairo_set_source_rgb(cr, 0.7, 0.7, 0.7); + cairo_paint(cr); -static void vertical_adjust(GtkAdjustment *adj, CrystFELImageView *iv) -{ - iv->y_scroll_pos = gtk_adjustment_get_value(adj); - redraw(iv); + cairo_scale(cr, iv->zoom, iv->zoom); + cairo_scale(cr, 1.0, -1.0); + cairo_translate(cr, -gtk_adjustment_get_value(iv->hadj), + gtk_adjustment_get_value(iv->vadj)); + + if ( iv->pixbufs != NULL ) { + int i; + for ( i=0; i<iv->image->detgeom->n_panels; i++ ) { + cairo_save(cr); + draw_panel_rectangle(cr, iv, i); + cairo_fill_preserve(cr); + cairo_set_source_rgb(cr, 0.0, 0.0, 0.0); + cairo_set_line_width(cr, 0.0002); + cairo_stroke(cr); + cairo_restore(cr); + } + } + + cairo_new_path(cr); + cairo_move_to(cr, 0.0, 0.0); + cairo_line_to(cr, 0.1, 0.0); + cairo_set_source_rgb(cr, 1.0, 0.0, 0.0); + cairo_set_line_width(cr, 0.001); + cairo_stroke(cr); + cairo_move_to(cr, 0.0, 0.0); + cairo_line_to(cr, 0.0, 0.1); + cairo_set_source_rgb(cr, 0.0, 1.0, 0.0); + cairo_set_line_width(cr, 0.001); + cairo_stroke(cr); + + cairo_restore(cr); + return FALSE; } -static void set_vertical_params(CrystFELImageView *iv) +static void scroll_adjust_sig(GtkAdjustment *adj, CrystFELImageView *iv) { - if ( iv->vadj == NULL ) return; - gtk_adjustment_configure(iv->vadj, iv->y_scroll_pos, 0, iv->w, 100, - iv->visible_width, iv->visible_width); + redraw(iv); } @@ -157,19 +252,19 @@ static void crystfel_image_view_set_property(GObject *obj, guint id, const GValu case CRYSTFELIMAGEVIEW_VADJ : iv->vadj = g_value_get_object(val); - set_vertical_params(iv); + configure_scroll_adjustments(iv); if ( iv->vadj != NULL ) { g_signal_connect(G_OBJECT(iv->vadj), "value-changed", - G_CALLBACK(vertical_adjust), iv); + G_CALLBACK(scroll_adjust_sig), iv); } break; case CRYSTFELIMAGEVIEW_HADJ : iv->hadj = g_value_get_object(val); - set_horizontal_params(iv); + configure_scroll_adjustments(iv); if ( iv->hadj != NULL ) { g_signal_connect(G_OBJECT(iv->hadj), "value-changed", - G_CALLBACK(horizontal_adjust), iv); + G_CALLBACK(scroll_adjust_sig), iv); } break; @@ -264,24 +359,24 @@ GtkWidget *crystfel_image_view_new() iv = g_object_new(CRYSTFEL_TYPE_IMAGE_VIEW, NULL); - iv->w = 100; - iv->h = 100; - iv->x_scroll_pos = 0; - iv->y_scroll_pos = 0; + /* All values initially meaningless */ + iv->detector_w = NAN; + iv->detector_h = NAN; + iv->zoom = NAN; iv->filename = NULL; iv->event = NULL; - gtk_widget_set_size_request(GTK_WIDGET(iv), iv->w, iv->h); - g_signal_connect(G_OBJECT(iv), "destroy", G_CALLBACK(destroy_sig), iv); g_signal_connect(G_OBJECT(iv), "realize", G_CALLBACK(realise_sig), iv); g_signal_connect(G_OBJECT(iv), "button-press-event", G_CALLBACK(button_press_sig), iv); + g_signal_connect(G_OBJECT(iv), "scroll-event", + G_CALLBACK(scroll_sig), iv); g_signal_connect(G_OBJECT(iv), "motion-notify-event", G_CALLBACK(motion_sig), iv); - g_signal_connect(G_OBJECT(iv), "configure-event", + g_signal_connect(G_OBJECT(iv), "size-allocate", G_CALLBACK(resize_sig), iv); g_signal_connect(G_OBJECT(iv), "draw", G_CALLBACK(draw_sig), iv); @@ -302,13 +397,90 @@ GtkWidget *crystfel_image_view_new() } +static void check_extents(struct detgeom_panel p, double *min_x, double *min_y, + double *max_x, double *max_y, double fs, double ss) +{ + double xs, ys; + + xs = (fs*p.fsx + ss*p.ssx + p.cnx) * p.pixel_pitch; + ys = (fs*p.fsy + ss*p.ssy + p.cny) * p.pixel_pitch; + + if ( xs > *max_x ) *max_x = xs; + if ( ys > *max_y ) *max_y = ys; + if ( xs < *min_x ) *min_x = xs; + if ( ys < *min_y ) *min_y = ys; +} + + +static void detgeom_pixel_extents(struct detgeom *det, + double *min_x, double *min_y, + double *max_x, double *max_y) +{ + int i; + + *min_x = 0.0; + *max_x = 0.0; + *min_y = 0.0; + *max_y = 0.0; + + /* To determine the maximum extents of the detector, put all four + * corners of each panel through the transformations and watch for the + * biggest */ + + for ( i=0; i<det->n_panels; i++ ) { + + check_extents(det->panels[i], min_x, min_y, max_x, max_y, + 0.0, 0.0); + + check_extents(det->panels[i], min_x, min_y, max_x, max_y, + 0.0, det->panels[i].h+1); + + check_extents(det->panels[i], min_x, min_y, max_x, max_y, + det->panels[i].w+1, 0.0); + + check_extents(det->panels[i], min_x, min_y, max_x, max_y, + det->panels[i].w+1, det->panels[i].h+1); + + + } +} + + static int reload_image(CrystFELImageView *iv) { + int i; + int n_pb; + double min_x, min_y, max_x, max_y; + if ( iv->dtempl == NULL ) return 0; if ( iv->filename == NULL ) return 0; - image_free(iv->image); + + /* Free old stuff */ + if ( iv->image != NULL ) { + image_free(iv->image); + if ( iv->image->detgeom != NULL ) { + for ( i=0; iv->image->detgeom->n_panels; iv++ ) { + gdk_pixbuf_unref(iv->pixbufs[i]); + } + } + } + iv->image = image_read(iv->dtempl, iv->filename, iv->event); - printf("loaded %p\n", iv->image); + if ( iv->image == NULL ) return 1; + + iv->pixbufs = render_panels(iv->image, 1, SCALE_COLOUR, 5, &n_pb); + if ( n_pb != iv->image->detgeom->n_panels ) { + ERROR("Wrong number of panels returned!\n"); + return 1; + } + + detgeom_pixel_extents(iv->image->detgeom, &min_x, &min_y, &max_x, &max_y); + STATUS("Extents: %f %f %f %f\n", min_x, min_y, max_x, max_y); + iv->detector_w = max_x - min_x; + iv->detector_h = max_y - min_y; + iv->zoom = 1.0/iv->image->detgeom->panels[0].pixel_pitch; + configure_scroll_adjustments(iv); + return 0; } diff --git a/src/crystfelimageview.h b/src/crystfelimageview.h index 829909df..8d3b23aa 100644 --- a/src/crystfelimageview.h +++ b/src/crystfelimageview.h @@ -33,6 +33,8 @@ #include <config.h> #endif +#include <gdk-pixbuf/gdk-pixbuf.h> + #include <image.h> #include <datatemplate.h> @@ -60,21 +62,28 @@ struct _crystfelimageview /*< private >*/ GtkIMContext *im_context; - int w; /* Surface size in pixels */ - int h; + /* Detector size in metres */ + double detector_w; + double detector_h; /* Redraw/scroll stuff */ GtkScrollablePolicy hpol; GtkScrollablePolicy vpol; GtkAdjustment *hadj; GtkAdjustment *vadj; - double x_scroll_pos; - double y_scroll_pos; + double visible_width; + double visible_height; + double zoom; + double drag_start_x; + double drag_start_y; + double drag_start_sp_x; + double drag_start_sp_y; DataTemplate *dtempl; char *filename; char *event; struct image *image; + GdkPixbuf **pixbufs; }; struct _crystfelimageviewclass |