[med-svn] [Git][med-team/bart-view][upstream] 30 commits: movie callback

Martin Uecker gitlab at salsa.debian.org
Sat Feb 17 18:36:23 UTC 2018


Martin Uecker pushed to branch upstream at Debian Med / bart-view


Commits:
92637c7e by Martin Uecker at 2016-06-09T21:19:16+02:00
movie callback

- - - - -
5a6b3607 by Martin Uecker at 2016-06-13T15:44:31+02:00
add refresh and setpos API

- - - - -
1dc33d7d by Martin Uecker at 2016-06-13T15:53:04+02:00
fix sync for position

- - - - -
71b9a4bd by Martin Uecker at 2016-06-13T15:53:04+02:00
make fit a toogle button

- - - - -
09b8c053 by Martin Uecker at 2016-06-13T15:53:04+02:00
set a default size

- - - - -
0f2baefa by Sebastian Rosenzweig at 2016-07-27T09:56:26+02:00
Save Dialog

- - - - -
f48f5fba by Sebastian Rosenzweig at 2016-07-27T10:05:09+02:00
Bugfix parent window

- - - - -
be203b04 by Sebastian Rosenzweig at 2016-07-27T14:09:27+02:00
Static function

- - - - -
1bb59749 by Sebastian Rosenzweig at 2016-07-27T14:39:09+02:00
renamed dim specifier

- - - - -
9d7ed9ad by Christian Holme at 2017-02-06T11:54:58+01:00
better default name and better string functions

Improved the default filename in the save dialog to be the basename of
the currently open path; and changed the default dimension string.

Replaced unsafe string functions by their safe alternatives.

- - - - -
3ad1af21 by Christian Holme at 2017-02-16T15:31:14+01:00
(re-)add movie export

Movie export now has it's own button, which lets the user select a
folder to which the movie will be exported.

- - - - -
3c950b50 by Christian Holme at 2017-02-16T15:56:37+01:00
fixup: add missing free, whitespace and comments

- - - - -
5515b648 by Christian Holme at 2017-02-24T13:49:57+01:00
safer string handling in save_callback


This should prevent writing past the name buffer.

- - - - -
5797bd4e by Christian Holme at 2017-06-30T13:13:00+02:00
added two new colormaps

Added two new colormaps, which have the beautiful names
"viridis" and "MYGBM".

viridis is the perceptually uniform, new default colormap of the matplotlib project.

MYGBM is the "cyclic_mygbm" colormap from the colorcet project
(https://github.com/bokeh/colorcet/),
It tries to give more accurate phase information by using 4
different colors for values at 0, pi/2, -pi/2 and +/-pi.

- - - - -
157dccb9 by Christian Holme at 2017-06-30T13:13:00+02:00
add UNUSED() macros to identify unused paramters

- - - - -
6d9991ee by Christian Holme at 2017-06-30T13:13:00+02:00
add cfl2png tool

Added a command-line tool 'cfl2png' which allows exporting images from
the command line. Currently still on the drawing code in view.c, so it
is not independent of GTK yet. Long term plan is to move this tool
(together with the code it needs) into BART.

- - - - -
401c369a by Christian Holme at 2017-06-30T16:14:08+02:00
cfl2png: fewer dependencies

We move some of the code around so that cfl2png no longer depends on
GTK+, since it really is an unneeded dependency.

Ugly part: draw now contains some functions that should rather belong in
some kind of general "utils" file or something similar, since they are
not related to drawing.

- - - - -
bfeed944 by Christian Holme at 2017-07-02T16:11:01+02:00
cfl2png: remove cairo dependency

- - - - -
fc55b798 by Martin Uecker at 2017-07-17T15:16:55+02:00
Merge pull request #4 from hcmh/sync_internal_version

Sync internal version
- - - - -
f504762e by Jon Tamir at 2017-07-20T16:56:13-07:00
bart version requirement

- - - - -
3070dff1 by Christian Holme at 2017-09-12T11:26:19+02:00
fix segfault on toggle_sync in newer GTK

With newer versions of GTK+ (at least with 3.22), a segfault is
triggered on changing sync state. The reason for that is that the signal
is called with 2 arguments, but the third argument is used as
struct view_s. According to
	 https://developer.gnome.org/gtk3/stable/GtkToggleButton.html#GtkToggleButton-toggled
the handler is called as
void
user_function (GtkToggleButton *togglebutton,
               gpointer         user_data)
so the first arguemnt is the button (which is unused in view) and the
second is the data we want.

This works on GTK+3 v3.22 and v3.14 at least. I do not know why it
worked before v3.22.

- - - - -
92117e2a by Martin Uecker at 2017-09-12T13:46:49+02:00
Merge pull request #5 from hcmh/toggle_sync_segfault

fix segfault on toggle_sync in newer GTK
- - - - -
f12900a5 by Christian Holme at 2017-12-05T15:56:07+01:00
whitespace fix

- - - - -
e6f77557 by Christian Holme at 2017-12-05T15:56:07+01:00
draw.c: correct interpolation

This commit fixes interpolation in view:
The idea is as follows: uninterpolated, each pixel represents a value
sitting in its center. This is exactly how GIMP implements linear
interpolation.

- - - - -
7d7ea08a by Christian Holme at 2017-12-05T15:56:07+01:00
add nearest-neighbor interpolation

- - - - -
ff5aabb7 by Martin Uecker at 2018-01-22T10:37:49+01:00
introduce pos2screen/screen2pos

- - - - -
9e9edccd by Martin Uecker at 2018-01-22T10:40:31+01:00
draw lines and grid

- - - - -
a4d8abde by Martin Uecker at 2018-01-22T10:43:01+01:00
warning and style

- - - - -
800b1d98 by Martin Uecker at 2018-01-22T10:49:38+01:00
color lines + crosshair

- - - - -
187c48cb by Martin Uecker at 2018-01-29T21:46:10+01:00
add markdown README and screenshot

- - - - -


12 changed files:

- .gitignore
- Makefile
- README
- + README.md
- + src/cfl2png.c
- + src/colormaps.inc
- src/draw.c
- src/draw.h
- src/view.c
- src/view.h
- src/viewer.ui
- + viewer.png


Changes:

=====================================
.gitignore
=====================================
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
 view
+cfl2png
 viewer.inc
 tags
 *.swp


=====================================
Makefile
=====================================
--- a/Makefile
+++ b/Makefile
@@ -41,7 +41,7 @@ endif
 -include Makefile.local
 
 
-all: view
+all: view cfl2png
 
 src/viewer.inc: src/viewer.ui
 	@echo "STRINGIFY(`cat src/viewer.ui`)" > src/viewer.inc
@@ -49,10 +49,12 @@ src/viewer.inc: src/viewer.ui
 view:	src/main.c src/view.[ch] src/draw.[ch] src/viewer.inc
 	$(CC) $(CFLAGS) $(EXPDYN) -o view -I$(TOOLBOX_INC) `pkg-config --cflags gtk+-3.0` src/main.c src/view.c src/draw.c `pkg-config --libs gtk+-3.0` $(TOOLBOX_LIB)/libmisc.a $(TOOLBOX_LIB)/libnum.a -lm -lpng
 
+cfl2png:	src/cfl2png.c src/view.[ch] src/draw.[ch] src/viewer.inc
+	$(CC) $(CFLAGS) $(EXPDYN) -o cfl2png -I$(TOOLBOX_INC) src/cfl2png.c src/draw.c $(TOOLBOX_LIB)/libmisc.a $(TOOLBOX_LIB)/libnum.a -lm -lpng
 
 install:
 	install view $(DESTDIR)/usr/lib/bart/commands/
 
 
 clean:
-	rm -f view viewer.inc
+	rm -f view cfl2png viewer.inc


=====================================
README
=====================================
--- a/README
+++ b/README
@@ -6,7 +6,7 @@ the Berkeley Advanced Reconstruction Toolbox (BART).
 
 https://mrirecon.github.io/bart/
 
-
+Requires BART up to commit e4df99aa75e0344931ba2e76d9ae052b02da498f
 
 Mac OS X:
 


=====================================
README.md
=====================================
--- /dev/null
+++ b/README.md
@@ -0,0 +1,30 @@
+
+
+Small image viewer for multi-dimensional files. Compiles
+on Linux and Mac OS X. It needs some libraries from
+the Berkeley Advanced Reconstruction Toolbox (BART).
+
+https://mrirecon.github.io/bart/
+
+![viewer](viewer.png)
+
+
+Installation:
+
+Requires BART up to commit e4df99aa75e0344931ba2e76d9ae052b02da498f
+
+Mac OS X:
+
+sudo port install pkgconfig
+sudo port install gtk3
+sudo port install adwaita-icon-theme
+
+Linux:
+sudo apt-get install libgtk-3-dev
+
+
+
+Compile with make after setting the TOOLBOX_PATH
+environment variable.
+
+


=====================================
src/cfl2png.c
=====================================
--- /dev/null
+++ b/src/cfl2png.c
@@ -0,0 +1,230 @@
+
+#include <stdio.h>
+#include <assert.h>
+#include <complex.h>
+#include <string.h>
+#include <strings.h>
+
+#undef MAX
+#undef MIN
+
+#include "num/multind.h"
+#include "num/init.h"
+
+#include "misc/misc.h"
+#include "misc/debug.h"
+#include "misc/mmio.h"
+#include "misc/opts.h"
+#include "misc/png.h"
+
+#include "draw.h"
+#include "view.h"
+
+#ifndef CFL_SIZE
+#define CFL_SIZE sizeof(complex float)
+#endif
+
+void export_images(const char* output_prefix, int xdim, int ydim, float windowing[2], float zoom, enum mode_t mode, enum flip_t flip, enum interp_t interpolation, const long dims[DIMS], const complex float* idata);
+
+static const char usage_str[] = "<input> <output_prefix>";
+static const char help_str[] = "Export images to png.";
+
+
+
+int main(int argc, char* argv[])
+{
+	int xdim = 0;
+	int ydim = 0;
+	float windowing[2] = {0.f, 1.f};
+	enum mode_t mode = MAGN;
+	float zoom =2.f;
+	enum flip_t flip = OO;
+	enum interp_t interpolation = NLINEAR;
+
+	struct opt_s modeopt[] = {
+		OPT_SELECT('M', enum mode_t, &mode, MAGN, 		"magnitude gray (default) "),
+		OPT_SELECT('V', enum mode_t, &mode, MAGN_VIRIDS, 	"magnitude viridis"),
+		OPT_SELECT('C', enum mode_t, &mode, CMPL,	 	"complex"),
+		OPT_SELECT('G', enum mode_t, &mode, CMPL_MYGBM,	 	"complex MYGBM"),
+		OPT_SELECT('P', enum mode_t, &mode, PHSE, 		"phase"),
+		OPT_SELECT('Y', enum mode_t, &mode, PHSE_MYGBM, 	"phase MYGBM"),
+		OPT_SELECT('R', enum mode_t, &mode, REAL, 		"real"),
+		OPT_SELECT('F', enum mode_t, &mode, FLOW, 		"flow"),
+	};
+
+	struct opt_s flipopt[] = {
+		OPT_SELECT('O', enum flip_t, &flip, OO, 		"flip OO"),
+		OPT_SELECT('X', enum flip_t, &flip, XO, 		"flip XO"),
+		OPT_SELECT('Y', enum flip_t, &flip, OY, 		"flip OY"),
+		OPT_SELECT('Z', enum flip_t, &flip, XY, 		"flip XY"),
+	};
+
+	struct opt_s interpopt[] = {
+		OPT_SELECT('L', enum interp_t, &interpolation, NLINEAR, 		"n-linear interpolation"),
+		OPT_SELECT('N', enum interp_t, &interpolation, NEAREST, 		"nearest neighbor interpolation"),
+	};
+
+	const struct opt_s opts[] = {
+		OPT_INT('x', &xdim, "xdim", "output xdim (default: 0) "),
+		OPT_INT('y', &ydim, "ydim", "output ydim (default: 0). If both are zero, first two non-singleton dims are used."),
+		OPT_FLOAT('l', &windowing[0], "l", "lower windowing value"),
+		OPT_FLOAT('u', &windowing[1], "u", "upper windowing value"),
+		OPT_FLOAT('z', &zoom, "z", "zoom factor (default: 2) "),
+		OPT_SUBOPT('C', "cmap", "colormap. -Ch for help.", ARRAY_SIZE(modeopt), modeopt),
+		OPT_SUBOPT('F', "flip", "flip. -Fh for help.", ARRAY_SIZE(flipopt), flipopt),
+		OPT_SUBOPT('I', "interp", "interp. -Ih for help.", ARRAY_SIZE(interpopt), interpopt),
+		OPT_INT('d', &debug_level, "level", "Debug level"),
+	};
+
+	cmdline(&argc, argv, 2, 1000, usage_str, help_str, ARRAY_SIZE(opts), opts);
+
+	assert(    (windowing[0] >= 0.f)
+		&& (windowing[1] <= 1.f)
+		&& (windowing[0] < windowing[1]));
+
+	const char* infile = argv[1];
+	const char* output_prefix = argv[2];
+
+	assert((0 <= xdim) && (xdim < DIMS));
+	assert((0 <= ydim) && (ydim < DIMS));
+
+	/*
+	 * If the filename ends in ".hdr", ".cfl" or just "." (from
+	 * tab-completion), just replace the "." with a \0-character.
+	 */
+	char* dot = strrchr(infile, '.');
+
+	if (   (NULL != dot)
+            && (   !strcmp(dot, ".cfl")
+		|| !strcmp(dot, ".hdr")
+		|| !strcmp(dot, ".")))
+		*dot = '\0';
+
+
+	long dims[DIMS];
+	complex float* idata = load_cfl(infile, DIMS, dims);
+
+	char* ext = rindex(output_prefix, '.');
+
+	if (NULL != ext) {
+
+		if (0 != strcmp(ext, ".png"))
+			error("Unknown file extension.");
+		else
+			*ext = '\0';
+	}
+
+	export_images(output_prefix, xdim, ydim, windowing, zoom, mode, flip, interpolation, dims, idata);
+
+
+	unmap_cfl(DIMS, dims, idata);
+
+	return 0;
+}
+
+
+
+/**
+ * Convert flat index to pos
+ *
+ */
+static void unravel_index(unsigned int D, long pos[D], const long dims[D], long index)
+{
+	for (unsigned int d = 0; d < D; ++d) {
+
+		if (1 == dims[d])
+			continue;
+
+		pos[d] = index % dims[d];
+		index /= dims[d];
+	}
+}
+
+
+void export_images(const char* output_prefix, int xdim, int ydim, float windowing[2], float zoom, enum mode_t mode, enum flip_t flip, enum interp_t interpolation, const long dims[DIMS], const complex float* idata)
+{
+	if (xdim == ydim) {
+
+		long sq_dims[2] = { 0 };
+
+		int l = 0;
+
+		for (int i = 0; (i < DIMS) && (l < 2); i++)
+			if (1 != dims[i])
+				sq_dims[l++] = i;
+
+		assert(2 == l);
+		xdim = sq_dims[0];
+		ydim = sq_dims[1];
+	}
+
+	double max = 0.;
+	for (long j = 0; j < md_calc_size(DIMS, dims); j++)
+		if (max < cabsf(idata[j]))
+			max = cabsf(idata[j]);
+
+	if (0. == max)
+		max = 1.;
+
+	int rgbw = dims[xdim] * zoom;
+	int rgbh = dims[ydim] * zoom;
+	int rgbstr = 4 * rgbw;
+	unsigned char* rgb = xmalloc(rgbh * rgbstr);
+
+	complex float* buf = xmalloc(rgbh * rgbw * sizeof(complex float));
+
+	// loop over all dims other than xdim and ydim
+	long loopdims[DIMS];
+	unsigned long loopflags = (MD_BIT(xdim)|MD_BIT(ydim));
+	md_select_dims(DIMS, ~loopflags, loopdims, dims);
+
+	debug_printf(DP_DEBUG3, "flags: %lu\nloopdims: ", loopflags);
+	debug_print_dims(DP_DEBUG3, DIMS, loopdims);
+
+
+
+	long pos[DIMS] = { [0 ... DIMS - 1] = 0  };
+	long strs[DIMS];
+	md_calc_strides(DIMS, strs, dims, sizeof(complex float));
+
+	for (unsigned long d = 0l; d < md_calc_size(DIMS, loopdims); ++d){
+
+		unravel_index(DIMS, pos, loopdims, d);
+
+		debug_printf(DP_DEBUG3, "\ti: %lu\n\t", d);
+		debug_print_dims(DP_DEBUG3, DIMS, pos);
+
+		// Prepare output filename
+		unsigned int bufsize = 255;
+		char name[bufsize];
+		char* cur = name;
+		const char* end = name + bufsize;
+
+		cur += snprintf(cur, end - cur, "%s", output_prefix);
+
+		for (unsigned int i = 0; i < DIMS; i++) {
+
+			if (1 != loopdims[i])
+				cur += snprintf(cur, end - cur, "_%s_%04ld", get_spec(i), pos[i]);
+		}
+
+		cur += snprintf(cur, end - cur, ".png");
+
+		debug_printf(DP_DEBUG2, "\t%s\n", name);
+
+		update_buf(xdim, ydim, DIMS, dims, strs, pos, flip, interpolation, zoom, zoom,
+			   rgbw, rgbh, idata, buf);
+
+		draw(rgbw, rgbh, rgbstr, (unsigned char(*)[rgbw][rgbstr / 4][4])rgb,
+			mode, 1. / max, windowing[0], windowing[1], 0,
+			rgbw, buf);
+
+		if (0 != png_write_bgr32(name, rgbw, rgbh, 0, rgb))
+			error("Error: writing image file.\n");
+	}
+
+// 	free(source);
+	free(buf);
+	free(rgb);
+}
+


=====================================
src/colormaps.inc
=====================================
--- /dev/null
+++ b/src/colormaps.inc
@@ -0,0 +1,545 @@
+// cyclic_mygbm is a phase colormap from the the
+// "colorcet" project (https://github.com/bokeh/colorcet)
+// using a transition from magenta through yellow, green, and blue back to 
+// magenta. More information can be found in:
+// 	Peter Kovesi. Good Colour Maps: How to Design Them.
+// 	arXiv:1509.03700 [cs.GR] 2015
+// cyclic_mygbm by Peter Kovesi (http://www.peterkovesi.com) is licensed under the
+// Creative Commons Attribution 4.0 International Public License (CC-BY)
+// (https://creativecommons.org/licenses/by/4.0/)
+// Direct link to the colormap is 
+// 	https://github.com/bokeh/colorcet/blob/master/assets/CETperceptual_csv_0_1/cyclic_mygbm_30-95_c78_n256_s25.csv
+static const double cyclic_mygbm[256][3] = {
+{0.18062,	0.13244,	0.91856},
+{0.19173,	0.12446,	0.92396},
+{0.20389,	0.11765,	0.92889},
+{0.21681,	0.11214,	0.93335},
+{0.23028,	0.10794,	0.93739},
+{0.24417,	0.10525,	0.94101},
+{0.25828,	0.10403,	0.94425},
+{0.27246,	0.10417,	0.94716},
+{0.28659,	0.10560,	0.94977},
+{0.30059,	0.10807,	0.95212},
+{0.31440,	0.11153,	0.95426},
+{0.32796,	0.11565,	0.95622},
+{0.34126,	0.12031,	0.95803},
+{0.35426,	0.12544,	0.95973},
+{0.36698,	0.13084,	0.96134},
+{0.37942,	0.13637,	0.96288},
+{0.39160,	0.14210,	0.96436},
+{0.40352,	0.14786,	0.96581},
+{0.41520,	0.15363,	0.96722},
+{0.42669,	0.15941,	0.9686},
+{0.43799,	0.16515,	0.96996},
+{0.44913,	0.17088,	0.97129},
+{0.46013,	0.17650,	0.97261},
+{0.47106,	0.18204,	0.97389},
+{0.48191,	0.18751,	0.97514},
+{0.49273,	0.19280,	0.97635},
+{0.50357,	0.19798,	0.97752},
+{0.51446,	0.20302,	0.97863},
+{0.52541,	0.20790,	0.97969},
+{0.53647,	0.21259,	0.98067},
+{0.54767,	0.21709,	0.98157},
+{0.55903,	0.22137,	0.98238},
+{0.57057,	0.22542,	0.9831},
+{0.58230,	0.22925,	0.98372},
+{0.59423,	0.23284,	0.98424},
+{0.60636,	0.23623,	0.98465},
+{0.61868,	0.23935,	0.98497},
+{0.63116,	0.24227,	0.98518},
+{0.64379,	0.24496,	0.9853},
+{0.65656,	0.24750,	0.98533},
+{0.66943,	0.24982,	0.98527},
+{0.68237,	0.25203,	0.98515},
+{0.69537,	0.25408,	0.98496},
+{0.70839,	0.25601,	0.98471},
+{0.72139,	0.25786,	0.98441},
+{0.73437,	0.25968,	0.98405},
+{0.74728,	0.26143,	0.98365},
+{0.76012,	0.26319,	0.98321},
+{0.77286,	0.26494,	0.98271},
+{0.78548,	0.26676,	0.98216},
+{0.79794,	0.26867,	0.98153},
+{0.81023,	0.27069,	0.98082},
+{0.82233,	0.27285,	0.98001},
+{0.83418,	0.27525,	0.97905},
+{0.84576,	0.27791,	0.97793},
+{0.85702,	0.28089,	0.97661},
+{0.86794,	0.28430,	0.97504},
+{0.87845,	0.28819,	0.97317},
+{0.88852,	0.29263,	0.97097},
+{0.89810,	0.29768,	0.96837},
+{0.90717,	0.30340,	0.96533},
+{0.91567,	0.30984,	0.96182},
+{0.92361,	0.31700,	0.9578},
+{0.93095,	0.32489,	0.95323},
+{0.93769,	0.33352,	0.94809},
+{0.94383,	0.34283,	0.94239},
+{0.94939,	0.35275,	0.93613},
+{0.95439,	0.36323,	0.92931},
+{0.95886,	0.37422,	0.92198},
+{0.96283,	0.38558,	0.91416},
+{0.96634,	0.39727,	0.90588},
+{0.96944,	0.40921,	0.89721},
+{0.97216,	0.42130,	0.88817},
+{0.97454,	0.43350,	0.87883},
+{0.97663,	0.44573,	0.86923},
+{0.97845,	0.45797,	0.8594},
+{0.98004,	0.47017,	0.84939},
+{0.98142,	0.48228,	0.83922},
+{0.98262,	0.49430,	0.82894},
+{0.98364,	0.50620,	0.81854},
+{0.98453,	0.51799,	0.80808},
+{0.98527,	0.52964,	0.79753},
+{0.98588,	0.54116,	0.78694},
+{0.98637,	0.55255,	0.77629},
+{0.98676,	0.56382,	0.76559},
+{0.98704,	0.57494,	0.75486},
+{0.98722,	0.58595,	0.74407},
+{0.98733,	0.59683,	0.73326},
+{0.98736,	0.60758,	0.72241},
+{0.98732,	0.61821,	0.71153},
+{0.98723,	0.62871,	0.7006},
+{0.98710,	0.63909,	0.68965},
+{0.98694,	0.64936,	0.67864},
+{0.98677,	0.65949,	0.66762},
+{0.98660,	0.66950,	0.65654},
+{0.98644,	0.67938,	0.64543},
+{0.98630,	0.68916,	0.63428},
+{0.98621,	0.69879,	0.62309},
+{0.98616,	0.70831,	0.61184},
+{0.98617,	0.71772,	0.60055},
+{0.98624,	0.72700,	0.5892},
+{0.98636,	0.73618,	0.57779},
+{0.98653,	0.74526,	0.56632},
+{0.98675,	0.75426,	0.55476},
+{0.98702,	0.76315,	0.54311},
+{0.98731,	0.77198,	0.53134},
+{0.98761,	0.78074,	0.51946},
+{0.98792,	0.78944,	0.50744},
+{0.98820,	0.79807,	0.49526},
+{0.98845,	0.80666,	0.48291},
+{0.98864,	0.81518,	0.47039},
+{0.98875,	0.82365,	0.45765},
+{0.98875,	0.83206,	0.4447},
+{0.98863,	0.84039,	0.43151},
+{0.98834,	0.84863,	0.41804},
+{0.98786,	0.85677,	0.40433},
+{0.98715,	0.86476,	0.39033},
+{0.98616,	0.87259,	0.37607},
+{0.98485,	0.88020,	0.36152},
+{0.98316,	0.88754,	0.3467},
+{0.98105,	0.89458,	0.33163},
+{0.97845,	0.90123,	0.31637},
+{0.97534,	0.90744,	0.30092},
+{0.97166,	0.91315,	0.28537},
+{0.96737,	0.91831,	0.26983},
+{0.96244,	0.92285,	0.25432},
+{0.95686,	0.92672,	0.23895},
+{0.95064,	0.92990,	0.22388},
+{0.94377,	0.93236,	0.2092},
+{0.93628,	0.93410,	0.19506},
+{0.92820,	0.93512,	0.18153},
+{0.91959,	0.93544,	0.16884},
+{0.91047,	0.93510,	0.15697},
+{0.90091,	0.93414,	0.1461},
+{0.89097,	0.93263,	0.13623},
+{0.88070,	0.93061,	0.12747},
+{0.87014,	0.92815,	0.11977},
+{0.85937,	0.92531,	0.11315},
+{0.84840,	0.92216,	0.10742},
+{0.83729,	0.91874,	0.10257},
+{0.82605,	0.91511,	0.098502},
+{0.81472,	0.91132,	0.095091},
+{0.80332,	0.90739,	0.092162},
+{0.79187,	0.90336,	0.089659},
+{0.78036,	0.89925,	0.087518},
+{0.76881,	0.89508,	0.08551},
+{0.75723,	0.89086,	0.083837},
+{0.74562,	0.88662,	0.082243},
+{0.73398,	0.88235,	0.080673},
+{0.72230,	0.87807,	0.079194},
+{0.71060,	0.87376,	0.077792},
+{0.69886,	0.86946,	0.076415},
+{0.68710,	0.86514,	0.075063},
+{0.67529,	0.86082,	0.073757},
+{0.66346,	0.85649,	0.072319},
+{0.65156,	0.85215,	0.071005},
+{0.63963,	0.84780,	0.069678},
+{0.62764,	0.84345,	0.068313},
+{0.61560,	0.83909,	0.066946},
+{0.60351,	0.83473,	0.065602},
+{0.59134,	0.83035,	0.064284},
+{0.57911,	0.82597,	0.063016},
+{0.56681,	0.82158,	0.061599},
+{0.55443,	0.81718,	0.060374},
+{0.54195,	0.81278,	0.059088},
+{0.52940,	0.80837,	0.057695},
+{0.51672,	0.80395,	0.056522},
+{0.50395,	0.79952,	0.055189},
+{0.49106,	0.79508,	0.053903},
+{0.47801,	0.79064,	0.052644},
+{0.46484,	0.78619,	0.051424},
+{0.45151,	0.78173,	0.050257},
+{0.43803,	0.77726,	0.04922},
+{0.42437,	0.77277,	0.04812},
+{0.41056,	0.76827,	0.047322},
+{0.39656,	0.76375,	0.04674},
+{0.38239,	0.75922,	0.046427},
+{0.36808,	0.75466,	0.046596},
+{0.35361,	0.75006,	0.047299},
+{0.33906,	0.74543,	0.04874},
+{0.32443,	0.74075,	0.050897},
+{0.30984,	0.73602,	0.054069},
+{0.29532,	0.73122,	0.058336},
+{0.28105,	0.72634,	0.063783},
+{0.26717,	0.72137,	0.070322},
+{0.25387,	0.71631,	0.077992},
+{0.24134,	0.71112,	0.08687},
+{0.22981,	0.70580,	0.096608},
+{0.21961,	0.70035,	0.10741},
+{0.21092,	0.69475,	0.11899},
+{0.20400,	0.68901,	0.13129},
+{0.19894,	0.68310,	0.14422},
+{0.19593,	0.67703,	0.15768},
+{0.19486,	0.67081,	0.17161},
+{0.19560,	0.66443,	0.18594},
+{0.19795,	0.65791,	0.2005},
+{0.20163,	0.65125,	0.21533},
+{0.20639,	0.64446,	0.2303},
+{0.21183,	0.63756,	0.24538},
+{0.21771,	0.63057,	0.26052},
+{0.22381,	0.62348,	0.27565},
+{0.22992,	0.61632,	0.29071},
+{0.23593,	0.60910,	0.30574},
+{0.24162,	0.60182,	0.32064},
+{0.24693,	0.59450,	0.33543},
+{0.25184,	0.58716,	0.35008},
+{0.25622,	0.57980,	0.36459},
+{0.26011,	0.57242,	0.37897},
+{0.26346,	0.56501,	0.3932},
+{0.26624,	0.55762,	0.4073},
+{0.26846,	0.55021,	0.42127},
+{0.27013,	0.54280,	0.43513},
+{0.27122,	0.53539,	0.44886},
+{0.27173,	0.52798,	0.46247},
+{0.27170,	0.52057,	0.476},
+{0.27112,	0.51317,	0.48942},
+{0.26997,	0.50576,	0.50275},
+{0.26823,	0.49837,	0.516},
+{0.26598,	0.49096,	0.52919},
+{0.26316,	0.48352,	0.54228},
+{0.25982,	0.47610,	0.55529},
+{0.25594,	0.46864,	0.56822},
+{0.25162,	0.46117,	0.58105},
+{0.24680,	0.45365,	0.5938},
+{0.24161,	0.44609,	0.60643},
+{0.23605,	0.43849,	0.61894},
+{0.23017,	0.43081,	0.63131},
+{0.22410,	0.42303,	0.64353},
+{0.21793,	0.41517,	0.6556},
+{0.21170,	0.40718,	0.66749},
+{0.20550,	0.39906,	0.67919},
+{0.19945,	0.39079,	0.6907},
+{0.19367,	0.38234,	0.70201},
+{0.18818,	0.37372,	0.71312},
+{0.18300,	0.36488,	0.72404},
+{0.17829,	0.35585,	0.73477},
+{0.17392,	0.34657,	0.7453},
+{0.16999,	0.33707,	0.75566},
+{0.16639,	0.32732,	0.76586},
+{0.16312,	0.31735,	0.7759},
+{0.16005,	0.30712,	0.78581},
+{0.15724,	0.29667,	0.79557},
+{0.15457,	0.28595,	0.80522},
+{0.15202,	0.27505,	0.81474},
+{0.14966,	0.26395,	0.82414},
+{0.14744,	0.25264,	0.8334},
+{0.14554,	0.24118,	0.84252},
+{0.14402,	0.22960,	0.85145},
+{0.14312,	0.21800,	0.86019},
+{0.14305,	0.20639,	0.86869},
+{0.14404,	0.19481,	0.87691},
+{0.14630,	0.18336,	0.88484},
+{0.15007,	0.17219,	0.89241},
+{0.15537,	0.16140,	0.8996},
+{0.16230,	0.15103,	0.90637},
+{0.17075,	0.14136,	0.9127},
+};
+
+
+// viridis is the new default perceptually uniform colormap of the 
+// "matplotlib" project (http://matplotlib.org/)
+// Direct link to the colormap is 
+// 	https://github.com/BIDS/colormap/blob/master/colormaps.py
+
+// Viridis (and the other colormaps available at the link) are created by
+// Nathaniel J. Smith, Stefan van der Walt, and (in the case of viridis) Eric Firing.
+
+// The file (https://github.com/BIDS/colormap/blob/master/colormaps.py)
+// and the colormaps in it are released under the CC0 license /
+// public domain dedication. The authors would appreciate credit if you use or
+// redistribute these colormaps, but do not impose any legal restrictions.
+
+// See <http://creativecommons.org/publicdomain/zero/1.0/> for a copy
+// of the CC0 license.
+
+static const double viridis[256][3] = {
+	{0.267004, 0.004874, 0.329415},
+	{0.268510, 0.009605, 0.335427},
+	{0.269944, 0.014625, 0.341379},
+	{0.271305, 0.019942, 0.347269},
+	{0.272594, 0.025563, 0.353093},
+	{0.273809, 0.031497, 0.358853},
+	{0.274952, 0.037752, 0.364543},
+	{0.276022, 0.044167, 0.370164},
+	{0.277018, 0.050344, 0.375715},
+	{0.277941, 0.056324, 0.381191},
+	{0.278791, 0.062145, 0.386592},
+	{0.279566, 0.067836, 0.391917},
+	{0.280267, 0.073417, 0.397163},
+	{0.280894, 0.078907, 0.402329},
+	{0.281446, 0.084320, 0.407414},
+	{0.281924, 0.089666, 0.412415},
+	{0.282327, 0.094955, 0.417331},
+	{0.282656, 0.100196, 0.422160},
+	{0.282910, 0.105393, 0.426902},
+	{0.283091, 0.110553, 0.431554},
+	{0.283197, 0.115680, 0.436115},
+	{0.283229, 0.120777, 0.440584},
+	{0.283187, 0.125848, 0.444960},
+	{0.283072, 0.130895, 0.449241},
+	{0.282884, 0.135920, 0.453427},
+	{0.282623, 0.140926, 0.457517},
+	{0.282290, 0.145912, 0.461510},
+	{0.281887, 0.150881, 0.465405},
+	{0.281412, 0.155834, 0.469201},
+	{0.280868, 0.160771, 0.472899},
+	{0.280255, 0.165693, 0.476498},
+	{0.279574, 0.170599, 0.479997},
+	{0.278826, 0.175490, 0.483397},
+	{0.278012, 0.180367, 0.486697},
+	{0.277134, 0.185228, 0.489898},
+	{0.276194, 0.190074, 0.493001},
+	{0.275191, 0.194905, 0.496005},
+	{0.274128, 0.199721, 0.498911},
+	{0.273006, 0.204520, 0.501721},
+	{0.271828, 0.209303, 0.504434},
+	{0.270595, 0.214069, 0.507052},
+	{0.269308, 0.218818, 0.509577},
+	{0.267968, 0.223549, 0.512008},
+	{0.266580, 0.228262, 0.514349},
+	{0.265145, 0.232956, 0.516599},
+	{0.263663, 0.237631, 0.518762},
+	{0.262138, 0.242286, 0.520837},
+	{0.260571, 0.246922, 0.522828},
+	{0.258965, 0.251537, 0.524736},
+	{0.257322, 0.256130, 0.526563},
+	{0.255645, 0.260703, 0.528312},
+	{0.253935, 0.265254, 0.529983},
+	{0.252194, 0.269783, 0.531579},
+	{0.250425, 0.274290, 0.533103},
+	{0.248629, 0.278775, 0.534556},
+	{0.246811, 0.283237, 0.535941},
+	{0.244972, 0.287675, 0.537260},
+	{0.243113, 0.292092, 0.538516},
+	{0.241237, 0.296485, 0.539709},
+	{0.239346, 0.300855, 0.540844},
+	{0.237441, 0.305202, 0.541921},
+	{0.235526, 0.309527, 0.542944},
+	{0.233603, 0.313828, 0.543914},
+	{0.231674, 0.318106, 0.544834},
+	{0.229739, 0.322361, 0.545706},
+	{0.227802, 0.326594, 0.546532},
+	{0.225863, 0.330805, 0.547314},
+	{0.223925, 0.334994, 0.548053},
+	{0.221989, 0.339161, 0.548752},
+	{0.220057, 0.343307, 0.549413},
+	{0.218130, 0.347432, 0.550038},
+	{0.216210, 0.351535, 0.550627},
+	{0.214298, 0.355619, 0.551184},
+	{0.212395, 0.359683, 0.551710},
+	{0.210503, 0.363727, 0.552206},
+	{0.208623, 0.367752, 0.552675},
+	{0.206756, 0.371758, 0.553117},
+	{0.204903, 0.375746, 0.553533},
+	{0.203063, 0.379716, 0.553925},
+	{0.201239, 0.383670, 0.554294},
+	{0.199430, 0.387607, 0.554642},
+	{0.197636, 0.391528, 0.554969},
+	{0.195860, 0.395433, 0.555276},
+	{0.194100, 0.399323, 0.555565},
+	{0.192357, 0.403199, 0.555836},
+	{0.190631, 0.407061, 0.556089},
+	{0.188923, 0.410910, 0.556326},
+	{0.187231, 0.414746, 0.556547},
+	{0.185556, 0.418570, 0.556753},
+	{0.183898, 0.422383, 0.556944},
+	{0.182256, 0.426184, 0.557120},
+	{0.180629, 0.429975, 0.557282},
+	{0.179019, 0.433756, 0.557430},
+	{0.177423, 0.437527, 0.557565},
+	{0.175841, 0.441290, 0.557685},
+	{0.174274, 0.445044, 0.557792},
+	{0.172719, 0.448791, 0.557885},
+	{0.171176, 0.452530, 0.557965},
+	{0.169646, 0.456262, 0.558030},
+	{0.168126, 0.459988, 0.558082},
+	{0.166617, 0.463708, 0.558119},
+	{0.165117, 0.467423, 0.558141},
+	{0.163625, 0.471133, 0.558148},
+	{0.162142, 0.474838, 0.558140},
+	{0.160665, 0.478540, 0.558115},
+	{0.159194, 0.482237, 0.558073},
+	{0.157729, 0.485932, 0.558013},
+	{0.156270, 0.489624, 0.557936},
+	{0.154815, 0.493313, 0.557840},
+	{0.153364, 0.497000, 0.557724},
+	{0.151918, 0.500685, 0.557587},
+	{0.150476, 0.504369, 0.557430},
+	{0.149039, 0.508051, 0.557250},
+	{0.147607, 0.511733, 0.557049},
+	{0.146180, 0.515413, 0.556823},
+	{0.144759, 0.519093, 0.556572},
+	{0.143343, 0.522773, 0.556295},
+	{0.141935, 0.526453, 0.555991},
+	{0.140536, 0.530132, 0.555659},
+	{0.139147, 0.533812, 0.555298},
+	{0.137770, 0.537492, 0.554906},
+	{0.136408, 0.541173, 0.554483},
+	{0.135066, 0.544853, 0.554029},
+	{0.133743, 0.548535, 0.553541},
+	{0.132444, 0.552216, 0.553018},
+	{0.131172, 0.555899, 0.552459},
+	{0.129933, 0.559582, 0.551864},
+	{0.128729, 0.563265, 0.551229},
+	{0.127568, 0.566949, 0.550556},
+	{0.126453, 0.570633, 0.549841},
+	{0.125394, 0.574318, 0.549086},
+	{0.124395, 0.578002, 0.548287},
+	{0.123463, 0.581687, 0.547445},
+	{0.122606, 0.585371, 0.546557},
+	{0.121831, 0.589055, 0.545623},
+	{0.121148, 0.592739, 0.544641},
+	{0.120565, 0.596422, 0.543611},
+	{0.120092, 0.600104, 0.542530},
+	{0.119738, 0.603785, 0.541400},
+	{0.119512, 0.607464, 0.540218},
+	{0.119423, 0.611141, 0.538982},
+	{0.119483, 0.614817, 0.537692},
+	{0.119699, 0.618490, 0.536347},
+	{0.120081, 0.622161, 0.534946},
+	{0.120638, 0.625828, 0.533488},
+	{0.121380, 0.629492, 0.531973},
+	{0.122312, 0.633153, 0.530398},
+	{0.123444, 0.636809, 0.528763},
+	{0.124780, 0.640461, 0.527068},
+	{0.126326, 0.644107, 0.525311},
+	{0.128087, 0.647749, 0.523491},
+	{0.130067, 0.651384, 0.521608},
+	{0.132268, 0.655014, 0.519661},
+	{0.134692, 0.658636, 0.517649},
+	{0.137339, 0.662252, 0.515571},
+	{0.140210, 0.665859, 0.513427},
+	{0.143303, 0.669459, 0.511215},
+	{0.146616, 0.673050, 0.508936},
+	{0.150148, 0.676631, 0.506589},
+	{0.153894, 0.680203, 0.504172},
+	{0.157851, 0.683765, 0.501686},
+	{0.162016, 0.687316, 0.499129},
+	{0.166383, 0.690856, 0.496502},
+	{0.170948, 0.694384, 0.493803},
+	{0.175707, 0.697900, 0.491033},
+	{0.180653, 0.701402, 0.488189},
+	{0.185783, 0.704891, 0.485273},
+	{0.191090, 0.708366, 0.482284},
+	{0.196571, 0.711827, 0.479221},
+	{0.202219, 0.715272, 0.476084},
+	{0.208030, 0.718701, 0.472873},
+	{0.214000, 0.722114, 0.469588},
+	{0.220124, 0.725509, 0.466226},
+	{0.226397, 0.728888, 0.462789},
+	{0.232815, 0.732247, 0.459277},
+	{0.239374, 0.735588, 0.455688},
+	{0.246070, 0.738910, 0.452024},
+	{0.252899, 0.742211, 0.448284},
+	{0.259857, 0.745492, 0.444467},
+	{0.266941, 0.748751, 0.440573},
+	{0.274149, 0.751988, 0.436601},
+	{0.281477, 0.755203, 0.432552},
+	{0.288921, 0.758394, 0.428426},
+	{0.296479, 0.761561, 0.424223},
+	{0.304148, 0.764704, 0.419943},
+	{0.311925, 0.767822, 0.415586},
+	{0.319809, 0.770914, 0.411152},
+	{0.327796, 0.773980, 0.406640},
+	{0.335885, 0.777018, 0.402049},
+	{0.344074, 0.780029, 0.397381},
+	{0.352360, 0.783011, 0.392636},
+	{0.360741, 0.785964, 0.387814},
+	{0.369214, 0.788888, 0.382914},
+	{0.377779, 0.791781, 0.377939},
+	{0.386433, 0.794644, 0.372886},
+	{0.395174, 0.797475, 0.367757},
+	{0.404001, 0.800275, 0.362552},
+	{0.412913, 0.803041, 0.357269},
+	{0.421908, 0.805774, 0.351910},
+	{0.430983, 0.808473, 0.346476},
+	{0.440137, 0.811138, 0.340967},
+	{0.449368, 0.813768, 0.335384},
+	{0.458674, 0.816363, 0.329727},
+	{0.468053, 0.818921, 0.323998},
+	{0.477504, 0.821444, 0.318195},
+	{0.487026, 0.823929, 0.312321},
+	{0.496615, 0.826376, 0.306377},
+	{0.506271, 0.828786, 0.300362},
+	{0.515992, 0.831158, 0.294279},
+	{0.525776, 0.833491, 0.288127},
+	{0.535621, 0.835785, 0.281908},
+	{0.545524, 0.838039, 0.275626},
+	{0.555484, 0.840254, 0.269281},
+	{0.565498, 0.842430, 0.262877},
+	{0.575563, 0.844566, 0.256415},
+	{0.585678, 0.846661, 0.249897},
+	{0.595839, 0.848717, 0.243329},
+	{0.606045, 0.850733, 0.236712},
+	{0.616293, 0.852709, 0.230052},
+	{0.626579, 0.854645, 0.223353},
+	{0.636902, 0.856542, 0.216620},
+	{0.647257, 0.858400, 0.209861},
+	{0.657642, 0.860219, 0.203082},
+	{0.668054, 0.861999, 0.196293},
+	{0.678489, 0.863742, 0.189503},
+	{0.688944, 0.865448, 0.182725},
+	{0.699415, 0.867117, 0.175971},
+	{0.709898, 0.868751, 0.169257},
+	{0.720391, 0.870350, 0.162603},
+	{0.730889, 0.871916, 0.156029},
+	{0.741388, 0.873449, 0.149561},
+	{0.751884, 0.874951, 0.143228},
+	{0.762373, 0.876424, 0.137064},
+	{0.772852, 0.877868, 0.131109},
+	{0.783315, 0.879285, 0.125405},
+	{0.793760, 0.880678, 0.120005},
+	{0.804182, 0.882046, 0.114965},
+	{0.814576, 0.883393, 0.110347},
+	{0.824940, 0.884720, 0.106217},
+	{0.835270, 0.886029, 0.102646},
+	{0.845561, 0.887322, 0.099702},
+	{0.855810, 0.888601, 0.097452},
+	{0.866013, 0.889868, 0.095953},
+	{0.876168, 0.891125, 0.095250},
+	{0.886271, 0.892374, 0.095374},
+	{0.896320, 0.893616, 0.096335},
+	{0.906311, 0.894855, 0.098125},
+	{0.916242, 0.896091, 0.100717},
+	{0.926106, 0.897330, 0.104071},
+	{0.935904, 0.898570, 0.108131},
+	{0.945636, 0.899815, 0.112838},
+	{0.955300, 0.901065, 0.118128},
+	{0.964894, 0.902323, 0.123941},
+	{0.974417, 0.903590, 0.130215},
+	{0.983868, 0.904867, 0.136897},
+	{0.993248, 0.906157, 0.143936},
+};


=====================================
src/draw.c
=====================================
--- a/src/draw.c
+++ b/src/draw.c
@@ -1,9 +1,9 @@
-/* Copyright 2015. Martin Uecker.
+/* Copyright 2015-2016. Martin Uecker.
  * All rights reserved. Use of this source code is governed by
  * a BSD-style license which can be found in the LICENSE file.
  *
  * Author:
- *	2015 Martin Uecker <martin.uecker at med.uni-goettingen.de>
+ *	2015-2016 Martin Uecker <martin.uecker at med.uni-goettingen.de>
  */
 
 #include <math.h>
@@ -14,6 +14,8 @@
 
 #include "draw.h"
 
+#include "colormaps.inc"
+
 // multind.h
 #define MD_BIT(x) (1u << (x))
 #define MD_IS_SET(x, y) ((x) & MD_BIT(y))
@@ -39,6 +41,21 @@ static void trans_magnitude(double rgb[3], double a, double b, complex double va
 	rgb[2] *= magn;
 }
 
+static void trans_magnitude_viridis(double rgb[3], double a, double b, complex double value)
+{
+	double magn = window(a, b, cabs(value));
+	// since window returns nonsense (NaN) if a == b, and since casting nonsense to int
+	// and using it as an array subscript is bound to lead to segfaults,
+	// we catch that case here
+	if ( isfinite(magn) ) {
+		int subscript = magn*255.;
+
+		rgb[0] *= viridis[subscript][0];
+		rgb[1] *= viridis[subscript][1];
+		rgb[2] *= viridis[subscript][2];
+	}
+}
+
 static void trans_real(double rgb[3], double a, double b, complex double value)
 {
 	rgb[0] *= window(a, b, +creal(value));
@@ -48,17 +65,40 @@ static void trans_real(double rgb[3], double a, double b, complex double value)
 
 static void trans_phase(double rgb[3], double a, double b, complex double value)
 {
+	UNUSED(a);
+	UNUSED(b);
 	rgb[0] *= (1. + sin(carg(value) + 0. * 2. * M_PI / 3.)) / 2.;
 	rgb[1] *= (1. + sin(carg(value) + 1. * 2. * M_PI / 3.)) / 2.;
 	rgb[2] *= (1. + sin(carg(value) + 2. * 2. * M_PI / 3.)) / 2.;
 }
 
+static void trans_phase_MYGBM(double rgb[3], double a, double b, complex double value)
+{
+	UNUSED(a);
+	UNUSED(b);
+	double arg = carg(value);
+	if (isfinite(arg)) {
+		int subscript = (arg+M_PI)/2./M_PI*255.;
+		assert( (0 <= subscript) && (subscript <=255) );
+	
+		rgb[0] *= cyclic_mygbm[subscript][0];
+		rgb[1] *= cyclic_mygbm[subscript][1];
+		rgb[2] *= cyclic_mygbm[subscript][2];
+	}
+}
+
 static void trans_complex(double rgb[3], double a, double b, complex double value)
 {
 	trans_magnitude(rgb, a, b, value);
 	trans_phase(rgb, a, b, value);
 }
 
+static void trans_complex_MYGBM(double rgb[3], double a, double b, complex double value)
+{
+	trans_magnitude(rgb, a, b, value);
+	trans_phase_MYGBM(rgb, a, b, value);
+}
+
 static void trans_flow(double rgb[3], double a, double b, complex double value)
 {
 	trans_magnitude(rgb, a, b, value);
@@ -75,13 +115,23 @@ static void trans_flow(double rgb[3], double a, double b, complex double value)
 // as an extra argument which could save time
 static complex float int_nlinear(int N, const float x[N], const long strs[N], const complex float* in)
 {
- 	return (0 == N) ? in[0]
+	return (0 == N) ? in[0]
 			: (  (1. - x[N - 1]) * int_nlinear(N - 1, x, strs, in + 0)
 		           +       x[N - 1]  * int_nlinear(N - 1, x, strs, in + strs[N - 1]));
 }
 
 
-complex float sample(int N, const float pos[N], const long dims[N], const long strs[N], const complex float* in)
+static complex float int_nearest(int N, const float x[N], const long strs[N], const complex float* in)
+{
+	size_t offs = 0;
+	for (int i = 0; i < N; ++i)
+		offs += round(x[i]) * strs[i];
+
+	return *(in + offs);
+}
+
+
+complex float sample(int N, const float pos[N], const long dims[N], const long strs[N], enum interp_t interpolation, const complex float* in)
 {
 	float rem[N];
 	int div[N];
@@ -96,8 +146,19 @@ complex float sample(int N, const float pos[N], const long dims[N], const long s
 
 		if (dims[i] > 1) {
 	
-			div[i] = truncf(pos[i]);
-			float xrem = pos[i] - truncf(pos[i]);
+			float xrem = 0.;
+			// values outside of valid range set to the edge values
+			if (pos[i] < 0.) {
+
+				div[i] = 0.;
+			} else if (pos[i] > (dims[i] - 1)) {
+
+				div[i] = dims[i] - 1;
+			} else {
+
+				div[i] = truncf(pos[i]);
+				xrem = pos[i] - truncf(pos[i]);
+			}
 
 			if (xrem != 0.) {
 
@@ -105,8 +166,6 @@ complex float sample(int N, const float pos[N], const long dims[N], const long s
 				rem[D++] = xrem;
 			}
 
-		//printf("%d\n", div[i]);
-
 			if ((div[i] < 0) || (div[i] >= dims[i]) || ((div[i] >= dims[i] - 1) && (xrem > 0.)))
 				return 0.;
 		}
@@ -117,22 +176,41 @@ complex float sample(int N, const float pos[N], const long dims[N], const long s
 	for (int i = 0; i < N; i++)
 		off0 += div[i] * strs[i];
 
-	return int_nlinear(D, rem, strs2, (const complex float*)(((char*)in) + off0));
-}
+	switch (interpolation) {
 
+	case NLINEAR: return int_nlinear(D, rem, strs2, (const complex float*)(((char*)in) + off0));
+	case NEAREST: return int_nearest(D, rem, strs2, (const complex float*)(((char*)in) + off0));
+	default: assert(0);
+	}
+}
 
+// The idea is the following:
+// samples sit in the middle of their pixels, so for even zoom factors,
+// the original values are between adjacent pixels, with pixels outside
+// of the valid range (negative pos2 and pos2 greater than dim-1) set to the
+// corresponding values. Therefore we need to start the pos2 array at negative
+// positions.
 extern void resample(int X, int Y, long str, complex float* buf,
 	int N, const double pos[N], const double dx[N], const double dy[N], 
-	const long dims[N], const long strs[N], const complex float* in)
+	const long dims[N], const long strs[N], enum interp_t interpolation, const complex float* in)
 {
 	for (int x = 0; x < X; x++) {
 		for (int y = 0; y < Y; y++) {
 
 			float pos2[N];
-			for (int i = 0; i < N; i++)
-				pos2[i] = pos[i] + x * dx[i] + y * dy[i];
-
-			buf[str * y + x] = sample(N, pos2, dims, strs, in);
+			for (int i = 0; i < N; i++) {
+
+				// start is only != 0 if dx or dy are != 0.
+				// Further, for negative dx/dy, it needs the same sign.
+				// ....0.......1....	d	(|d| - 1.) / 2.
+				// |---*---|---*---|	1.00 ->	-0.000
+				// |-*-|-*-|-*-|-*-|	0.50 ->	-0.250
+				// |*|*|*|*|*|*|*|*|	0.25 ->	-0.375
+				double start = 	- (dx[i] != 0.) * copysign((fabs(dx[i]) - 1.) / 2., dx[i])
+						- (dy[i] != 0.) * copysign((fabs(dy[i]) - 1.) / 2., dy[i]);
+				pos2[i] = pos[i] + start + x * dx[i] + y * dy[i];
+			}
+			buf[str * y + x] = sample(N, pos2, dims, strs, interpolation, in);
 		}
 	}
 }
@@ -140,7 +218,7 @@ extern void resample(int X, int Y, long str, complex float* buf,
 
 
 
-extern void draw(int X, int Y, int rgbstr, unsigned char* rgbbuf,
+extern void draw(int X, int Y, int rgbstr, unsigned char (*rgbbuf)[Y][rgbstr / 4][4],
 	enum mode_t mode, float scale, float winlow, float winhigh, float phrot,
 	long str, const complex float* buf)
 {
@@ -156,17 +234,144 @@ extern void draw(int X, int Y, int rgbstr, unsigned char* rgbbuf,
 			switch (mode) {
 
 			case MAGN: trans_magnitude(rgb, winlow, winhigh, val); break;
+			case MAGN_VIRIDS: trans_magnitude_viridis(rgb, winlow, winhigh, val); break;
 			case PHSE: trans_phase(rgb, winlow, winhigh, val); break;
+			case PHSE_MYGBM: trans_phase_MYGBM(rgb, winlow, winhigh, val); break;
 			case CMPL: trans_complex(rgb, winlow, winhigh, val); break;
+			case CMPL_MYGBM: trans_complex_MYGBM(rgb, winlow, winhigh, val); break;
 			case REAL: trans_real(rgb, winlow, winhigh, val); break;
 			case FLOW: trans_flow(rgb, winlow, winhigh, val); break;
 			default: assert(0);
 			}
 
-			rgbbuf[y * rgbstr + x * 4 + 0] = 255. * rgb[2];
-			rgbbuf[y * rgbstr + x * 4 + 1] = 255. * rgb[1];
-			rgbbuf[y * rgbstr + x * 4 + 2] = 255. * rgb[0];
-			rgbbuf[y * rgbstr + x * 4 + 3] = 0.;
+			(*rgbbuf)[y][x][0] = 255. * rgb[2];
+			(*rgbbuf)[y][x][1] = 255. * rgb[1];
+			(*rgbbuf)[y][x][2] = 255. * rgb[0];
+			(*rgbbuf)[y][x][3] = 255.;
+		}
+	}
+}
+
+
+void update_buf(long xdim, long ydim, int N, const long dims[N],  const long strs[N], const long pos[N],
+		enum flip_t flip, enum interp_t interpolation, double xzoom, double yzoom,
+		long rgbw, long rgbh, const complex float* data, complex float* buf)
+{
+	double dpos[N];
+	for (int i = 0; i < N; i++)
+		dpos[i] = pos[i];
+
+	dpos[xdim] = 0.;
+	dpos[ydim] = 0.;
+
+	double dx[N];
+	for (int i = 0; i < N; i++)
+		dx[i] = 0.;
+
+	double dy[N];
+	for (int i = 0; i < N; i++)
+		dy[i] = 0.;
+
+	dx[xdim] = 1.;
+	dy[ydim] = 1.;
+
+
+	if ((XY == flip) || (XO == flip)) {
+
+		dpos[xdim] = dims[xdim] - 1;
+		dx[xdim] *= -1.;
+	}
+
+	if ((XY == flip) || (OY == flip)) {
+
+		dpos[ydim] = dims[ydim] - 1;
+		dy[ydim] *= -1.;
+	}
+
+	dx[xdim] = dx[xdim] / xzoom;
+	dy[ydim] = dy[ydim] / yzoom;
+
+	resample(rgbw, rgbh, rgbw, buf,
+		 N, dpos, dx, dy, dims, strs, interpolation, data);
+}
+
+// Get dimension specifier for filename
+extern char* get_spec(int i)
+{
+	switch(i) {
+		case  0: return "x"; break;
+		case  1: return "y"; break;
+		case  2: return "z"; break;
+		case  3: return "coil"; break;
+		case  4: return "map"; break;
+		case  5: return "n"; break;
+		case  6: return "o"; break;
+		case  7: return "p"; break;
+		case  8: return "q"; break;
+		case  9: return "slice"; break;
+		case 10: return "frame"; break;
+		case 11: return "s"; break;
+		case 12: return "t"; break;
+		case 13: return "u"; break;
+		case 14: return "v"; break;
+		case 15: return "w"; break;
+		default: error("Invalid dimension!");
+	}
+	return "";
+}
+
+
+
+const char color_white[3] = { 255, 255, 255 };
+const char color_blue[3] = { 255, 0, 0 };
+const char color_red[3] = { 0, 0, 255 };
+
+
+extern void draw_line(int X, int Y, int rgbstr, unsigned char (*rgbbuf)[Y][rgbstr / 4][4], float x0, float y0, float x1, float y1, const char (*color)[3])
+{
+	float stepx = x1 - x0;
+	float stepy = y1 - y0;
+
+	float max = 1.44 * sqrtf(powf(stepx, 2.) + powf(stepy, 2.));
+
+	stepx /= max;
+	stepy /= max;
+
+	for (unsigned int i = 0; i < max; i++) {
+
+		int xi = (int)roundf(x0 + i * stepx);
+		int yi = (int)roundf(y0 + i * stepy);
+
+		if ((0 <= xi) && (xi < X) && (0 <= yi) && (yi < Y)) {
+
+			(*rgbbuf)[yi][xi][0] = (*color)[0];
+			(*rgbbuf)[yi][xi][1] = (*color)[1];
+			(*rgbbuf)[yi][xi][2] = (*color)[2];
+		}
+	}
+}
+
+
+extern void draw_grid(int X, int Y, int rgbstr, unsigned char (*rgbbuf)[Y][rgbstr / 4][4], const float (*coord)[4][2], int divs, const char (*color)[3])
+{
+	for (int i = 0; i <= divs; i++) {
+		for (int j = 0; j <= divs; j++) {
+
+			float x0 = (*coord)[0][0] + i * ((*coord)[1][0] - (*coord)[0][0]) / divs;
+			float y0 = (*coord)[0][1] + i * ((*coord)[1][1] - (*coord)[0][1]) / divs;
+
+			float x1 = (*coord)[2][0] + i * ((*coord)[3][0] - (*coord)[2][0]) / divs;
+			float y1 = (*coord)[2][1] + i * ((*coord)[3][1] - (*coord)[2][1]) / divs;
+
+			draw_line(X, Y, rgbstr, rgbbuf, x0, y0, x1, y1, color);
+
+			x0 = (*coord)[0][0] + i * ((*coord)[2][0] - (*coord)[0][0]) / divs;
+			y0 = (*coord)[0][1] + i * ((*coord)[2][1] - (*coord)[0][1]) / divs;
+
+			x1 = (*coord)[1][0] + i * ((*coord)[3][0] - (*coord)[1][0]) / divs;
+			y1 = (*coord)[1][1] + i * ((*coord)[3][1] - (*coord)[1][1]) / divs;
+
+			draw_line(X, Y, rgbstr, rgbbuf, x0, y0, x1, y1, color);
 		}
 	}
 }


=====================================
src/draw.h
=====================================
--- a/src/draw.h
+++ b/src/draw.h
@@ -2,16 +2,29 @@
 #include <complex.h>
 
 
-enum mode_t { MAGN, CMPL, PHSE, REAL, FLOW };
+enum mode_t { MAGN, MAGN_VIRIDS, CMPL, CMPL_MYGBM, PHSE, PHSE_MYGBM, REAL, FLOW };
+enum flip_t { OO, XO, OY, XY };
+enum interp_t { NLINEAR, NEAREST };
 
-extern complex float sample(int N, const float pos[N], const long dims[N], const long strs[N], const complex float* in);
+extern complex float sample(int N, const float pos[N], const long dims[N], const long strs[N], enum interp_t interpolation, const complex float* in);
 
 extern void resample(int X, int Y, long str, complex float* buf,
 	int N, const double pos[N], const double dx[N], const double dy[N], 
-	const long dims[N], const long strs[N], const complex float* in);
+	const long dims[N], const long strs[N], enum interp_t interpolation, const complex float* in);
 
-extern void draw(int X, int Y, int rgbstr, unsigned char* rgbbuf,
+extern void draw(int X, int Y, int rgbstr, unsigned char (*rgbbuf)[Y][rgbstr / 4][4],
 	enum mode_t mode, float scale, float winlow, float winhigh, float phrot,
 	long str, const complex float* buf);
 
+extern void update_buf(long xdim, long ydim, int N, const long dims[N],  const long strs[N], const long pos[N], enum flip_t flip, enum interp_t interpolation, double xzoom, double yzoom,
+		long rgbw, long rgbh, const complex float* data, complex float* buf);
+
+extern char* get_spec(int i);
+
+extern void draw_line(int X, int Y, int rgbstr, unsigned char (*rgbbuf)[Y][rgbstr / 4][4], float x0, float y0, float x1, float y1, const char (*color)[3]);
+extern void draw_grid(int X, int Y, int rgbstr, unsigned char (*rgbbuf)[Y][rgbstr / 4][4], const float (*coord)[4][2], int divs, const char (*color)[3]);
+
+extern const char color_white[3];
+extern const char color_red[3];
+extern const char color_blue[3];
 


=====================================
src/view.c
=====================================
--- a/src/view.c
+++ b/src/view.c
@@ -11,6 +11,8 @@
 #include <complex.h>
 #include <stdbool.h>
 
+#include <libgen.h>
+
 #include <gtk/gtk.h>
 #include <pango/pango.h>
 #include <pango/pangocairo.h>
@@ -44,6 +46,8 @@ struct view_s {
 	struct view_s* prev;
 	bool sync;
 
+	bool cross_hair;
+
 	const char* name;
 
 	// geometry
@@ -52,7 +56,7 @@ struct view_s {
 	int ydim;
 	double xzoom;
 	double yzoom;
-	enum flip_t { OO, XO, OY, XY } flip;
+	enum flip_t flip;
 	bool transpose;
 
 	// representation
@@ -61,6 +65,7 @@ struct view_s {
 	double winlow;
 	double phrot;
 	double max;
+	enum interp_t interpolation;
 
 	complex float* buf;
 
@@ -82,6 +87,7 @@ struct view_s {
 	// widgets
 	GtkComboBox* gtk_mode;
 	GtkComboBox* gtk_flip;
+	GtkComboBox* gtk_interp;
 	GtkWidget* gtk_drawingarea;
 	GtkWidget* gtk_viewport;
 	GtkAdjustment* gtk_winlow;
@@ -90,9 +96,14 @@ struct view_s {
 	GtkAdjustment* gtk_aniso;
 	GtkEntry* gtk_entry;
 	GtkToggleToolButton* gtk_transpose;
+	GtkToggleToolButton* gtk_fit;
 
 	GtkAdjustment* gtk_posall[DIMS];
 	GtkCheckButton* gtk_checkall[DIMS];
+	
+	GtkWidget *dialog; // Save dialog
+	GtkFileChooser *chooser; // Save dialog
+	GtkWindow *window; 
 
 	// windowing
 	int lastx;
@@ -157,8 +168,14 @@ extern gboolean update_view(struct view_s* v)
 
 extern gboolean fit_callback(GtkWidget *widget, gpointer data)
 {
+	UNUSED(widget);
 	struct view_s* v = data;
 
+	gboolean flag = gtk_toggle_tool_button_get_active(v->gtk_fit);
+
+	if (!flag)
+		return FALSE;
+
 	double aniso = gtk_adjustment_get_value(v->gtk_aniso);
 
 	GtkAllocation alloc;
@@ -176,10 +193,31 @@ extern gboolean fit_callback(GtkWidget *widget, gpointer data)
 }
 
 
-extern gboolean refresh_callback(GtkWidget *widget, gpointer data)
+extern gboolean configure_callback(GtkWidget *widget, GdkEvent* event, gpointer data)
 {
-	struct view_s* v = data;
+	UNUSED(event);
+	return fit_callback(widget, data);
+}
+
+
+extern void view_setpos(struct view_s* v, unsigned int flags, const long pos[DIMS])
+{
+	for (unsigned int i = 0; i < DIMS; i++) {
+
+		if (MD_IS_SET(flags, i)) {
+
+			gtk_adjustment_set_value(v->gtk_posall[i], pos[i]);
+
+			for (struct view_s* v2 = v->next; v2 != v; v2 = v2->next)
+				if (v->sync && v2->sync)
+					gtk_adjustment_set_value(v2->gtk_posall[i], pos[i]);
+		}
+	}
+}
 
+
+extern void view_refresh(struct view_s* v)
+{
 	v->invalid = true;
 
 	long size = md_calc_size(DIMS, v->dims);
@@ -194,13 +232,19 @@ extern gboolean refresh_callback(GtkWidget *widget, gpointer data)
 	v->max = max;
 
 	update_view(v);
+}
 
+extern gboolean refresh_callback(GtkWidget *widget, gpointer data)
+{
+	UNUSED(widget);
+	view_refresh(data);
 	return FALSE;
 }
 
 
 extern gboolean geom_callback(GtkWidget *widget, gpointer data)
 {
+	UNUSED(widget);
 	struct view_s* v = data;
 
 	for (int j = 0; j < DIMS; j++) {
@@ -245,6 +289,7 @@ extern gboolean geom_callback(GtkWidget *widget, gpointer data)
 	v->yzoom = zoom;
 
 	v->flip = gtk_combo_box_get_active(v->gtk_flip);
+	v->interpolation = gtk_combo_box_get_active(v->gtk_interp);
 	v->transpose = gtk_toggle_tool_button_get_active(v->gtk_transpose);
 
 	if (v->transpose) {
@@ -278,6 +323,7 @@ extern gboolean geom_callback(GtkWidget *widget, gpointer data)
 
 extern gboolean window_callback(GtkWidget *widget, gpointer data)
 {
+	UNUSED(widget);
 	struct view_s* v = data;
 
 	v->mode = gtk_combo_box_get_active(v->gtk_mode);
@@ -301,61 +347,172 @@ extern gboolean window_callback(GtkWidget *widget, gpointer data)
 	return FALSE;
 }
 
+static void update_buf_view(struct view_s* v)
+{
+	update_buf(v->xdim, v->ydim, DIMS, v->dims, v->strs, v->pos, v->flip, v->interpolation, v->xzoom, v->yzoom,
+		   v->rgbw, v->rgbh, v->data, v->buf);
+}
+
+
+
 extern gboolean save_callback(GtkWidget *widget, gpointer data)
 {
+	UNUSED(widget);
 	struct view_s* v = data;
+	
+	// Prepare output filename
+	unsigned int bufsize = 255;
+	char name[bufsize];
+	char* cur = name;
+	const char* end = name + bufsize;
+	cur += snprintf(cur, end - cur, "%s", v->name);
+	char dir[bufsize];
+	strncpy(dir, v->name, bufsize);
+
+	for ( int i = 0; i < DIMS; i++) {
+		if ( v->dims[i] != 1 && i != v->xdim && i != v->ydim ){
+			cur += snprintf(cur, end - cur, "_%s_%04ld", get_spec(i), v->pos[i]);
+		}
+	}
+	cur += snprintf(cur, end - cur, ".png");
+
+	v->dialog = gtk_file_chooser_dialog_new ("Save File",
+                                      v->window,
+				      GTK_FILE_CHOOSER_ACTION_SAVE,
+                                      "Cancel",
+                                      GTK_RESPONSE_CANCEL,
+                                      "Save",
+                                      GTK_RESPONSE_ACCEPT,
+                                      NULL);
+	v->chooser = GTK_FILE_CHOOSER (v->dialog);
+
+	gtk_file_chooser_set_current_name (v->chooser, basename(name));
+	
+	// Outputfolder = Inputfolder
+	gtk_file_chooser_set_current_folder (v->chooser, dirname(dir));
+	gtk_file_chooser_set_do_overwrite_confirmation (v->chooser, TRUE);
+
+	gint res = gtk_dialog_run (GTK_DIALOG (v->dialog));
+
+	if (res == GTK_RESPONSE_ACCEPT) {
+		// export single image
+		char *filename = gtk_file_chooser_get_filename (v->chooser);
+		if (CAIRO_STATUS_SUCCESS != cairo_surface_write_to_png(v->source, filename))
+			gtk_entry_set_text(v->gtk_entry, "Error: writing image file.\n");
+
+		gtk_entry_set_text(v->gtk_entry, "Saved!");
+		g_free (filename);
+	}
 
-	if (CAIRO_STATUS_SUCCESS != cairo_surface_write_to_png(v->source, "save.png"))
-		gtk_entry_set_text(v->gtk_entry, "Error: writing image file.\n");
-
-	gtk_entry_set_text(v->gtk_entry, "Saved to: save.png");
 
+	gtk_widget_destroy (v->dialog);
 	return FALSE;
 }
 
-
-extern gboolean draw_callback(GtkWidget *widget, cairo_t *cr, gpointer data)
+extern gboolean save_movie_callback(GtkWidget *widget, gpointer data)
 {
+	UNUSED(widget);
 	struct view_s* v = data;
 
-	if (v->invalid) {
+	unsigned int bufsize = 255;
+	char dir[bufsize];
+	strncpy(dir, v->name, bufsize);
 
-		double dpos[DIMS];
-		for (int i = 0; i < DIMS; i++)
-			dpos[i] = v->pos[i];
+	int frame_dim = 10;
 
-		dpos[v->xdim] = 0.;
-		dpos[v->ydim] = 0.;
+	v->dialog = gtk_file_chooser_dialog_new("Export movie to folder",
+						v->window,
+						GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
+						"Cancel",
+						GTK_RESPONSE_CANCEL,
+						"Export",
+						GTK_RESPONSE_ACCEPT,
+						NULL);
 
-		double dx[DIMS];
-		for (int i = 0; i < DIMS; i++)
-			dx[i] = 0.;
+	v->chooser = GTK_FILE_CHOOSER(v->dialog);
+	// Outputfolder = Inputfolder
+	gtk_file_chooser_set_current_folder(v->chooser, dirname(dir));
 
-		double dy[DIMS];
-		for (int i = 0; i < DIMS; i++)
-			dy[i] = 0.;
+	gint res = gtk_dialog_run (GTK_DIALOG (v->dialog));
 
-		dx[v->xdim] = 1.;
-		dy[v->ydim] = 1.;
+	if (res == GTK_RESPONSE_ACCEPT) {
 
+		char *chosen_dir = gtk_file_chooser_get_filename(v->chooser);
+		char output_name[bufsize];
 
-		if ((XY == v->flip) || (XO == v->flip)) {
+		for (unsigned int f = 0; f < v->dims[frame_dim]; f++) {
 
-			dpos[v->xdim] = v->dims[v->xdim] - 1;
-			dx[v->xdim] *= -1.;
-		}
+			v->pos[frame_dim] = f;
+			update_buf_view(v);
+
+			draw(v->rgbw, v->rgbh, v->rgbstr, (unsigned char(*)[v->rgbw][v->rgbstr / 4][4])v->rgb,
+				v->mode, 1. / v->max, v->winlow, v->winhigh, v->phrot,
+				v->rgbw, v->buf);
 
-		if ((XY == v->flip) || (OY == v->flip)) {
+			char suff[16];
+			snprintf(suff, 16, "/mov-%04d.png", f);
+			strncpy(output_name, chosen_dir, bufsize - 16);
+			strncat(output_name, suff, 16);
 
-			dpos[v->ydim] = v->dims[v->ydim] - 1;
-			dy[v->ydim] *= -1.;
+			if (CAIRO_STATUS_SUCCESS != cairo_surface_write_to_png(v->source, output_name))
+				gtk_entry_set_text(v->gtk_entry, "Error: writing image file.\n");
 		}
 
-		dx[v->xdim] = dx[v->xdim] / v->xzoom;
-		dy[v->ydim] = dy[v->ydim] / v->yzoom;
+		g_free(chosen_dir);
+		gtk_entry_set_text(v->gtk_entry, "Movie exported.");
+	}
+
+	gtk_widget_destroy (v->dialog);
+
+	return FALSE;
+}
+
+
+struct xy_s { float x; float y; };
 
-		resample(v->rgbw, v->rgbh, v->rgbw, v->buf,
-			DIMS, dpos, dx, dy, v->dims, v->strs, v->data);
+static struct xy_s pos2screen(const struct view_s* v, /*const+*/float (*pos)[DIMS])
+{
+	float x = (*pos)[v->xdim];
+	float y = (*pos)[v->ydim];
+
+	if ((XY == v->flip) || (XO == v->flip))
+		x = v->dims[v->xdim] - 1 - x;
+
+	if ((XY == v->flip) || (OY == v->flip))
+		y = v->dims[v->ydim] - 1 - y;
+
+	x *= v->xzoom;
+	y *= v->yzoom;
+
+	return (struct xy_s){ x, y };
+}
+
+static void screen2pos(const struct view_s* v, float (*pos)[DIMS], struct xy_s xy)
+{
+	for (unsigned int i = 0; i < DIMS; i++)
+		(*pos)[i] = v->pos[i];
+
+	float x = xy.x / v->xzoom;
+	float y = xy.y / v->yzoom;
+
+	if ((XY == v->flip) || (XO == v->flip))
+		x = v->dims[v->xdim] - 1 - x;
+
+	if ((XY == v->flip) || (OY == v->flip))
+		y = v->dims[v->ydim] - 1 - y;
+
+	(*pos)[v->xdim] = x;
+	(*pos)[v->ydim] = y;
+}
+
+extern gboolean draw_callback(GtkWidget *widget, cairo_t *cr, gpointer data)
+{
+	UNUSED(widget);
+	struct view_s* v = data;
+
+	if (v->invalid) {
+
+		update_buf_view(v);
 
 		v->invalid = false;
 		v->rgb_invalid = true;
@@ -363,7 +520,7 @@ extern gboolean draw_callback(GtkWidget *widget, cairo_t *cr, gpointer data)
 
 	if (v->rgb_invalid) {
 
-		draw(v->rgbw, v->rgbh, v->rgbstr, v->rgb,
+		draw(v->rgbw, v->rgbh, v->rgbstr, (unsigned char(*)[v->rgbw][v->rgbstr / 4][4])v->rgb,
 			v->mode, 1. / v->max, v->winlow, v->winhigh, v->phrot,
 			v->rgbw, v->buf);
 
@@ -374,6 +531,24 @@ extern gboolean draw_callback(GtkWidget *widget, cairo_t *cr, gpointer data)
 
 	// add_text(v->source, 3, 3, 10, v->name);
 
+	if (v->cross_hair) {
+
+		float posi[DIMS];
+		for (unsigned int i = 0; i < DIMS; i++)
+			posi[i] = v->pos[i];
+
+		struct xy_s xy = pos2screen(v, &posi);
+
+		draw_line(v->rgbw, v->rgbh, v->rgbstr, (unsigned char (*)[v->rgbw][v->rgbstr / 4][4])v->rgb,
+				0, (int)xy.y, v->rgbw - 1, (int)xy.y, (v->xdim > v->ydim) ? &color_red : &color_blue);
+
+		draw_line(v->rgbw, v->rgbh, v->rgbstr, (unsigned char (*)[v->rgbw][v->rgbstr / 4][4])v->rgb,
+				(int)xy.x, 0, (int)xy.x, v->rgbh - 1, (v->xdim < v->ydim) ? &color_red : &color_blue);
+
+//		float coords[4][2] = { { 0, 0 }, { 100, 0 }, { 0, 100 }, { 100, 100 } };
+//		draw_grid(v->rgbw, v->rgbh, v->rgbstr, (unsigned char (*)[v->rgbw][v->rgbstr / 4][4])v->rgb, &coords, 4, &color_white);
+	}
+
 	cairo_set_source_surface(cr, v->source, 0, 0);
 	cairo_paint(cr);
 	return FALSE;
@@ -382,7 +557,7 @@ extern gboolean draw_callback(GtkWidget *widget, cairo_t *cr, gpointer data)
 
 
 
-struct view_s* create_view(const char* name, long* pos, const long dims[DIMS], const complex float* data)
+struct view_s* create_view(const char* name, const long pos[DIMS], const long dims[DIMS], const complex float* data)
 {
 	long sq_dims[2] = { 0 };
 
@@ -399,12 +574,15 @@ struct view_s* create_view(const char* name, long* pos, const long dims[DIMS], c
 	v->next = v->prev = v;
 	v->sync = true;
 
+	v->cross_hair = false;
+
 	v->name = name;
-	v->pos = pos;
 	v->max = 1.;
 
-	if (NULL == v->pos)
-		v->pos = xmalloc(DIMS * sizeof(long));
+	v->pos = xmalloc(DIMS * sizeof(long));
+
+	for (int i = 0; i < DIMS; i++)
+		v->pos[i] = (NULL != pos) ? pos[i] : 0;
 
 	v->xdim = sq_dims[0];
 	v->ydim = sq_dims[1];
@@ -421,10 +599,6 @@ struct view_s* create_view(const char* name, long* pos, const long dims[DIMS], c
 	md_calc_strides(DIMS, v->strs, dims, sizeof(complex float));
 	v->data = data;
 
-	for (int i = 0; i < DIMS; i++)
-		v->pos[i] = 0;
-
-
 	v->winlow = 0.;
 	v->winhigh = 1.;
 	v->phrot = 0.;
@@ -453,8 +627,9 @@ static void delete_view(struct view_s* v)
 }
 
 
-extern gboolean toggle_sync(GtkWidget *widget, GtkToggleButton* button, gpointer data)
+extern gboolean toggle_sync(GtkToggleButton* button, gpointer data)
 {
+	UNUSED(button);
 	struct view_s* v = data;
 	v->sync = !v->sync;
 
@@ -462,17 +637,15 @@ extern gboolean toggle_sync(GtkWidget *widget, GtkToggleButton* button, gpointer
 }
 
 
-static void update_status_bar(struct view_s* v, int x2, int y2)
+static void update_status_bar(struct view_s* v, /*const*/ float (*pos)[DIMS])
 {
-	float pos[DIMS];
+	int x2 = (*pos)[v->xdim];
+	int y2 = (*pos)[v->ydim];
 
-	for (int i = 0; i < DIMS; i++)
-		pos[i] = v->pos[i];
-
-	pos[v->xdim] = x2;
-	pos[v->ydim] = y2;
+	(*pos)[v->xdim] = x2;
+	(*pos)[v->ydim] = y2;
 
-	complex float val = sample(DIMS, pos, v->dims, v->strs, v->data);
+	complex float val = sample(DIMS, *pos, v->dims, v->strs, v->interpolation, v->data);
 
 	// FIXME: make sure this matches exactly the pixel
 	char buf[100];
@@ -483,37 +656,50 @@ static void update_status_bar(struct view_s* v, int x2, int y2)
 }
 
 
+extern void set_position(struct view_s* v, unsigned int dim, unsigned int p)
+{
+	v->pos[dim] = p;
+
+	gtk_adjustment_set_value(v->gtk_posall[dim], p);
+
+	for (struct view_s* v2 = v->next; v2 != v; v2 = v2->next)
+		if (v->sync && v2->sync)
+			gtk_adjustment_set_value(v2->gtk_posall[dim], p);
+}
+
+
 extern gboolean button_press_event(GtkWidget *widget, GdkEventButton *event, gpointer data)
 {
+	UNUSED(widget);
 	struct view_s* v = data;
 
-	int y = event->y;
-	int x = event->x;
+	struct xy_s xy = { event->x, event->y };
 
-	int x2 = x / v->xzoom;
-	int y2 = y / v->yzoom;
+	float pos[DIMS];
+	screen2pos(v, &pos, xy);
 
-	if (event->button == GDK_BUTTON_SECONDARY) {
+	if (event->button == GDK_BUTTON_PRIMARY) {
 
-		v->pos[v->xdim] = x2;
-		v->pos[v->ydim] = y2;
+		v->cross_hair = false;
 
-		gtk_adjustment_set_value(v->gtk_posall[v->xdim], x2);
-		gtk_adjustment_set_value(v->gtk_posall[v->ydim], y2);
+		v->rgb_invalid = true;
+		update_view(v);
+	}
 
-		update_status_bar(v, x2, y2);
+	if (event->button == GDK_BUTTON_SECONDARY) {
 
-		for (struct view_s* v2 = v->next; v2 != v; v2 = v2->next) {
+		v->cross_hair = true;
 
-			if (v->sync && v2->sync) {
+		set_position(v, v->xdim, pos[v->xdim]);
+		set_position(v, v->ydim, pos[v->ydim]);
 
-				gtk_adjustment_set_value(v2->gtk_posall[v->xdim], x2);
-				gtk_adjustment_set_value(v2->gtk_posall[v->ydim], y2);
+		update_status_bar(v, &pos);
 
-				update_status_bar(v2, x2, y2);
-			}
-		}
+		for (struct view_s* v2 = v->next; v2 != v; v2 = v2->next)
+			if (v->sync && v2->sync)
+				update_status_bar(v2, &pos);
 	}
+
 	return FALSE;
 }
 
@@ -521,6 +707,7 @@ extern gboolean button_press_event(GtkWidget *widget, GdkEventButton *event, gpo
 
 extern gboolean motion_notify_event(GtkWidget *widget, GdkEventMotion *event, gpointer data)
 {
+	UNUSED(widget);
 	struct view_s* v = data;
 
 	int y = event->y;
@@ -578,6 +765,8 @@ static int nr_windows = 0;
 
 extern gboolean window_close(GtkWidget *widget, GdkEvent* event, gpointer data)
 {
+	UNUSED(widget);
+	UNUSED(event);
 	struct view_s* v = data;
 
 	delete_view(v);
@@ -591,7 +780,7 @@ extern gboolean window_close(GtkWidget *widget, GdkEvent* event, gpointer data)
 
 
 
-extern struct view_s* window_new(const char* name, long* pos, const long dims[DIMS], const complex float* x)
+extern struct view_s* window_new(const char* name, const long pos[DIMS], const long dims[DIMS], const complex float* x)
 {
 	struct view_s* v = create_view(name, pos, dims, x);
 
@@ -622,7 +811,12 @@ extern struct view_s* window_new(const char* name, long* pos, const long dims[DI
 	v->gtk_flip = GTK_COMBO_BOX(gtk_builder_get_object(builder, "flip"));
 	gtk_combo_box_set_active(v->gtk_flip, 0);
 
+	v->gtk_interp = GTK_COMBO_BOX(gtk_builder_get_object(builder, "interp"));
+	gtk_combo_box_set_active(v->gtk_interp, 0);
+    
 	v->gtk_transpose = GTK_TOGGLE_TOOL_BUTTON(gtk_builder_get_object(builder, "transpose"));
+	v->gtk_fit = GTK_TOGGLE_TOOL_BUTTON(gtk_builder_get_object(builder, "fit"));
+	gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(v->gtk_fit), TRUE);
 
 	for (int j = 0; j < DIMS; j++) {
 
@@ -630,7 +824,7 @@ extern struct view_s* window_new(const char* name, long* pos, const long dims[DI
 		snprintf(pname, 10, "pos%02d", j);
 		v->gtk_posall[j] = GTK_ADJUSTMENT(gtk_builder_get_object(builder, pname));
 		gtk_adjustment_set_upper(v->gtk_posall[j], v->dims[j] - 1);
-		gtk_adjustment_set_value(v->gtk_posall[j], 0);
+		gtk_adjustment_set_value(v->gtk_posall[j], v->pos[j]);
 
 		snprintf(pname, 10, "check%02d", j);
 		v->gtk_checkall[j] = GTK_CHECK_BUTTON(gtk_builder_get_object(builder, pname));
@@ -639,17 +833,22 @@ extern struct view_s* window_new(const char* name, long* pos, const long dims[DI
 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(v->gtk_checkall[v->xdim]), TRUE);
 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(v->gtk_checkall[v->ydim]), TRUE);
 
+#if 0
+	gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(builder, "toolbar1")));
+	gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(builder, "toolbar2")));
+	gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(builder, "entry")));
+#endif
 	gtk_builder_connect_signals(builder, v);
 
 	GtkWindow* window = GTK_WINDOW(gtk_builder_get_object(builder, "window1"));
 	g_object_unref(G_OBJECT(builder));
-
+	v->window = window;
 	gtk_window_set_title(window, name);
-
 	gtk_widget_show(GTK_WIDGET(window));
 
 	nr_windows++;
 
+//	fit_callback(NULL, v);
 	refresh_callback(NULL, v);
 	geom_callback(NULL, v);
 	window_callback(NULL, v);
@@ -657,7 +856,6 @@ extern struct view_s* window_new(const char* name, long* pos, const long dims[DI
 	return v;
 }
 
-
 void window_connect_sync(struct view_s* v, struct view_s* v2)
 {
 	// add to linked list for sync
@@ -669,17 +867,23 @@ void window_connect_sync(struct view_s* v, struct view_s* v2)
 	window_callback(NULL, v);
 }
 
-extern gboolean window_clone(GtkWidget *widget, gpointer data)
+struct view_s* view_clone(struct view_s* v, const long pos[DIMS])
 {
-	struct view_s* v = data;
-
-	struct view_s* v2 = window_new(v->name, v->pos, v->dims, v->data);
+	struct view_s* v2 = window_new(v->name, pos, v->dims, v->data);
 
 	window_connect_sync(v, v2);
 
-	return FALSE;
+	return v2;
 }
 
+extern gboolean window_clone(GtkWidget *widget, gpointer data)
+{
+	UNUSED(widget);
+	struct view_s* v = data;
 
+	view_clone(v, v->pos);
+
+	return FALSE;
+}
 
 


=====================================
src/view.h
=====================================
--- a/src/view.h
+++ b/src/view.h
@@ -5,6 +5,10 @@
 
 struct view_s;
 
-extern struct view_s* window_new(const char* name, long* pos, const long dims[DIMS], const complex float* x);
+extern struct view_s* window_new(const char* name, const long pos[DIMS], const long dims[DIMS], const complex float* x);
+
 extern void window_connect_sync(struct view_s* a, struct view_s* b);
 
+extern void view_refresh(struct view_s* v);
+extern void view_setpos(struct view_s* v, unsigned int flags, const long pos[DIMS]);
+extern struct view_s* view_clone(struct view_s* v, const long pos[DIMS]);


=====================================
src/viewer.ui
=====================================
--- a/src/viewer.ui
+++ b/src/viewer.ui
@@ -15,15 +15,24 @@
     </columns>
     <data>
       <row>
-        <col id="0" translatable="yes">MAGNITUDE</col>
+        <col id="0" translatable="yes">MAGNITUDE (gray)</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">MAGNITUDE (viridis)</col>
       </row>
       <row>
         <col id="0" translatable="yes">COMPLEX</col>
       </row>
       <row>
+        <col id="0" translatable="yes">COMPLEX (MYGBM)</col>
+      </row>
+      <row>
         <col id="0" translatable="yes">PHASE</col>
       </row>
       <row>
+        <col id="0" translatable="yes">PHASE (MYGBM)</col>
+      </row>
+      <row>
         <col id="0" translatable="yes">REAL</col>
       </row>
       <row>
@@ -51,6 +60,20 @@
       </row>
     </data>
   </object>
+  <object class="GtkListStore" id="liststore3">
+    <columns>
+      <!-- column-name text -->
+      <column type="gchararray"/>
+    </columns>
+    <data>
+      <row>
+        <col id="0" translatable="yes">NLIN</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">NEAREST</col>
+      </row>
+    </data>
+  </object>
   <object class="GtkAdjustment" id="pos00">
     <property name="step_increment">1</property>
     <property name="page_increment">10</property>
@@ -134,6 +157,8 @@
   </object>
   <object class="GtkWindow" id="window1">
     <property name="can_focus">False</property>
+    <property name="default_height">600</property>
+    <property name="default_width">600</property>
     <signal name="delete-event" handler="window_close" swapped="no"/>
     <child>
       <object class="GtkBox" id="box1">
@@ -196,21 +221,36 @@
               </packing>
             </child>
             <child>
-              <object class="GtkToolItem" id="toolbutton4">
+              <object class="GtkToggleToolButton" id="fit">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label" translatable="yes">fit</property>
+                <property name="use_underline">True</property>
+                <property name="stock_id">gtk-zoom-fit</property>
+                <signal name="clicked" handler="fit_callback" swapped="no"/>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="homogeneous">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkToolItem" id="toolbutton11">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
                 <child>
-                  <object class="GtkButton" id="fit">
+                  <object class="GtkComboBox" id="flip">
                     <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="receives_default">False</property>
-                    <signal name="clicked" handler="fit_callback" swapped="no"/>
+                    <property name="can_focus">False</property>
+                    <property name="halign">start</property>
+                    <property name="model">liststore2</property>
+                    <property name="active">0</property>
+                    <signal name="changed" handler="geom_callback" swapped="no"/>
                     <child>
-                      <object class="GtkImage" id="image2">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="stock">gtk-zoom-fit</property>
-                      </object>
+                      <object class="GtkCellRendererText" id="cellrenderertext2"/>
+                      <attributes>
+                        <attribute name="text">0</attribute>
+                      </attributes>
                     </child>
                   </object>
                 </child>
@@ -221,19 +261,19 @@
               </packing>
             </child>
             <child>
-              <object class="GtkToolItem" id="toolbutton11">
+              <object class="GtkToolItem" id="toolbutton15">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
                 <child>
-                  <object class="GtkComboBox" id="flip">
+                  <object class="GtkComboBox" id="interp">
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
                     <property name="halign">start</property>
-                    <property name="model">liststore2</property>
+                    <property name="model">liststore3</property>
                     <property name="active">0</property>
                     <signal name="changed" handler="geom_callback" swapped="no"/>
                     <child>
-                      <object class="GtkCellRendererText" id="cellrenderertext2"/>
+                      <object class="GtkCellRendererText" id="cellrenderertext3"/>
                       <attributes>
                         <attribute name="text">0</attribute>
                       </attributes>
@@ -286,6 +326,31 @@
               </packing>
             </child>
             <child>
+              <object class="GtkToolItem" id="toolbutton14">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <child>
+                  <object class="GtkButton" id="button3">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <signal name="clicked" handler="save_movie_callback" swapped="no"/>
+                    <child>
+                      <object class="GtkImage" id="image4">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+			<property name="icon-name">media-record</property>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="homogeneous">True</property>
+              </packing>
+            </child>
+            <child>
               <object class="GtkToolButton" id="toolbutton12">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
@@ -489,7 +554,7 @@
                 <property name="can_focus">True</property>
                 <property name="shadow_type">in</property>
                 <property name="min_content_width">100</property>
-                <property name="min_content_height">200</property>
+                <property name="min_content_height">100</property>
                 <child>
                   <object class="GtkViewport" id="viewport1">
                     <property name="visible">True</property>
@@ -502,6 +567,7 @@
                         <signal name="button-press-event" handler="button_press_event" swapped="no"/>
                         <signal name="draw" handler="draw_callback" swapped="no"/>
                         <signal name="motion-notify-event" handler="motion_notify_event" swapped="no"/>
+			<signal name="configure-event" handler="configure_callback" swapped="no"/>
                       </object>
                     </child>
                   </object>


=====================================
viewer.png
=====================================
Binary files /dev/null and b/viewer.png differ



View it on GitLab: https://salsa.debian.org/med-team/bart-view/compare/2121cb97e01578d768c85db62d4efa3f73611a5d...187c48cbcb65cb09449e17a8e55af3442af1cdf1

---
View it on GitLab: https://salsa.debian.org/med-team/bart-view/compare/2121cb97e01578d768c85db62d4efa3f73611a5d...187c48cbcb65cb09449e17a8e55af3442af1cdf1
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.alioth.debian.org/pipermail/debian-med-commit/attachments/20180217/c3c449e1/attachment-0001.html>


More information about the debian-med-commit mailing list