aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas White <taw@physics.org>2020-02-28 17:18:07 +0100
committerThomas White <taw@physics.org>2020-07-29 18:42:24 +0200
commitb125f044e10d4834b460abda857a93388788bc8e (patch)
tree88dfdd311df5554ad8b4345ff4fcb78afdb4130e
parent2524e53def770933bc684b3e3762a02603273496 (diff)
Panel drawing
-rw-r--r--src/crystfelimageview.c252
-rw-r--r--src/crystfelimageview.h17
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