[med-svn] [Git][med-team/bart-view][upstream] 25 commits: BUGFIX: screen2pos: correct calculation of x and y

Martin Uecker (@uecker-guest) gitlab at salsa.debian.org
Mon Oct 24 19:08:27 BST 2022



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


Commits:
93838492 by Christian Holme at 2019-07-18T17:00:28+02:00
BUGFIX: screen2pos: correct calculation of x and y

This commit corrects the calculation of the x and y position in
`screen2pos()` for flipped coordinates.

Previously, the values calculated in `screen2pos()` were truncated to
integers later (either in passing them to `set_position()` or in
`update_status_bar()`). Now, they are explicitly rounded in
`screen2pos()`.

Furthermore, this commits removes the truncation in
`update_status_bar()` and marks the `pos` argument as const where
appropriate.

- - - - -
bd836a29 by Christian Holme at 2019-07-18T17:05:49+02:00
view.c: shift crosshair lines to pixel center

- - - - -
f3764f09 by Christian Holme at 2019-07-18T17:05:49+02:00
make status bar dismissible

Similar to the crosshair, the status bar is now also cleared when
clicking the primary button. For this, the new function
`clear_status_bar` is introduced.

- - - - -
c00f7259 by Christian Holme at 2019-07-18T17:06:43+02:00
change status bar when changing pos

Previously, the status bar was only updated when pressing the secondary
mouse button, but not when changing the position through one of the spin
buttons.

Now, not only the crosshair but also the status bar is updated when the
position is changed through a spin button.

The `clear_status_bar` and `update_status_bar` functions are moved
around to avoid forward declarations.

- - - - -
70883358 by Martin Uecker at 2019-07-18T21:08:20+02:00
fix windowing instead

- - - - -
34c3a59a by Martin Uecker at 2019-07-18T21:08:21+02:00
turn off use of deprecated function

- - - - -
14551d78 by Martin Uecker at 2019-07-22T16:18:12+02:00
minor fixes and style

- - - - -
30f13e7e by Martin Uecker at 2019-07-22T16:18:12+02:00
add geometry field

- - - - -
4286844c by Martin Uecker at 2019-07-22T16:18:12+02:00
maintain geom_current pointer

- - - - -
e947c07f by Martin Uecker at 2019-07-22T16:18:39+02:00
bart style

- - - - -
d16f06ef by Martin Uecker at 2019-07-22T16:18:39+02:00
shorter file names

- - - - -
c8359a6f by Martin Uecker at 2019-07-23T19:52:43+02:00
line integral convolution

- - - - -
47b3fa27 by Martin Uecker at 2019-07-23T19:53:18+02:00
plotting mode

- - - - -
23b28b18 by Martin Uecker at 2020-05-06T11:42:46+02:00
reorder libraries

- - - - -
793dd8de by malits at 2020-05-09T08:35:37+02:00
Makefile and README modifications for recent versions of OS X

- - - - -
2fcd6880 by Martin Uecker at 2020-05-09T08:55:15+02:00
update README

- - - - -
6ffa4566 by Martin Uecker at 2020-05-09T14:28:07+02:00
clang support & Makefile improvements

- - - - -
6510f9fb by Christian Holme at 2021-05-07T09:46:20+02:00
link with -lrt

as of bart commit c5b91ba7f6d66472c882d01124f47cade6b0476d
we need to also link the rt library.

- - - - -
26ee29db by Christian Holme at 2021-05-07T09:48:41+02:00
make cuda lib directory configurable

For consistency with bart

- - - - -
16ad0397 by Christian Holme at 2021-06-21T09:47:59+02:00
changes for new positional arguments in bart

- - - - -
77f12745 by Christian Holme at 2021-06-21T09:53:27+02:00
Makefile: allow compilation with CUDA

To link view to a bart version compiled with CUDA support, view also
needs to link with CUDA.

Further, to properly set CUDA_L, Makefile.local needs to set
CUDA=1 and CUDA_BASE before it is initialized in the Makefile.

- - - - -
1e8abf21 by Martin Uecker at 2022-10-24T19:04:52+02:00
rewrite generation of file names

- - - - -
fb51e11e by Martin Uecker at 2022-10-24T19:05:03+02:00
missing braces

- - - - -
80432a48 by Martin Uecker at 2022-10-24T19:14:56+02:00
require BART 0.8.00

- - - - -
011f14a0 by Martin Uecker at 2022-10-24T19:15:34+02:00
copyright years

- - - - -


11 changed files:

- LICENSE
- Makefile
- README
- README.md
- src/cfl2png.c
- src/draw.c
- src/draw.h
- src/main.c
- src/view.c
- src/view.h
- src/viewer.ui


Changes:

=====================================
LICENSE
=====================================
@@ -1,4 +1,4 @@
-Copyright (c) 2015. Martin Uecker.
+Copyright (c) 2015-2022. Martin Uecker.
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without


=====================================
Makefile
=====================================
@@ -1,7 +1,10 @@
 
 
+-include Makefile.local
+
 CUDA?=0
 CUDA_BASE ?= /usr/local/cuda
+CUDA_LIB ?= lib
 
 BUILDTYPE = Linux
 UNAME = $(shell uname -s)
@@ -20,25 +23,43 @@ TOOLBOX_LIB=$(TOOLBOX_PATH)/lib/
 endif
 
 
-CC ?= gcc
-CFLAGS ?= -Wall -O2
-CFLAGS += -std=c11 -fopenmp
+ifeq ($(origin CC), default)
+	CC = gcc
+endif
+
+CFLAGS = -Wall -O2
+
+
+ifeq ($(BUILDTYPE), MacOSX)
+	CFLAGS += -std=c11 -Xpreprocessor -fopenmp
+else
+	CFLAGS += -std=c11 -fopenmp
+endif
+
+# clang
+
+ifeq ($(findstring clang, $(CC)), clang)
+	CFLAGS += -fblocks
+	LDFLAGS += -lBlocksRuntime
+endif
 
 
 ifeq ($(CUDA),1)
-    CUDA_L := -L$(CUDA_BASE)/lib64 -lcufft -lcudart -lcublas
+    CUDA_L := -L$(CUDA_BASE)/$(CUDA_LIB) -lcufft -lcudart -lcublas
 else
     CUDA_L :=
 endif
 
 
+EXPDYN = -rdynamic
+
+
 ifeq ($(BUILDTYPE), MacOSX)
-    EXPDYN = -Wl,-export_dynamic
+	LDFLAGS += -L/opt/local/lib -lm -lpng -lomp -lrt
 else
-    EXPDYN = -export-dynamic
+	LDFLAGS += -lm -lpng -lrt
 endif
 
--include Makefile.local
 
 
 all: view cfl2png
@@ -47,10 +68,10 @@ src/viewer.inc: src/viewer.ui
 	@echo "STRINGIFY(`cat src/viewer.ui`)" > src/viewer.inc
 
 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
+	$(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)/libgeom.a $(TOOLBOX_LIB)/libnum.a $(CUDA_L) $(LDFLAGS)
 
 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
+	$(CC) $(CFLAGS) $(EXPDYN) -o cfl2png -I$(TOOLBOX_INC) src/cfl2png.c src/draw.c $(TOOLBOX_LIB)/libmisc.a  $(TOOLBOX_LIB)/libgeom.a $(TOOLBOX_LIB)/libnum.a $(CUDA_L) $(LDFLAGS)
 
 install:
 	install view $(DESTDIR)/usr/lib/bart/commands/


=====================================
README
=====================================
@@ -6,13 +6,16 @@ the Berkeley Advanced Reconstruction Toolbox (BART).
 
 https://mrirecon.github.io/bart/
 
-Requires BART up to commit e4df99aa75e0344931ba2e76d9ae052b02da498f
+Requires BART 0.8.00 or later.
+
 
 Mac OS X:
 
 sudo port install pkgconfig
 sudo port install gtk3
 sudo port install adwaita-icon-theme
+sudo port install libomp
+
 
 Linux:
 sudo apt-get install libgtk-3-dev
@@ -20,6 +23,8 @@ sudo apt-get install libgtk-3-dev
 
 
 Compile with make after setting the TOOLBOX_PATH
-environment variable.
+environment variable to the directory where BART
+is installed.
+
 
 


=====================================
README.md
=====================================
@@ -11,13 +11,15 @@ https://mrirecon.github.io/bart/
 
 Installation:
 
-Requires BART up to commit e4df99aa75e0344931ba2e76d9ae052b02da498f
+Requires BART 0.8.00 or later.
+
 
 Mac OS X:
 
 sudo port install pkgconfig
 sudo port install gtk3
 sudo port install adwaita-icon-theme
+sudo port install libomp
 
 Linux:
 sudo apt-get install libgtk-3-dev
@@ -25,6 +27,20 @@ sudo apt-get install libgtk-3-dev
 
 
 Compile with make after setting the TOOLBOX_PATH
-environment variable.
+environment variable to the directory where BART
+is installed.
+
+### Usage
+
+`view <images>...`
+
+### Troubleshooting
+
+If an error is raised along the lines of
+`Gtk-WARNING **: cannot open display`, ensure X11 is installed
+and running. On later versions of OS X, you may
+need ![XQuartz](https://www.xquartz.org/) for View to run.
 
+Set the environment variable `DISPLAY=":0"`, run XQuartz,
+and then retry `view`.
 


=====================================
src/cfl2png.c
=====================================
@@ -5,9 +5,6 @@
 #include <string.h>
 #include <strings.h>
 
-#undef MAX
-#undef MIN
-
 #include "num/multind.h"
 #include "num/init.h"
 
@@ -18,21 +15,35 @@
 #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);
+#ifndef DIMS
+#define DIMS 16
+#endif
+
+
+static 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 main(int argc, char* argv[argc])
 {
+	const char* in_file;
+	const char* out_prefix;
+
+	struct arg_s args[] = {
+
+		ARG_INFILE(true, &in_file, "input"),
+		ARG_STRING(true, &out_prefix, "output_prefix"),
+	};
+
+
 	int xdim = 0;
 	int ydim = 0;
 	float windowing[2] = {0.f, 1.f};
@@ -76,15 +87,12 @@ int main(int argc, char* argv[])
 		OPT_INT('d', &debug_level, "level", "Debug level"),
 	};
 
-	cmdline(&argc, argv, 2, 1000, usage_str, help_str, ARRAY_SIZE(opts), opts);
+	cmdline(&argc, argv, ARRAY_SIZE(args), args, 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));
 
@@ -92,7 +100,7 @@ int main(int argc, char* argv[])
 	 * If the filename ends in ".hdr", ".cfl" or just "." (from
 	 * tab-completion), just replace the "." with a \0-character.
 	 */
-	char* dot = strrchr(infile, '.');
+	char* dot = strrchr(in_file, '.');
 
 	if (   (NULL != dot)
             && (   !strcmp(dot, ".cfl")
@@ -102,9 +110,9 @@ int main(int argc, char* argv[])
 
 
 	long dims[DIMS];
-	complex float* idata = load_cfl(infile, DIMS, dims);
+	complex float* idata = load_cfl(in_file, DIMS, dims);
 
-	char* ext = rindex(output_prefix, '.');
+	char* ext = rindex(out_prefix, '.');
 
 	if (NULL != ext) {
 
@@ -114,7 +122,7 @@ int main(int argc, char* argv[])
 			*ext = '\0';
 	}
 
-	export_images(output_prefix, xdim, ydim, windowing, zoom, mode, flip, interpolation, dims, idata);
+	export_images(out_prefix, xdim, ydim, windowing, zoom, mode, flip, interpolation, dims, idata);
 
 
 	unmap_cfl(DIMS, dims, idata);
@@ -195,24 +203,33 @@ void export_images(const char* output_prefix, int xdim, int ydim, float windowin
 		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;
+		static const char* spec = "xyzcmnopqsfrtuvw";
+		int len = 0;
+
+		len += snprintf(NULL, 0, "%s_", output_prefix);
 
-		cur += snprintf(cur, end - cur, "%s", output_prefix);
+		for (unsigned int i = 0; i < DIMS; i++)
+			if (1 != loopdims[i])
+				len += snprintf(NULL, 0, "%c%04ld", spec[i], pos[i]);
+
+		len += snprintf(NULL, 0, ".png");
+		len++;
 
-		for (unsigned int i = 0; i < DIMS; i++) {
+		char* name = xmalloc(len);
+		int off = 0;
 
+		off += snprintf(name + off, len - off, "%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]);
-		}
+				off += snprintf(name + off, len - off, "%c%04ld", spec[i], pos[i]);
 
-		cur += snprintf(cur, end - cur, ".png");
+		off += snprintf(name + off, len - off, ".png");
 
 		debug_printf(DP_DEBUG2, "\t%s\n", name);
 
-		update_buf(xdim, ydim, DIMS, dims, strs, pos, flip, interpolation, zoom, zoom,
+		update_buf(xdim, ydim, DIMS, dims, strs, pos,
+			   flip, interpolation, zoom, zoom, false,
 			   rgbw, rgbh, idata, buf);
 
 		draw(rgbw, rgbh, rgbstr, (unsigned char(*)[rgbw][rgbstr / 4][4])rgb,
@@ -221,6 +238,8 @@ void export_images(const char* output_prefix, int xdim, int ydim, float windowin
 
 		if (0 != png_write_bgr32(name, rgbw, rgbh, 0, rgb))
 			error("Error: writing image file.\n");
+
+		xfree(name);
 	}
 
 // 	free(source);


=====================================
src/draw.c
=====================================
@@ -12,6 +12,8 @@
 
 #include "misc/misc.h"
 
+#include "geom/draw.h"
+
 #include "draw.h"
 
 #include "colormaps.inc"
@@ -29,6 +31,9 @@ static double clamp(double a, double b, double x)
 
 static double window(double a, double b, double x)
 {
+	if (a == b)
+		return (0. == x) ? 0. : 1.;
+
 	return clamp(0., 1., (x - a) / (b - a));
 }
 
@@ -44,16 +49,12 @@ static void trans_magnitude(double rgb[3], double a, double b, complex double va
 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];
-	}
+
+	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)
@@ -67,6 +68,7 @@ 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.;
@@ -76,10 +78,14 @@ static void trans_phase_MYGBM(double rgb[3], double a, double b, complex double
 {
 	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) );
+
+		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];
@@ -124,6 +130,7 @@ static complex float int_nlinear(int N, const float x[N], const long strs[N], co
 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];
 
@@ -131,13 +138,20 @@ static complex float int_nearest(int N, const float x[N], const long strs[N], co
 }
 
 
+static complex float lic_sample(int N, const float pos[N], const long dims[N], const long strs[N], const complex float* in);
+
 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)
 {
+	if (LIINCO == interpolation)
+		return lic_sample(N, pos, dims, strs, in);
+
+
 	float rem[N];
 	int div[N];
 	int D = 0;
 	long strs2[N];
 
+
 	// 0 1. [0 1] dims 2
 	for (int i = 0; i < N; i++) {
 
@@ -147,13 +161,17 @@ complex float sample(int N, const float pos[N], const long dims[N], const long s
 		if (dims[i] > 1) {
 	
 			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)) {
+
+			} else
+			if (pos[i] > (dims[i] - 1)) {
 
 				div[i] = dims[i] - 1;
+
 			} else {
 
 				div[i] = truncf(pos[i]);
@@ -178,18 +196,98 @@ complex float sample(int N, const float pos[N], const long dims[N], const long s
 
 	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);
+	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);
+	}
+}
+
+
+static complex float lic_hash(int p0, int p1)
+{
+	p0 += 12345;
+	p0 *= 2654435761U;
+	p0 += p1;
+	p0 += 12345;
+	p0 *= 2654435761U;
+	p0 ^= p0 >> 13;
+	p0 *= 2654435761U;
+	p0 ^= p0 >> 17;
+	p0 *= 2654435761U;
+
+	return (1. * (p0 % 256) + 1.i * ((p0 / 256) % 256)) / 256.;
+}
+
+// line integral convolution
+
+complex float lic_sample(int N, const float pos[N], const long dims[N], const long strs[N], const complex float* in)
+{
+	int L = 9;
+	float os = 3.;
+
+	assert(N >= 2);
+	assert(1 < dims[0]);
+	assert(1 < dims[1]);
+
+	complex float out = 0.;
+
+	float pos1[N];
+
+	complex float val = sample(N, pos1, dims, strs, NLINEAR, in);
+
+	for (int i = 0; i < N; i++)
+		pos1[i] = pos[i];
+
+	for (int i = 0; i < L; i++) {
+
+		complex float a = sample(N, pos1, dims, strs, NLINEAR, in);
+
+		a /= cabsf(a);
+
+		pos1[0] += crealf(a) / os;
+		pos1[1] += cimagf(a) / os;
+
+		int p0 = (int)(os * pos1[0]);
+		int p1 = (int)(os * pos1[1]);
+
+		out += lic_hash(p0, p1);
+	}
+
+	for (int i = 0; i < N; i++)
+		pos1[i] = pos[i];
+
+	for (int i = 0; i < L; i++) {
+
+		complex float a = sample(N, pos1, dims, strs, NLINEAR, in);
+
+		a /= cabsf(a);
+
+		pos1[0] -= crealf(a) / os;
+		pos1[1] -= cimagf(a) / os;
+
+		int p0 = (int)(os * pos1[0]);
+		int p1 = (int)(os * pos1[1]);
+
+		out += lic_hash(p0, p1);
 	}
+
+	return out * cabsf(val);
 }
 
-// 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.
+
+/* 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], enum interp_t interpolation, const complex float* in)
@@ -198,18 +296,23 @@ extern void resample(int X, int Y, long str, complex float* buf,
 		for (int y = 0; y < Y; y++) {
 
 			float pos2[N];
+
 			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
+				/* 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);
 		}
 	}
@@ -218,6 +321,8 @@ extern void resample(int X, int Y, long str, complex float* buf,
 
 
 
+
+
 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)
@@ -253,16 +358,21 @@ extern void draw(int X, int Y, int rgbstr, unsigned char (*rgbbuf)[Y][rgbstr / 4
 }
 
 
-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,
+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, bool plot,
 		long rgbw, long rgbh, const complex float* data, complex float* buf)
 {
+	if (plot)
+		rgbh = 1;
+
 	double dpos[N];
 	for (int i = 0; i < N; i++)
 		dpos[i] = pos[i];
 
 	dpos[xdim] = 0.;
-	dpos[ydim] = 0.;
+
+	if (!plot)
+		dpos[ydim] = 0.;
 
 	double dx[N];
 	for (int i = 0; i < N; i++)
@@ -273,7 +383,9 @@ void update_buf(long xdim, long ydim, int N, const long dims[N],  const long str
 		dy[i] = 0.;
 
 	dx[xdim] = 1.;
-	dy[ydim] = 1.;
+
+	if (!plot)
+		dy[ydim] = 1.;
 
 
 	if ((XY == flip) || (XO == flip)) {
@@ -284,8 +396,11 @@ void update_buf(long xdim, long ydim, int N, const long dims[N],  const long str
 
 	if ((XY == flip) || (OY == flip)) {
 
-		dpos[ydim] = dims[ydim] - 1;
-		dy[ydim] *= -1.;
+		if (!plot) {
+
+			dpos[ydim] = dims[ydim] - 1;
+			dy[ydim] *= -1.;
+		}
 	}
 
 	dx[xdim] = dx[xdim] / xzoom;
@@ -295,32 +410,6 @@ void update_buf(long xdim, long ydim, int N, const long dims[N],  const long str
 		 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 };
@@ -329,26 +418,9 @@ 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)) {
+	unsigned char color2[4] = { (*color)[0], (*color)[1], (*color)[2], 1 };
 
-			(*rgbbuf)[yi][xi][0] = (*color)[0];
-			(*rgbbuf)[yi][xi][1] = (*color)[1];
-			(*rgbbuf)[yi][xi][2] = (*color)[2];
-		}
-	}
+	bresenham_rgba(Y, X, rgbbuf, &color2, y0, x0, y1, x1);
 }
 
 
@@ -378,3 +450,56 @@ extern void draw_grid(int X, int Y, int rgbstr, unsigned char (*rgbbuf)[Y][rgbst
 
 
 
+extern void draw_plot(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)
+{
+	unsigned char bg[4] = { 255, 255, 255, 0 };
+	unsigned char half[4] = { 163, 163, 163, 255 };
+
+	assert(X == rgbstr / 4);
+	assert(X == str);
+
+	for (int i = 0; i < X; i++)
+		for (int j = 0; j < Y; j++)
+			for (int c = 0; c < 4; c++)
+				(*rgbbuf)[j][i][c] = bg[c];
+
+
+	for (int i = 1; i < 10; i++) {
+
+		bresenham_rgba(Y, X, rgbbuf, &half, 0, i * (X / 10), Y - 1, i * (X / 10));
+		bresenham_rgba(Y, X, rgbbuf, &half, i * (Y / 10), 0, i * (Y / 10), X - 1);
+	}
+
+	unsigned char colorr[4] = { 0, 0, 0, 255 };
+	unsigned char colori[4] = { 255, 255, 0, 255 };
+
+	for (int x = 0; x < X - 1; x++) {
+
+		NESTED(double, trafo, (complex float val))
+		{
+			complex float v2 = scale * val * cexpf(1.i * phrot);
+
+			return window(winlow, winhigh, crealf(v2))
+				- window(winlow, winhigh, -crealf(v2));
+		};
+
+		float rx0 = (float)(x + 0);
+		float ry0 = Y / 2 * (1. - trafo(buf[x + 0]));
+
+		float rx1 = (float)(x + 1);
+		float ry1 = Y / 2 * (1. - trafo(buf[x + 1]));
+
+		xiaolin_wu_rgba(Y, X, rgbbuf, &colorr, ry0, rx0, ry1, rx1);
+
+		float ix0 = (float)(x + 0);
+		float iy0 = Y / 2 * (1. - trafo(1.i * buf[x + 0]));
+
+		float ix1 = (float)(x + 1);
+		float iy1 = Y / 2 * (1. - trafo(1.i * buf[x + 1]));
+
+		xiaolin_wu_rgba(Y, X, rgbbuf, &colori, iy0, ix0, iy1, ix1);
+	}
+}
+


=====================================
src/draw.h
=====================================
@@ -1,10 +1,11 @@
 
 #include <complex.h>
+#include <stdbool.h>
 
 
 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 };
+enum interp_t { NLINEAR, NEAREST, LIINCO };
 
 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);
 
@@ -16,10 +17,13 @@ extern void draw(int X, int Y, int rgbstr, unsigned char (*rgbbuf)[Y][rgbstr / 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 void draw_plot(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 char* get_spec(int i);
+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, bool plot,
+		long rgbw, long rgbh, const complex float* data, complex float* buf);
 
 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]);


=====================================
src/main.c
=====================================
@@ -22,23 +22,32 @@
 
 
 
-static const char usage_str[] = "<image> ...";
 static const char help_str[] = "View images.";
 
 
-int main(int argc, char* argv[])
+int main(int argc, char* argv[argc])
 {
 	gtk_init(&argc, &argv);
 
+	long count;
+	const char** in_files;
+
+	struct arg_s args[] = {
+
+		ARG_TUPLE(true, &count, 1, { OPT_INFILE, sizeof(char*), &in_files, "image" }),
+	};
+
+
+
 	const struct opt_s opts[] = {
 
 	};
 
-	cmdline(&argc, argv, 1, 100, usage_str, help_str, ARRAY_SIZE(opts), opts);
+	cmdline(&argc, argv, ARRAY_SIZE(args), args, help_str, ARRAY_SIZE(opts), opts);
 
 	struct view_s* v = NULL;
 
-	for (int i = 1; i < argc; i++) {
+	for (int i = 0; i < count; i++) {
 
 		long dims[DIMS];
 
@@ -51,19 +60,19 @@ int main(int argc, char* argv[])
 		 * a file manager.
 		 */
 
-		char* dot = strrchr(argv[i], '.');
+		char* dot = strrchr(in_files[i], '.');
 
 		if ((NULL != dot) && (	 !strcmp(dot, ".cfl") 
 				      || !strcmp(dot, ".hdr") 
 				      || !strcmp(dot, ".")))
 			*dot = '\0';
 
-		complex float* x = load_cfl(argv[i], DIMS, dims);
+		complex float* x = load_cfl(in_files[i], DIMS, dims);
 
 
 
 		// FIXME: we never delete them
-		struct view_s* v2 = window_new(argv[i], NULL, dims, x);
+		struct view_s* v2 = window_new(in_files[i], NULL, dims, x);
 
 		// If multiple files are passed on the commandline, add them to window
 		// list. This enables sync of windowing and so on...


=====================================
src/view.c
=====================================
@@ -1,15 +1,13 @@
 /* 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-2016 Martin Uecker <martin.uecker at med.uni-goettinge.de>
  */
 
 #define _GNU_SOURCE
 #include <unistd.h>
 #include <complex.h>
 #include <stdbool.h>
+#include <math.h>
 
 #include <libgen.h>
 
@@ -47,6 +45,7 @@ struct view_s {
 	bool sync;
 
 	bool cross_hair;
+	bool status_bar;
 
 	const char* name;
 
@@ -60,6 +59,7 @@ struct view_s {
 	bool transpose;
 
 	// representation
+	bool plot;
 	enum mode_t mode;
 	double winhigh;
 	double winlow;
@@ -84,6 +84,11 @@ struct view_s {
 	long strs[DIMS];
 	const complex float* data;
 
+	// geometry
+	unsigned long geom_flags;
+	const float (*geom)[3][3];
+	const float (*geom_current)[3][3];
+
 	// widgets
 	GtkComboBox* gtk_mode;
 	GtkComboBox* gtk_flip;
@@ -140,6 +145,24 @@ static void add_text(cairo_surface_t* surface, int x, int y, int size, const cha
 }
 
 
+extern void update_geom(struct view_s* v)
+{
+	if (NULL == v->geom)
+		return;
+
+	long dims[DIMS];
+	md_select_dims(DIMS, v->geom_flags, dims, v->dims);
+
+	long strs[DIMS];
+	md_calc_strides(DIMS, strs, dims, 1);
+
+	v->geom_current = &v->geom[md_calc_offset(DIMS, strs, v->pos)];
+
+	printf("%f %f %f %f %f %f %f %f %f\n",
+		(*v->geom_current)[0][0], (*v->geom_current)[0][1], (*v->geom_current)[0][2],
+		(*v->geom_current)[1][0], (*v->geom_current)[1][1], (*v->geom_current)[1][2],
+		(*v->geom_current)[2][0], (*v->geom_current)[2][1], (*v->geom_current)[2][2]);
+}
 
 
 extern gboolean update_view(struct view_s* v)
@@ -234,6 +257,17 @@ extern void view_refresh(struct view_s* v)
 	update_view(v);
 }
 
+
+extern void view_add_geometry(struct view_s* v, unsigned long flags, const float (*geom)[3][3])
+{
+	v->geom_flags = flags;
+	v->geom = geom;
+	v->geom_current = NULL;
+
+	update_geom(v);
+}
+
+
 extern gboolean refresh_callback(GtkWidget *widget, gpointer data)
 {
 	UNUSED(widget);
@@ -316,6 +350,7 @@ extern gboolean geom_callback(GtkWidget *widget, gpointer data)
 
 	v->invalid = true;
 
+	update_geom(v);
 	update_view(v);
 
 	return FALSE;
@@ -349,34 +384,46 @@ extern gboolean window_callback(GtkWidget *widget, gpointer data)
 
 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);
+	update_buf(v->xdim, v->ydim, DIMS, v->dims, v->strs, v->pos,
+		v->flip, v->interpolation, v->xzoom, v->yzoom, v->plot,
+		v->rgbw, v->rgbh, v->data, v->buf);
 }
 
 
+static const char* spec = "xyzcmnopqsfrtuvw";
 
 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");
+	int len = 0;
+
+	len += snprintf(NULL, 0, "%s_", v->name);
+
+	for (int i = 0; i < DIMS; i++)
+		if ((v->dims[i] != 1) && (i != v->xdim) && (i != v->ydim))
+			len += snprintf(NULL, 0, "%c%04ld", spec[i], v->pos[i]);
+
+	len += snprintf(NULL, 0, ".png");
+
+	len++;
+
+	char* name = xmalloc(len);
+
+	int off = 0;
+
+	off += snprintf(name + off, len - off, "%s_", v->name);
+
+	for (int i = 0; i < DIMS; i++)
+		if ((v->dims[i] != 1) && (i != v->xdim) && (i != v->ydim))
+			off += snprintf(name + off, len - off, "%c%04ld", spec[i], v->pos[i]);
 
-	v->dialog = gtk_file_chooser_dialog_new ("Save File",
+	off += snprintf(name + off, len - off, ".png");
+
+
+
+	v->dialog = gtk_file_chooser_dialog_new("Save File",
                                       v->window,
 				      GTK_FILE_CHOOSER_ACTION_SAVE,
                                       "Cancel",
@@ -384,40 +431,47 @@ extern gboolean save_callback(GtkWidget *widget, gpointer data)
                                       "Save",
                                       GTK_RESPONSE_ACCEPT,
                                       NULL);
-	v->chooser = GTK_FILE_CHOOSER (v->dialog);
 
-	gtk_file_chooser_set_current_name (v->chooser, basename(name));
+	v->chooser = GTK_FILE_CHOOSER(v->dialog);
+
+	gtk_file_chooser_set_current_name(v->chooser, basename(name));
 	
+	char* dname = strdup(v->name);
+
 	// Outputfolder = Inputfolder
-	gtk_file_chooser_set_current_folder (v->chooser, dirname(dir));
-	gtk_file_chooser_set_do_overwrite_confirmation (v->chooser, TRUE);
+	gtk_file_chooser_set_current_folder(v->chooser, dirname(dname));
+	gtk_file_chooser_set_do_overwrite_confirmation(v->chooser, TRUE);
+
+	gint res = gtk_dialog_run(GTK_DIALOG(v->dialog));
 
-	gint res = gtk_dialog_run (GTK_DIALOG (v->dialog));
+	if (GTK_RESPONSE_ACCEPT == res) {
 
-	if (res == GTK_RESPONSE_ACCEPT) {
 		// export single image
-		char *filename = gtk_file_chooser_get_filename (v->chooser);
+		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);
-	}
 
+		g_free(filename);
+	}
 
 	gtk_widget_destroy (v->dialog);
+
+	xfree(name);
+	xfree(dname);
+
 	return FALSE;
 }
 
+
+
 extern gboolean save_movie_callback(GtkWidget *widget, gpointer data)
 {
 	UNUSED(widget);
 	struct view_s* v = data;
 
-	unsigned int bufsize = 255;
-	char dir[bufsize];
-	strncpy(dir, v->name, bufsize);
-
 	int frame_dim = 10;
 
 	v->dialog = gtk_file_chooser_dialog_new("Export movie to folder",
@@ -430,15 +484,18 @@ extern gboolean save_movie_callback(GtkWidget *widget, gpointer data)
 						NULL);
 
 	v->chooser = GTK_FILE_CHOOSER(v->dialog);
+
+
+	char* dname = strdup(v->name);
+
 	// Outputfolder = Inputfolder
-	gtk_file_chooser_set_current_folder(v->chooser, dirname(dir));
+	gtk_file_chooser_set_current_folder(v->chooser, dirname(dname));
 
-	gint res = gtk_dialog_run (GTK_DIALOG (v->dialog));
+	gint res = gtk_dialog_run(GTK_DIALOG (v->dialog));
 
-	if (res == GTK_RESPONSE_ACCEPT) {
+	if (GTK_RESPONSE_ACCEPT == res) {
 
 		char *chosen_dir = gtk_file_chooser_get_filename(v->chooser);
-		char output_name[bufsize];
 
 		for (unsigned int f = 0; f < v->dims[frame_dim]; f++) {
 
@@ -449,10 +506,14 @@ extern gboolean save_movie_callback(GtkWidget *widget, gpointer data)
 				v->mode, 1. / v->max, v->winlow, v->winhigh, v->phrot,
 				v->rgbw, v->buf);
 
-			char suff[16];
-			snprintf(suff, 16, "/mov-%04d.png", f);
-			strncpy(output_name, chosen_dir, bufsize - 16);
-			strncat(output_name, suff, 16);
+			char output_name[256];
+			int len = snprintf(output_name, 256, "%s/mov-%04d.png", chosen_dir, f);
+
+			if (len + 1 >= sizeof(output_name)) {
+
+				gtk_entry_set_text(v->gtk_entry, "Error: writing image file.\n");
+				break;
+			}
 
 			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");
@@ -464,13 +525,15 @@ extern gboolean save_movie_callback(GtkWidget *widget, gpointer data)
 
 	gtk_widget_destroy (v->dialog);
 
+	xfree(dname);
+
 	return FALSE;
 }
 
 
 struct xy_s { float x; float y; };
 
-static struct xy_s pos2screen(const struct view_s* v, /*const+*/float (*pos)[DIMS])
+static struct xy_s pos2screen(const struct view_s* v, const float (*pos)[DIMS])
 {
 	float x = (*pos)[v->xdim];
 	float y = (*pos)[v->ydim];
@@ -481,9 +544,16 @@ static struct xy_s pos2screen(const struct view_s* v, /*const+*/float (*pos)[DIM
 	if ((XY == v->flip) || (OY == v->flip))
 		y = v->dims[v->ydim] - 1 - y;
 
+	// shift to the center of pixels
+	x += 0.5;
+	y += 0.5;
+
 	x *= v->xzoom;
 	y *= v->yzoom;
 
+	if (v->plot)
+		y = v->rgbh / 2;
+
 	return (struct xy_s){ x, y };
 }
 
@@ -492,8 +562,8 @@ static void screen2pos(const struct view_s* v, float (*pos)[DIMS], struct xy_s x
 	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;
+	float x = xy.x / v->xzoom - 0.5;
+	float y = xy.y / v->yzoom - 0.5;
 
 	if ((XY == v->flip) || (XO == v->flip))
 		x = v->dims[v->xdim] - 1 - x;
@@ -501,10 +571,37 @@ static void screen2pos(const struct view_s* v, float (*pos)[DIMS], struct xy_s x
 	if ((XY == v->flip) || (OY == v->flip))
 		y = v->dims[v->ydim] - 1 - y;
 
-	(*pos)[v->xdim] = x;
-	(*pos)[v->ydim] = y;
+	(*pos)[v->xdim] = roundf(x);
+
+	if (!v->plot)
+		(*pos)[v->ydim] = roundf(y);
 }
 
+
+
+static void clear_status_bar(struct view_s* v)
+{
+	char buf = '\0';
+	gtk_entry_set_text(v->gtk_entry, &buf);
+}
+
+
+static void update_status_bar(struct view_s* v, const float (*pos)[DIMS])
+{
+	int x2 = (*pos)[v->xdim];
+	int y2 = (*pos)[v->ydim];
+
+	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];
+	snprintf(buf, 100, "Pos: %03d %03d Magn: %.3e Val: %+.3e%+.3ei Arg: %+.2f", x2, y2,
+			cabsf(val), crealf(val), cimagf(val), cargf(val));
+
+	gtk_entry_set_text(v->gtk_entry, buf);
+}
+
+
 extern gboolean draw_callback(GtkWidget *widget, cairo_t *cr, gpointer data)
 {
 	UNUSED(widget);
@@ -520,11 +617,11 @@ extern gboolean draw_callback(GtkWidget *widget, cairo_t *cr, gpointer data)
 
 	if (v->rgb_invalid) {
 
-		draw(v->rgbw, v->rgbh, v->rgbstr, (unsigned char(*)[v->rgbw][v->rgbstr / 4][4])v->rgb,
+		(v->plot ? draw_plot : 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);
 
-
 		v->rgb_invalid = false;
 	}
 
@@ -549,6 +646,19 @@ extern gboolean draw_callback(GtkWidget *widget, cairo_t *cr, gpointer data)
 //		draw_grid(v->rgbw, v->rgbh, v->rgbstr, (unsigned char (*)[v->rgbw][v->rgbstr / 4][4])v->rgb, &coords, 4, &color_white);
 	}
 
+	if (v->status_bar) {
+
+		float posi[DIMS];
+		for (unsigned int i = 0; i < DIMS; i++)
+			posi[i] = v->pos[i];
+
+		update_status_bar(v, &posi);
+
+		for (struct view_s* v2 = v->next; v2 != v; v2 = v2->next)
+			if (v->sync && v2->sync)
+				update_status_bar(v2, &posi);
+	}
+
 	cairo_set_source_surface(cr, v->source, 0, 0);
 	cairo_paint(cr);
 	return FALSE;
@@ -575,6 +685,7 @@ struct view_s* create_view(const char* name, const long pos[DIMS], const long di
 	v->sync = true;
 
 	v->cross_hair = false;
+	v->status_bar = false;
 
 	v->name = name;
 	v->max = 1.;
@@ -587,6 +698,8 @@ struct view_s* create_view(const char* name, const long pos[DIMS], const long di
 	v->xdim = sq_dims[0];
 	v->ydim = sq_dims[1];
 
+	v->plot = false;
+
 	v->xzoom = 2.;
 	v->yzoom = 2.;
 
@@ -599,6 +712,10 @@ struct view_s* create_view(const char* name, const long pos[DIMS], const long di
 	md_calc_strides(DIMS, v->strs, dims, sizeof(complex float));
 	v->data = data;
 
+	v->geom_flags = 0ul;
+	v->geom = NULL;
+	v->geom_current = NULL;
+
 	v->winlow = 0.;
 	v->winhigh = 1.;
 	v->phrot = 0.;
@@ -637,22 +754,19 @@ extern gboolean toggle_sync(GtkToggleButton* button, gpointer data)
 }
 
 
-static void update_status_bar(struct view_s* v, /*const*/ float (*pos)[DIMS])
+extern gboolean toggle_plot(GtkToggleButton* button, gpointer data)
 {
-	int x2 = (*pos)[v->xdim];
-	int y2 = (*pos)[v->ydim];
+	UNUSED(button);
+	struct view_s* v = data;
+	v->plot = !v->plot;
 
-	(*pos)[v->xdim] = x2;
-	(*pos)[v->ydim] = y2;
+	gtk_widget_set_sensitive(GTK_WIDGET(v->gtk_mode),
+		v->plot ? FALSE : TRUE);
 
-	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];
-	snprintf(buf, 100, "Pos: %03d %03d Magn: %.3e Val: %+.3e%+.3ei Arg: %+.2f", x2, y2,
-			cabsf(val), crealf(val), cimagf(val), cargf(val));
+	v->invalid = true;
+	update_view(v);
 
-	gtk_entry_set_text(v->gtk_entry, buf);
+	return FALSE;
 }
 
 
@@ -681,6 +795,8 @@ extern gboolean button_press_event(GtkWidget *widget, GdkEventButton *event, gpo
 	if (event->button == GDK_BUTTON_PRIMARY) {
 
 		v->cross_hair = false;
+		v->status_bar = false;
+		clear_status_bar(v);
 
 		v->rgb_invalid = true;
 		update_view(v);
@@ -689,15 +805,10 @@ extern gboolean button_press_event(GtkWidget *widget, GdkEventButton *event, gpo
 	if (event->button == GDK_BUTTON_SECONDARY) {
 
 		v->cross_hair = true;
+		v->status_bar = true;
 
 		set_position(v, v->xdim, pos[v->xdim]);
 		set_position(v, v->ydim, pos[v->ydim]);
-
-		update_status_bar(v, &pos);
-
-		for (struct view_s* v2 = v->next; v2 != v; v2 = v2->next)
-			if (v->sync && v2->sync)
-				update_status_bar(v2, &pos);
 	}
 
 	return FALSE;
@@ -795,13 +906,14 @@ extern struct view_s* window_new(const char* name, const long pos[DIMS], const l
 	v->gtk_winhigh = GTK_ADJUSTMENT(gtk_builder_get_object(builder, "winhigh"));
 
 	v->gtk_entry = GTK_ENTRY(gtk_builder_get_object(builder, "entry"));
+#if 0
 	PangoFontDescription* desc = pango_font_description_new();
 	pango_font_description_set_family(desc, "mono");
 	pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD);
 	pango_font_description_set_absolute_size(desc, 10 * PANGO_SCALE);
 	gtk_widget_override_font(GTK_WIDGET(v->gtk_entry), desc);
 	pango_font_description_free(desc);
-
+#endif
 	v->gtk_zoom = GTK_ADJUSTMENT(gtk_builder_get_object(builder, "zoom"));
 	v->gtk_aniso = GTK_ADJUSTMENT(gtk_builder_get_object(builder, "aniso"));
 


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


=====================================
src/viewer.ui
=====================================
@@ -72,6 +72,9 @@
       <row>
         <col id="0" translatable="yes">NEAREST</col>
       </row>
+      <row>
+        <col id="0" translatable="yes">LIINCO</col>
+      </row>
     </data>
   </object>
   <object class="GtkAdjustment" id="pos00">
@@ -377,6 +380,20 @@
                 <property name="expand">False</property>
                 <property name="homogeneous">True</property>
               </packing>
+	    </child>
+	    <child>
+              <object class="GtkToggleToolButton" id="toolbutton16">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label" translatable="yes">plot</property>
+                <property name="use_underline">True</property>
+                <property name="stock_id">gtk-connect</property>
+                <signal name="clicked" handler="toggle_plot" swapped="no"/>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="homogeneous">True</property>
+              </packing>
             </child>
           </object>
           <packing>



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

-- 
View it on GitLab: https://salsa.debian.org/med-team/bart-view/-/compare/187c48cbcb65cb09449e17a8e55af3442af1cdf1...011f14a043c064003561e47f55cd78b6d9da9691
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/debian-med-commit/attachments/20221024/8314a24e/attachment-0001.htm>


More information about the debian-med-commit mailing list