+++ /dev/null
-#include <assert.h>
-#include "ImageData.H"
-#include "string.h"
-#include <Fl/filename.H>
-#include <stdlib.h>
-#include <FL/Fl.H>
-#include <time.h>
-#include "misc.h"
-#include "mypam.h"
-#include "../config.h"
-
-#include <algorithm>
-// From http://www.redhat.com/docs/manuals/enterprise/RHEL-3-Manual/gcc/variadic-macros.html
-
-#define badfile(A, ...) {info(A, ## __VA_ARGS__); return -1;}
-#define badfilec(A, ...) {fclose(fp); info(A, ## __VA_ARGS__); return -1;} // ALso close the file.
-
-#define LINESIZE 1024*1024
-
-#define MTX_HEADER_SIZE 256*10
-
-// mingw32 does not seem to implement NAN properly: it seems to be set to 0.
-#ifdef WIN32
-#define NAN INFINITY
-#define isnan(A) isinf(A)
-#endif
-
-//some handy local functions
-
-double parse_reading(char *line, int col);
-double nextreading(FILE *fp, int col, int &lnum);
-int nextline(FILE *fp, char *buf);
-
-ImageData::ImageData()
-{
- data_loaded = 0;
- orig_data = NULL;
- qmin = xmin = ymin = 0;
- qmax = xmax = ymax = 1;
- auto_quant = 1;
- auto_quant_percent = 50.0;
- incorrect_column = COPY_ADJACENT;
- mtx_cut_type = XY;
- mtx_index = 0;
- do_mtx_cut_title = false;
- data3d = false;
- gpload_type = COLUMNS;
- gp_column = 2;
- datfile_type = MATRIX;
- fallbackfile_type = PGM;
-}
-
-ImageData::~ImageData()
-{
- clear();
-}
-
-void ImageData::clear()
-{
- if (orig_data != NULL) //was using "data_loaded", but we had a big memory leak...
- {
- //info("clearing image data arrays\n");
- delete [] orig_data;
- delete [] raw_data;
- delete [] quant_data;
- delete [] threshold_reject;
- orig_data = NULL;
- }
- data_loaded = 0;
-}
-
-void ImageData::reallocate()
-{
- clear();
- orig_data = new double[width*height];
- raw_data = new double[width*height];
- quant_data = new int[width*height];
- threshold_reject = new bool[width*height];
- data_loaded = 1;
-}
-
-void ImageData::resize_tmp_arrays(int new_width, int new_height)
-{
- // Only ever make things bigger
- if (new_width*new_height > orig_width*orig_height)
- {
- delete [] quant_data;
- delete [] threshold_reject;
- quant_data = new int[new_width*new_height];
- threshold_reject = new bool[new_width*new_height];
- }
-}
-
-void ImageData::reset()
-{
- memcpy(raw_data, orig_data, sizeof(double)*orig_width*orig_height);
- width = orig_width;
- height = orig_height;
- xmin = orig_xmin;
- ymin = orig_ymin;
- xmax = orig_xmax;
- ymax = orig_ymax;
- xname = orig_xname;
- yname = orig_yname;
-}
-
-void ImageData::saveMTX(const char *filename)
-{
- FILE *fp = fopen(filename, "wb");
- if (fp == NULL)
- {
- info("error opening file %s", filename);
- return;
- }
-
- fprintf(fp, "Units, %s,"
- "%s, %e, %e,"
- "%s, %e, %e,"
- "Nothing, 0, 1\n",
- zname.c_str(),
- xname.c_str(), xmin, xmax,
- yname.c_str(), ymax, ymin);
- fprintf(fp, "%d %d 1 8\n", width, height);
-
- for (int i=0; i<width; i++)
- for (int j=0; j<height; j++)
- fwrite(&raw(i,j), sizeof(double), 1, fp);
- fclose(fp);
-}
-
-void ImageData::shift_data(int after_row, int offset)
-{
- double *new_row = new double[width]; // less efficient, but easier to read the code
- for (int j=0; j<height; j++)
- {
- if (j>=after_row)
- {
- for (int i=0; i<width; i++)
- {
- int i2 = i - offset;
- if (i2 > width-1) i2 = i2 % (width);
- if (i2 < 0) i2 = i2 + (-i2/width+1)*width;
- if (i2>=0 && i2 < width)
- new_row[i] = raw(i2,j);
- else
- new_row[i] = -1e2; // we should never get here if we
- // did the bounds checking right
- }
- for (int i=0; i<width; i++)
- raw(i,j) = new_row[i];
- }
- }
- delete [] new_row;
-}
-
-void ImageData::rescale_data(double new_qmin, double new_qmax)
-{
- for (int i = 0; i<width*height; i++)
- raw_data[i] = new_qmin + (raw_data[i]-qmin)/(qmax-qmin)*(new_qmax-new_qmin);
- qmax = new_qmax;
- qmin = new_qmin;
-}
-
-void ImageData::store_orig()
-{
- memcpy(orig_data, raw_data, sizeof(double)*width*height);
- orig_width = width;
- orig_height = height;
- orig_xmin = xmin;
- orig_ymin = ymin;
- orig_xmax = xmax;
- orig_ymax = ymax;
- orig_xname = xname;
- orig_yname = yname;
-}
-
-void ImageData::load_int(int *data,
- int w, int h,
- double x1, double x2,
- double y1, double y2,
- double z1, double z2)
-{
- xmin = isnan(x1) ? x1 : 0;
- xmax = isnan(x2) ? x2 : width-1;
- ymin = isnan(y1) ? y1 : 0;
- ymax = isnan(y2) ? y2 : height-1;
- qmin = isnan(z1) ? z1 : 0;
- qmax = isnan(z2) ? z2 : QUANT_MAX;
- width = w;
- height = h;
-
- reallocate();
-
- xname = "X";
- yname = "Y";
- zname = "Data";
-
- // Perform conversion to floating point at very first step, even if
- // the data is integer: we will then requantize it by calling
- // quantize().
-
- // We may want to have a UI option to preserve orginal quantization:
- // turning off auto_quant should work... (although it will always be
- // preserved anyway in the raw_data, and so also in the line cuts)
-
- for (int i=0; i<width*height; i++)
- raw_data[i] = qmin + 1.0*data[i]*(qmax-qmin)/QUANT_MAX;
-
- store_orig();
-}
-
-void ImageData::load_raw(double *data,
- int w, int h,
- double x1, double x2,
- double y1, double y2)
-{
- xmin = isnan(x1) ? x1 : 0;
- xmax = isnan(x2) ? x2 : width-1;
- ymin = isnan(y1) ? y1 : 0;
- ymax = isnan(y2) ? y2 : height-1;
- width = w;
- height = h;
-
- reallocate();
-
- xname = "X";
- yname = "Y";
- zname = "Data";
-
- memcpy(raw_data, data, width*height*sizeof(double));
- store_orig();
-}
-
-int ImageData::load_file(const char *name)
-{
- // We will identify the relevant helper function by the filename
- // extension
-
- const char *ext = strrchr(name, '.');
-
- data_loaded = 0;
- if (ext == NULL)
- badfile("Unsupported extension on file: %s\n", name);
-
- if (strcmp(ext, ".Stm") == 0)
- return load_STM(name);
- else if (strcmp(ext, ".pgm") == 0)
- return load_PGM(name);
- else if (strcmp(ext, ".mtx") == 0)
- return load_MTX(name);
- else if (strcmp(ext, ".dat") == 0)
- {
- if (datfile_type == MATRIX)
- return load_DAT(name);
- else if (datfile_type == GNUPLOT)
- return load_GP(name);
- else if (datfile_type == DELFT_LEGACY)
- return load_Delft(name);
- else if (datfile_type == DAT_META)
- return load_DAT_meta(name);
- }
- else if (strcasecmp(ext, ".TIF") == 0)
- return load_XL30S_TIF(name);
- else
- {
- if (fallbackfile_type == PGM)
- return load_PGM(name);
- else if (fallbackfile_type == MTX)
- return load_MTX(name);
- else //if (fallbackfile_type == DAT)
- {
- if (datfile_type == MATRIX)
- return load_DAT(name);
- else if (datfile_type == GNUPLOT)
- return load_GP(name);
- else if (datfile_type == DELFT_LEGACY)
- return load_Delft(name);
- else if (datfile_type == DAT_META)
- return load_DAT_meta(name);
- }
- }
-}
-
-int ImageData::load_STM(const char *name)
-{
- // variables for binary read
- int m = 0;
- unsigned char tmp[2];
- short unsigned int datatmp;
-
- // variables for header info
- int w, h;
- double xvrange, yvrange, xcal, ycal;
- int chnum;
- char buf1[256], buf2[256];
- char ch_name[256];
- char ch_units[256];
- double ch_scale;
-
- // Some Stm headers (older ones, v2.5.1 software, at least), have 0x800 byte headers.
- // Version 2.6.0 also have 0x800 byte headers.
- // The newer ones, v 2.6.3, have 0x1000 byte headers.
- // Any space not used by the header info is filled with 0x2e up until the last byte
- // before the image data starts, which is always 0x00.
-
- char header[0x1000];
- int hdrlen;
-
- FILE *fp = fopen(name, "rb");
- if(fp == NULL)
- badfile("Unable to open file \"%s\": %s\n",name,strerror(errno));
-
- // Read the second line of the file, which has the software version
- int s1, s2, s3;
- if (fgets(buf1, 256, fp) == NULL)
- badfilec("Short file error\n");
- if (fgets(buf1, 256, fp) == NULL)
- badfilec("Short file error\n");
- if (sscanf(buf1, "SwV %d.%d.%d", &s1, &s2, &s3) != 3)
- hdrlen = 0x800;
- else
- {
- if ((s2 > 5) && (s3 > 2))
- hdrlen = 0x1000;
- else
- hdrlen = 0x800;
- }
-
- // Rewind and now read the correct header length
- rewind(fp);
- assert(hdrlen > 0);
- if (fread(header, 1, hdrlen, fp) < static_cast<unsigned>(hdrlen))
- badfilec("Invalid STM file");
-
- if (sscanf(strstr(header, "Pix"), "Pix %d", &w) != 1)
- badfilec("Invalid width\n");
-
- if (sscanf(strstr(header, "Lin"), "Lin %d", &h) != 1)
- badfilec("Invalid height\n");
-
- if (sscanf(strstr(header, "SR0"), "SR0 %lf", &xvrange) != 1) // range in volts
- badfilec("Invalid xrange\n");
-
- if (sscanf(strstr(header, "SR1"), "SR1 %lf", &yvrange) != 1)
- badfilec("Invalid yrange\n");
-
- if (sscanf(strstr(header, "S00"), "S00 %lf", &xcal) != 1) // scanner calibration in Ang/V
- badfilec("Invalid xscale\n");
-
- if (sscanf(strstr(header, "S10"), "S10 %lf", &ycal) != 1)
- badfilec("Invalid xscale\n");
-
- if (sscanf(strstr(header, "ImC"), "ImC %d", &chnum) != 1)
- badfilec("Invalid chnum\n");
-
- sprintf(buf1, "A%dN", chnum);
- sprintf(buf2, "A%dN %%256\[^\n]", chnum);
- if (sscanf(strstr(header, buf1), buf2, ch_name) != 1)
- badfilec("Invalid channel name\n");
-
- sprintf(buf1, "A%dU", chnum);
- sprintf(buf2, "A%dU %%256[^\n]", chnum);
- if (sscanf(strstr(header, buf1), buf2, ch_units) != 1)
- badfilec("Invalid channel units\n");
-
- sprintf(buf1, "A%dV", chnum);
- sprintf(buf2, "A%dV %%lf\n", chnum);
- if (sscanf(strstr(header, buf1), buf2, &ch_scale) != 1)
- badfilec("Invalid channel scale\n");
-
-
- // Now update the ranges and stuff
-
- xmin = 0;
- xmax = xvrange * xcal / 10000; // in microns
- xname = "Microns";
-
- ymin = 0;
- ymax = yvrange * ycal / 10000; // in microns
- yname = "Microns";
-
- // Let's leave the STM file Z scale just as 0 to 65535
- // (It's usually just the +/- 10V anyway, which is not any more physical...)
-
- zname = "DAC Value";
-
- width = w; height = h;
-
- reallocate();
-
- for (int i=0; i<width*height; i++)
- {
- m=fread(&tmp[1], 1, 1, fp); // byteswap from the SGI
- m=fread(&tmp[0], 1, 1, fp);
- if (m == 0)
- badfilec( "Read error row %d!\n", i/w);
- memcpy(&datatmp, &tmp, 2);
- datatmp = datatmp + 32768; // overflow the short unsigned int to convert from 16-bit signed to 16-bit unsigned
- raw_data[i] = datatmp;
-
- if (raw_data[i] > 65535 || raw_data[i] < 0)
- {
- warn("%4d %4d Data %02x %02x %.1f %6d\n", i/w, i%w, tmp[0], tmp[1], raw_data[i], datatmp);
- //getchar();
- }
- }
- fclose(fp);
- store_orig();
- data3d = false;
- return 0;
-}
-
-
-int ImageData::load_PGM(const char *name)
-{
- char buf[1024];
- char *p;
-
- char xunit[256];
- char yunit[256];
- char zunit[256];
-
- int maxval;
-
- //FILE *fp = fopen(name, "rb");
- // This is very annoying! pgm_readpgm exits on error...
- // I will have to write a more fault tolerant routine myself.
- //gray **image;
- //gray maxval;
- //image = pgm_readpgm(fp, &width, &height, &maxval);
- //reallocate();
- //fclose(fp);
-
- FILE *fp = fopen(name, "rb");
- if(fp == NULL)
- badfile("Unable to open file \"%s\": %s\n",name,strerror(errno));
-
- qmin = 0;
- qmax = 65535;
- xmin = 0;
- xmax = width-1;
- ymin = 0;
- ymax = height-1;
-
- sprintf(xunit, "Pixels");
- sprintf(yunit, "Pixels");
- sprintf(zunit, "Gray Value");
-
- // Get the first two lines: I always put comments below the image size
- if (fgets(buf,sizeof(buf),fp) == NULL)
- badfilec("no characters read: empty or short file?");
- if (strncmp(buf, "P5", 2) != 0)
- badfilec("wrong magic number %s: only raw pgm files are supported", buf);
- if (fgets(buf,sizeof(buf),fp) == NULL)
- badfilec("no characters read: empty or short file?");
- while (buf[0] == '#') // ignore any non-spyview comments
- fgets(buf,sizeof(buf),fp);
- if (sscanf(buf, "%d %d", &width, &height) != 2)
- badfilec("error reading width and height from line %s", buf);
-
- // Allocate the arrays now that we have the width and height
- reallocate();
-
- // Now get any lines that contain comments
- while (true)
- {
- fgets(buf, 1024, fp);
- if (buf[0] != '#')
- break;
- p = &buf[1];
- while (*p == ' ') p++;
- if (parse_pgm_comments("zmin", "%lf", &qmin, p, name)) continue;
- if (parse_pgm_comments("zmax", "%lf", &qmax, p, name)) continue;
- if (parse_pgm_comments("xmin", "%lf", &xmin, p, name)) continue;
- if (parse_pgm_comments("xmax", "%lf", &xmax, p, name)) continue;
- if (parse_pgm_comments("ymin", "%lf", &ymin, p, name)) continue;
- if (parse_pgm_comments("ymax", "%lf", &ymax, p, name)) continue;
- if (parse_pgm_comments("xunit", "%s", xunit, p, name)) continue;
- if (parse_pgm_comments("yunit", "%s", yunit, p, name)) continue;
- if (parse_pgm_comments("zunit", "%s", zunit, p, name)) continue;
- }
- xname = xunit;
- yname = yunit;
- zname = zunit;
-
- // The next item is the maxval, which should already be in the
- // buffer: we need to know if the data is one byte or two.
- if (sscanf(buf, "%d", &maxval) != 1)
- badfilec("error reading maxval");
-
- unsigned char b1;
- unsigned char b2;
- int data;
- // Now lets read the data
- for (int i=0; i<width*height; i++)
- {
- if (fread(&b1, 1, 1, fp) != 1)
- badfilec("short file at pixel %d", i);
- if (maxval > 255)
- {
- if (fread(&b2, 1, 1, fp) != 1)
- badfilec("short file at pixel %d", i);
- data = b1*256+b2;
- }
- else
- data = b1;
- raw_data[i] = qmin + 1.0*data*(qmax-qmin)/QUANT_MAX;
- }
-
- store_orig();
- fclose(fp);
- data3d = false;
- return 0;
-}
-
-int ImageData::parse_pgm_comments(const char *ident, const char *fmt, void *val, char *p, const char *filename)
-{
- if (strncmp(p, ident, 3) == 0)
- {
- p = strchr(p, ' ');
- if (strcmp(fmt, "%s") == 0)
- {
- char *cval = (char *)val;
- while (*p == ' ') p++;
- strcpy(cval, p);
- for(int i = strlen(cval)-1; i > 0 && isspace(cval[i]); i--)
- cval[i] = 0; // get rid of blank spaces at the end
- return 1;
- }
- if (sscanf(p, fmt, val) != 1)
- badfile( "Invalid %s %s in file %s\n", ident, p, filename);
- return(1);
- }
- return(0);
-}
-
-int ImageData::load_MTX(const char *name)
-{
- if (mtx.load_file(name) == -1) return -1;
- load_mtx_cut();
- data3d = true;
- return 0;
-}
-
-int ImageData::load_GP(const char *name)
-{
- if (gpload_type == COLUMNS)
- {
- if (mtx.load_gp_cols(name) == -1) return -1;
- // Good default settings for gp_cols
- mtx_index = gp_column;
- mtx_cut_type = 0;
- do_mtx_cut_title = false;
- }
- if (gpload_type == INDEX)
- {
- if (mtx.load_gp_index(name, gp_column) == -1) return -1;
- //mtx_index = 0;
- //mtx_cut_type = 2;
- do_mtx_cut_title = true;
- }
-
- load_mtx_cut();
- data3d = true;
- return 0;
-}
-
-int ImageData::load_DAT_meta(const char *name)
-{
- int n = mtx.load_dat_meta(name, gp_column);
- if (n == -1)
- {
- warn("Error reading metadata file\n");
- return -1;
- }
- else if (n == -2)
- {
- warn("Error reading data file\n");
- return -1;
- }
- // Why would I set these?
- //mtx_index = 0;
- //mtx_cut_type = 2; // Range checking should be done in load_mtx_cut(), which it is.
- load_mtx_cut();
- data3d = true;
- return 0;
-}
-
-
-void ImageData::load_mtx_cut()
-{
- if (!mtx.data_loaded)
- error("load_mtx_cut called with no mtx data loaded!");
-
- mtx_cut_type = static_cast<mtxcut_t>(mtx_cut_type % 3); //in case the user set it to an integer instead of using the enums
-
- //info("loading mtx cut type %d (YZ = 0, XY = 1, XZ = 2)\n", mtx_cut_type);
-
- if (mtx_index<0) mtx_index = 0;
- if (mtx_index > mtx.size[mtx_cut_type]-1) mtx_index = mtx.size[mtx_cut_type]-1;
-
- int xaxis = (mtx_cut_type+1)%3;
- int yaxis = (mtx_cut_type+2)%3;
- int zaxis = (mtx_cut_type)%3;
-
- width = mtx.size[xaxis];
- height = mtx.size[yaxis];
-
- //info("xaxis is %d width %d\n", xaxis, width);
- //info("yaxis is %d height %d\n", yaxis, height);
-
- reallocate();
-
- //warn( "mtx_cut_type = %d, xaxis = %d, yaxis = %d\n", mtx_cut_type, xaxis, yaxis);
- //warn( "width %d height %d\n", width, height);
- //warn( "loading index %d type %d\n", mtx_index, mtx_cut_type);
-
- for (int i=0; i<width; i++)
- for (int j=0; j<height; j++)
- {
- if (mtx_cut_type == 0)
- raw(i,j) = mtx.getData(mtx_index, i, j);
- else if (mtx_cut_type == 1)
- raw(i,j) = mtx.getData(j, mtx_index, i);
- else
- raw(i,j) = mtx.getData(i, j, mtx_index);
- }
-
- xname = mtx.axisname[xaxis];
- yname = mtx.axisname[yaxis];
-
- if (do_mtx_cut_title)
- {
- char buf[256];
- snprintf(buf,256,"%g", mtx.get_coordinate(zaxis,mtx_index));
- zname = mtx.dataname + " at " + mtx.axisname[zaxis] + " = " + buf;
- }
- else
- zname = mtx.dataname;
-
- // This is the proper way to do it:
-
- xmin = mtx.get_coordinate(xaxis, 0);
- xmax = mtx.get_coordinate(xaxis, width-1);
-
- // Y is always flipped
- ymin = mtx.get_coordinate(yaxis, height-1);
- ymax = mtx.get_coordinate(yaxis, 0);
-
- store_orig();
-}
-
-int ImageData::load_Delft(const char *name)
-{
- vector<double> data;
- char linebuffer[LINESIZE];
- FILE *fp = fopen(name, "rb");
- if(fp == NULL)
- badfile("Unable to open file \"%s\": %s\n",name,strerror(errno));
- int nread = 0;
- int num_points = 0;
- int points_per_sweep = -1;
- int num_sweeps = -1;
- double sweep_min = NAN;
- double sweep_max = NAN;
- bool found_sweep_max = false;
- double last_sweep;
- double last_data;
- string first_sweep_header;
- string last_sweep_header;
- string second_sweep_header;
-
- // This file format is a pain in the ass. In particular since there
- // are so many variations of it. I find the whole thing unbelievably
- // retarded.
- //
- // The basic structure something like this:
- //
- // 0 XL GATE VOLTAGE (mV)
- // 0 YL CURRENT (pA), Y2L CURRENT (pA)
- // 0 T T.U. Delft, TCS & Magnet PMS & dewar gnd disconnected, still heater from battery ,6-10-2008, 13:12
- // -1 L B=0.000T T=19.9mK sw=DAC6 D1=5.00 D2=0.00 D3=-1000.00 D4=0.00 D5=0.00 D6=-1000.00 D7=0.00 D8=0.00
- // [sweep data...]
- // 0 XL GATE VOLTAGE (mV)
- // 0 YL CURRENT (pA), Y2L CURRENT (pA)
- // 0 T T.U. Delft, TCS & Magnet PMS & dewar gnd disconnected, still heater from battery ,6-10-2008, 13:14
- // -2 L B=0.000T T=19.9mK sw=DAC6 D1=5.00 D2=0.00 D3=-998.00 D4=0.00 D5=0.00 D6=600.00 D7=0.00 D8=0.00
- // [sweep data...]
- //
- // Parsing is as follows:
- //
- // - look for "0 XL" to indicate new sweep
- // - sweep value is from col 2
- // - data value is from following columns
-
- if (mtx.progress_gui)
- mtx.open_progress_gui();
-
- while (1)
- {
- nread++;
- if (fgets(linebuffer, LINESIZE, fp) == NULL)
- break;
-
- if (nread % 100 == 0)
- {
- static char buf[256];
- snprintf(buf, sizeof(buf), "Lines read: %d", nread);
- if (mtx.progress_gui)
- {
- mtx.msg->value(buf);
- Fl::check();
- }
- }
-
- if (strstr(linebuffer, "0 XL") != NULL)
- {
- //info("found sweep, line %d", nread);getchar();
- if (num_sweeps == -1) // this is the XL line at top of file
- {
- if (fgets(linebuffer, LINESIZE, fp) == NULL) break;
- if (fgets(linebuffer, LINESIZE, fp) == NULL) break;
- if (fgets(linebuffer, LINESIZE, fp) == NULL) break;
- nread += 3;
- first_sweep_header = linebuffer;
- num_sweeps = 0;
- continue;
- }
- else
- {
- // if (isnan(sweep_max)) doesn't seem to work under win32?
- if (!found_sweep_max)
- {
- sweep_max = last_sweep;
- found_sweep_max = true;
- info("settings sweep max to %e from line %d\n", sweep_max, nread+4-1);
- }
- num_sweeps++;
- if (points_per_sweep == -1)
- points_per_sweep = num_points;
- else if (num_points != points_per_sweep)
- badfilec("%d points in sweep %d doesn't match previous value %d\nline number %d\n",
- num_points, num_sweeps, points_per_sweep, nread);
- num_points = 0;
-
- if (fgets(linebuffer, LINESIZE, fp) == NULL) break;
- if (fgets(linebuffer, LINESIZE, fp) == NULL) break;
- if (fgets(linebuffer, LINESIZE, fp) == NULL) break;
- nread+=3;
- last_sweep_header = linebuffer;
-
- if (num_sweeps == 1)
- second_sweep_header = last_sweep_header;
-
- continue;
- }
-
- }
-
- if (strchr("#\n\r",linebuffer[0]) != NULL)
- continue;
-
- //if (sscanf(linebuffer, "%*f\t%lf\t%lf", &last_sweep, &last_data) != 2)
- last_data = parse_reading(linebuffer, gp_column);
- if (isnan(last_data))
- {
- //info("line\n%s\ncgp_column %d\nval %e\n", linebuffer, gp_column, last_data);
- badfilec("invalid data in delft file at line %d\nline: %s\n", nread, linebuffer);
- }
-
- data.push_back(last_data);
- if (num_points == 0) sweep_min = last_sweep;
- num_points++;
- }
-
- if (mtx.progress_gui)
- mtx.close_progress_gui();
-
- num_sweeps++;
- if (num_points != points_per_sweep)
- {
- info("Incomplete last sweep: \n"
- "%d points in sweep %d doesn't match previous value %d\n",
- num_points, num_sweeps, points_per_sweep);
- num_sweeps--;
- }
-
-
- info("points_per_sweep %d num_sweeps %d\n", points_per_sweep, num_sweeps);
-
- unsigned int i,j;
- i = first_sweep_header.find("sw=", 0);
- j = first_sweep_header.find("D1", i);
-
- string sweepname = first_sweep_header.substr(i+3,j-i-4);
-
- info("i %d j %d sweepname set to _%s_", i, j, sweepname.c_str());
-
- info("\n\n%s%s%s\n",
- first_sweep_header.c_str(),
- second_sweep_header.c_str(),
- last_sweep_header.c_str());
-
- height = points_per_sweep;
- width = num_sweeps;
- reallocate();
-
- info("data " _STF " w*h %d\n", data.size(), width*height);
-
- //for (int i=0; i<width*height; i++)
- //raw_data[i] = data[i];
-
- for (int i=0; i<width; i++)
- for (int j=0; j<height; j++)
- raw(i,j) = data[i*height+(height-1-j)];
-
- data3d = false;
- ymin = sweep_min;
- ymax = sweep_max;
- xmin = 0;
- xmax = num_sweeps;
- xname = "Loop Variable";
- yname = sweepname;
- zname = "Current (pA)";
- store_orig();
-
- fclose(fp);
- return 0;
-}
-
-
-// copied from fei2pgm test code
-
-int fei_error(char *msg, const char *name)
-{
- warn(msg, name);
- return -1;
-}
-
-int ImageData::load_XL30S_TIF(const char *name)
-{
- char buf[0x1200];
- double mag;
- char *p;
-
- int size = 712*484; // we support only low res tifs for now
-
- // First get the header
-
- FILE *fp = fopen(name, "r");
-
- fread(buf, 1, 0x1200, fp);
-
- // Read the magnification
-
- for (int i=0; i<0x1200; i++)
- if ( (p = strstr(buf+i, "Magni")) != 0)
- break;
- if (p == NULL)
- return fei_error("error: could not find magnification tag in XL30S TIF file %s", name);
-
- if (sscanf(p, "Magnification = %lf", &mag) == 0)
- return fei_error("error: could not read magnification in XL30S TIF file %s", name);
-
- info("XL30S TIF Mag is %g\n", mag);
-
- // Check for XLFileType tag to see if this is really an XL30s TIF
- p = NULL;
- for (int i=0; i<0x1200; i++)
- if ( (p = strstr(buf+i, "XLFileType")) != 0)
- break;
- if (p == NULL)
- return fei_error("file %s does not seem to be and XL30s TIFF", name);
-
- // Try to seek to start of the data (always last chunk of file?)
-
- if (fseek(fp, -size, SEEK_END) == -1)
- return fei_error("Error seeking in file: %s", name);
-
- xname = "Microns";
- yname = "Microns";
- zname = "SEM Signal";
- xmin = 0; ymin = 0;
- xmax = 712.0/215.0/mag*29736.822;
- ymax = 484.0/215.0/mag*29736.822;
- width = 712;
- height = 484;
- reallocate();
-
- unsigned char tmp[size];
- fread(tmp, 1, size, fp);
- fclose(fp);
-
- for (int i=0; i<size; i++)
- raw_data[i] = tmp[i];
-
- store_orig();
- data3d = false;
- return 0;
-}
-
-// Copied from dat2pgm
-int ImageData::load_DAT(const char *name)
-{
- int w, col;
- int h, row;
-
- vector<double> data;
-
- char linebuffer[LINESIZE];
- char *p;
-
- double datatmp;
-
- char sep[] = " \t\n\r";
-
- FILE *fp = fopen(name, "rb");
- if(fp == NULL)
- badfile("Unable to open file \"%s\": %s\n",name,strerror(errno));
-
- row = col = w = h = 0;
-
- while (1)
- {
- if (fgets(linebuffer, LINESIZE, fp) == NULL)
- break;
-
- // Figure out what kind of line this is
- for(p = linebuffer; *p != 0 && isspace(*p); p++)
- ;
-
- if(*p == '\n' || *p == 0 || *p == '#')
- continue;
-
- col = 0;
- p = strtok(linebuffer, sep);
- while (p != NULL)
- {
- if (sscanf(p, "%lf", &datatmp) != 1)
- warn( "load_DAT: invalid data at row %d col %d: \"%s\", copying last read value\n", row, col, p);
- data.push_back(datatmp);
- col++;
- p = strtok(0, sep);
- }
-
- if (row == 0)
- w = col;
- else if (w != col)
- {
- if (col == 0)
- break; // ignore empty lines at the end.
- if(col < w) // This row is too short
- {
- warn( "number of columns %d at row %d does not match width of previous rows (%d)\n", col, row, w);
- double d = 0; // This is used for ZERO; Mean updates the value so they can share insertion code.
- switch(incorrect_column)
- {
- case EXIT:
- exit(-1);
- case COPY_ADJACENT:
- d = data[data.size()];
- for (int i=0; i < (w-col); i++)
- data.push_back(d);
- break;
- case DROP:
- data.erase(data.begin()+(row*w),data.end());
- row--;
- break;
- case FILL_MEAN:
- for(int i = 0; i < col; i++)
- d += data[row*w + i];
- d = d / col;
- case FILL_ZERO: // Warning! Falling case!
- assert(col < w);
- for(int i = 0; i < (w-col); i++)
- data.push_back(d);
- break;
- default:
- badfilec( "Invalid setting for incorrect_column width: %c\n",incorrect_column);
- }
- }
- else // This row is too long
- {
- switch(incorrect_column)
- {
- case EXIT:
- badfilec( "number of columns %d at row %d does not match width of previous rows (%d)\n", col, row, w);
- case COPY_ADJACENT:
- case FILL_ZERO: // Warning! Falling case!
- case FILL_MEAN:
- warn( "number of columns %d at row %d does not match; fill_mean and fill_zero no ready yet for this case.\n",col,row);
- warn( "dropping column.");
- while(col > w)
- {
- data.pop_back();
- col--;
- }
- break;
- case DROP:
- data.erase(data.begin(),data.begin()+(row*w));
- row = 0;
- w = col;
- break;
- default:
- badfilec( "Invalid argument for -i: %c\n",incorrect_column);
- }
-
- }
-
- }
- row++;
- assert((int)data.size() == row * w);
- }
- h = row;
-
- fclose(fp);
-
- width = w;
- height = h;
- reallocate();
-
- for (int i=0; i<width*height; i++)
- raw_data[i] = data[i];
-
- data3d = false;
- store_orig();
- return 0;
-}
-
-void ImageData::find_raw_limits()
-{
- rawmin = INFINITY;
- rawmax = -INFINITY;
-
- for (int i=0; i<width*height; i++)
- {
- if (raw_data[i] < rawmin) rawmin = raw_data[i];
- if (raw_data[i] > rawmax) rawmax = raw_data[i];
- }
-}
-
-void ImageData::quantize()
-{
- if (auto_quant)
- {
- find_raw_limits();
- qmin = (rawmin+rawmax)/2 - (rawmax-rawmin)/2/auto_quant_percent*100;
- qmax = (rawmin+rawmax)/2 + (rawmax-rawmin)/2/auto_quant_percent*100;
- }
-
- for (int i=0; i<width*height; i++)
- quant_data[i] = raw_to_quant(raw_data[i]);
-}
-
-void ImageData::log10(bool do_offset, double new_offset)
-{
- // Refresh the rawmin and rawmax variables
- if (do_offset) find_raw_limits();
-
- if (do_offset)
- for (int i=0; i<width*height; i++)
- raw_data[i] = log(raw_data[i]-rawmin+new_offset)/log(10.0);
- else
- for (int i=0; i<width*height; i++)
- raw_data[i] = log(raw_data[i])/log(10.0);
-}
-
-void ImageData::magnitude()
-{
- for (int i=0; i<width*height; i++)
- raw_data[i] = fabs(raw_data[i]);
-}
-
-void ImageData::neg()
-{
- for (int i=0; i<width*height; i++)
- raw_data[i] = -raw_data[i];
-}
-
-void ImageData::offset(double offset, bool do_auto)
-{
- if (do_auto) find_raw_limits();
-
- for (int i=0; i<width*height; i++)
- raw_data[i] = raw_data[i]+offset-(do_auto ? rawmin : 0);
-
-}
-
-void ImageData::scale(double factor)
-{
- for (int i=0; i<width*height; i++)
- raw_data[i] = raw_data[i]*factor;
-}
-
-void ImageData::gamma(double gamma, double epsilon)
-{
- // This is tricky: what to do if we have a negative power and we get zero?
- // To handle this nicely, we should add an epsilon.
- double v1,v2;
- for (int i=0; i<width*height; i++)
- {
- v1 = raw_data[i];
- // problems with 1/0
- if (fabs(v1) < fabs(epsilon) && gamma<0)
- {
- if (v1<0) v1 = -fabs(epsilon);
- else if (v1>0) v1 = fabs(epsilon);
- else v1 = fabs(epsilon);
- }
- v2 = pow(v1, gamma);
- //if (!isfinite(v2))
- //info("v1 %e v2 %e eps %e\n", v1, v2, epsilon);
- if (isnan(v2))
- raw_data[i] = 0;
- else
- raw_data[i] = v2;
-
- }
-}
-
-// calculate a 2D histogram of the dataset
-// For each x-value, tranform the y axis of the dataset into a histogram of the measured datavalues
-
-void ImageData::hist2d(double dmin, double dmax, int num_bins)
-{
- int new_height = num_bins;
- int histogram[new_height];
- double tmp;
- int i,j;
-
- // never shrink the arrays (leads to segfaults somewhere...)
- double *new_data;
- if (width * new_height > orig_width*orig_height)
- new_data = new double[width*new_height];
- else
- new_data = new double[orig_width*orig_height];
-
- for (i=0; i<width; i++)
- {
- for (j=0; j<new_height; j++)
- histogram[j] = 0;
- for (j=0; j<height; j++)
- {
- tmp = (raw(i,j)-dmin)/(dmax-dmin)*new_height;
- if (tmp >= 0 && tmp < new_height)
- histogram[(int)tmp]++;
- }
- for (j=0; j<new_height; j++)
- new_data[j*width+i] = histogram[new_height-1-j];
- }
- ymin = dmin;
- ymax = dmax;
-
- delete [] raw_data;
- raw_data = new_data;
- resize_tmp_arrays(width, new_height);
- height = new_height;
-}
-
-void ImageData::interpolate(int new_width, int new_height, int type)
-{
- if (new_width == width && new_height == height)
- return;
-
- // Had some trouble with segfaults. It's safest to just only make
- // matrices bigger if needed (don't shrink ones).
- double *new_data;
- if (new_width * new_height > orig_width*orig_height)
- new_data = new double[new_width*new_height];
- else
- new_data = new double[orig_width*orig_height];
-
- double x_step = (double)width/(double)new_width;
- double y_step = (double)height/(double)new_height;
-
- for (int j=0; j<new_height; j++)
- for (int i = 0; i<new_width; i++)
- new_data[j*new_width+i] = raw_interp(i*x_step,j*y_step);
-
- delete [] raw_data;
- raw_data = new_data;
-
- resize_tmp_arrays(new_width, new_height);
-
- width = new_width;
- height = new_height;
-}
-
-void ImageData::calculate_thresholds(int type,
- double low, double high,
- double bottom_limit, double top_limit)
-{
- // Only data points that lie within {min,max} will be counted,
- // others will be rejected.
-
- double min, max;
-
- // type = 0 = image percentiles
- // type = 1 = line percentiles, with optional limits
- // type = 2 = column percentiles, with optional limits
- // type = 3 = manual value thresholding
-
- // Easy one: a single threshold for the whole image
- if (type == 0 || type == 3)
- {
- if (type == 0)
- find_image_threasholds(low, high, min, max);
- else if (type == 3)
- {
- min = low; max = high;
- if (min > max) min = max;
- }
- for (int i=0; i<width*height; i++)
- {
- if (raw_data[i] > min && raw_data[i] < max)
- threshold_reject[i] = 0;
- else
- threshold_reject[i] = 1;
- }
- }
-
- // The more difficult ones: thresholds based on percentages for a
- // given row or column
-
- else if (type == 1)
- {
- vector <double> line_data;
- for (int j=0; j<height; j++)
- {
- line_data.clear();
- for (int i=0; i<width; i++)
- if (raw(i,j) > bottom_limit && raw(i,j) < top_limit)
- line_data.push_back(raw(i,j));
- find_threasholds(line_data, low, high, min, max);
- for (int i=0; i<width; i++)
- {
- if(raw(i,j) > min && raw(i,j) < max)
- threshold_reject[j*width+i] = 0;
- else
- threshold_reject[j*width+i] = 1;
- }
- }
- }
- else //if (type == 2)
- {
- vector <double> col_data;
- for (int i=0; i<width; i++)
- {
- col_data.clear();
- for (int j=0; j<height; j++)
- if (raw(i,j) > bottom_limit && raw(i,j) < top_limit)
- col_data.push_back(raw(i,j));
- find_threasholds(col_data, low, high, min, max);
- for (int j=0; j<height; j++)
- {
- if(raw(i,j) > min && raw(i,j) < max)
- threshold_reject[j*width+i] = 0;
- else
- threshold_reject[j*width+i] = 1;
- }
- }
- }
-}
-
-// A handy simple way to calculate threasholds for things like line
-// cuts. Note that you have to put the data first into an STL
-// container. It is more expensive, though.
-
-void ImageData::find_threasholds(vector <double> data,
- double bottom_percent, double top_percent,
- double &low, double &high)
-{
- if (bottom_percent < 0) bottom_percent = 0;
- if (bottom_percent > 100) bottom_percent = 100;
-
- if (top_percent < 0) top_percent = 0;
- if (top_percent > 100) top_percent = 100;
-
- sort(data.begin(), data.end());
- int low_index = (int) (data.size()*bottom_percent/100.0);
- int high_index = (int) (data.size()*(100-top_percent)/100.0-1);
- low = data[low_index];
- high = data[high_index];
-}
-
-// A function which calculates threasholds for the whole image using
-// the same truncation method we use to calculate the histogram, which
-// should be faster than putting the whole dataset in an stl container
-// and sorting it.
-
-void ImageData::find_image_threasholds(double bottom_percent, double top_percent,
- double &low, double &high)
-{
- int levels = 1000;
- int histogram[levels];
-
- double tmp;
- int i;
- int lowint, highint;
- int count;
-
- find_raw_limits();
-
- if (bottom_percent < 0) bottom_percent = 0;
- if (bottom_percent > 100) bottom_percent = 100;
-
- if (top_percent < 0) top_percent = 0;
- if (top_percent > 100) top_percent = 100;
-
- for (i=0; i<levels; i++)
- histogram[i] = 0;
-
- for (i=0; i<width*height; i++)
- {
- tmp = (raw_data[i]-rawmin)/(rawmax-rawmin)*levels;
- if (tmp < 0 || tmp > levels)
- {
- info("tmp is %g \n", tmp);
- }
- histogram[(int)tmp]++;
- }
-
- count = 0;
- for (lowint=0; lowint<levels; lowint++)
- {
- count += histogram[lowint];
- if (count > bottom_percent/100.0*width*height) break;
- }
- low = rawmin + lowint*(rawmax-rawmin)/levels;
-
- count = 0;
- for (highint=levels-1; highint>=0; highint--)
- {
- count += histogram[highint];
- if (count > top_percent/100.0*width*height) break;
- }
- high = rawmin + highint*(rawmax-rawmin)/levels;
-
- info("image threashold: min %e max %e\n", low, high);
-}
-
-void ImageData::remove_lines(int start, int nlines)
-{
- for (int y = start; y < height - nlines; y++)
- memcpy(raw_data+y*width, raw_data+(y+nlines)*width, sizeof(double)*width);
- double new_ymin = getY(height-nlines);
- height = height-nlines;
- ymin = new_ymin;
-}
-
-void ImageData::lbl(double bp, double tp,
- bool whole_image_threashold, bool percentiles,
- double bottom_limit, double top_limit)
-{
- double line_average;
- int navg;
-
- int type;
-
- if (percentiles & whole_image_threashold)
- type = 0;
- else if (percentiles)
- type = 1;
- else //if (!percentiles)
- type = 3;
-
- calculate_thresholds(type, bp, tp, bottom_limit, top_limit);
- double offset;
-
- for (int j=0; j<height; j++)
- {
- line_average = navg = 0;
- for (int i=0; i<width; i++)
- if (!threshold_reject[j*width+i])
- {
- line_average += raw(i,j);
- navg++;
- }
- if (navg != 0)
- {
- line_average /= navg;
- offset = line_average;
- }
- for (int i=0; i<width; i++)
- raw(i,j) -= offset;
- }
-}
-
-void ImageData::cbc(double bp, double tp,
- bool whole_image_threashold, bool percentiles,
- double bottom_limit, double top_limit)
-{
- double col_average;
- int navg;
-
- int type;
-
- if (percentiles & whole_image_threashold)
- type = 0;
- else if (percentiles)
- type = 2;
- else //if (!percentiles)
- type = 3;
-
- calculate_thresholds(type, bp, tp, bottom_limit, top_limit);
-
- for (int i=0; i<width; i++)
- {
- col_average = navg = 0;
- for (int j=0; j<height; j++)
- if (!threshold_reject[j*width+i])
- {
- col_average += raw(i,j);
- navg++;
- }
- if (navg != 0) col_average /= navg;
-
- for (int j=0; j<height; j++)
- raw(i,j) -= col_average;
- }
-}
-
-void ImageData::outlier_line(bool horizontal, int pos)
-{
- int cnt=0; // Number of lines averaged
- if(horizontal)
- {
- if(pos > height || pos < 0)
- return;
- for(int i = 0; i < width; i++)
- raw(i,pos)=0;
- if(pos-1 >= 0)
- {
- for(int i = 0; i < width; i++)
- raw(i,pos)=raw(i,pos)+raw(i,pos-1);
- cnt++;
- }
- if(pos+1 < height)
- {
- for(int i = 0; i < width; i++)
- raw(i,pos)=raw(i,pos)+raw(i,pos+1);
- cnt++;
- }
- if(cnt > 1)
- for(int i = 0; i < width; i++)
- raw(i,pos) = raw(i,pos)/cnt;
- }
- else
- {
- if(pos > width || pos < 0)
- return;
- for(int i = 0; i < height; i++)
- raw(pos,i)=0;
- if(pos-1 >= 0)
- {
- cnt++;
- for(int i = 0; i < height; i++)
- raw(pos,i)=raw(pos,i)+raw(pos-1,i);
- }
- if(pos+1 < width)
- {
- cnt++;
- for(int i = 0; i < height; i++)
- raw(pos,i)=raw(pos,i)+raw(pos+1,i);
- }
- if(cnt > 1)
- for(int i = 0; i < height; i++)
- raw(pos,i) = raw(pos,i)/cnt;
- }
-}
-void ImageData::sub_linecut(bool horizontal, int pos)
-{
- if(horizontal)
- {
- if(pos >= height || pos < 0)
- return;
- for(int j = 0; j < height; j++)
- for(int i = 0; i < width; i++)
- if (j != pos) raw(i,j) -= raw(i,pos);
- for(int i = 0; i < width; i++)
- raw(i,pos) = 0;
- }
- else
- {
- if(pos >= width || pos < 0)
- return;
- for(int i = 0; i < width; i++)
- for(int j = 0; j < height; j++)
- if (i != pos) raw(i,j) -= raw(pos,j);
- for(int j = 0; j < height; j++)
- raw(pos, j) = 0;
- }
-}
-
-void ImageData::norm_lbl()
-{
- double min, max;
- for (int j=0; j<height; j++)
- {
- min = INFINITY;
- max = -INFINITY;
- for (int i=0; i<width; i++)
- {
- if (raw(i,j) < min) min = raw(i,j);
- if (raw(i,j) > max) max = raw(i,j);
- }
- for (int i=0; i<width; i++)
- raw(i,j) = (min != max) ? (raw(i,j) - min)/(max-min) : 0;
- }
-}
-
-void ImageData::norm_cbc()
-{
- double min, max;
-
- for (int i=0; i<width; i++)
- {
- min = INFINITY;
- max = -INFINITY;
- for (int j=0; j<height; j++)
- {
- if (raw(i,j) < min) min = raw(i,j);
- if (raw(i,j) > max) max = raw(i,j);
- }
- for (int j=0; j<height; j++)
- raw(i,j) = (min != max) ? (raw(i,j) - min)/(max-min) : 0;
- }
-}
-
-void ImageData::fitplane(double bp, double tp, bool percentiles)
-{
- // Formula for the plane: Z = a*X + b*Y + c
- double a,b,c;
- // calculate the moments
- int N = 0;
- double Zavg = 0;
- double Xavg = 0;
- double Yavg = 0;
- double sXZ = 0;
- double sYZ = 0;
- double sXX = 0;
- double sYY = 0;
- double val;
-
- double low, high;
- // In principle, we should call calculate_thresholds to be
- // consistent, but this is faster...
- if (percentiles)
- find_image_threasholds(bp, tp, low, high);
- else
- {
- low = bp;
- high = tp;
- }
-
- for (int x=0; x < width; x++)
- {
- for (int y=0; y < height; y++)
- {
- val = raw(x,y);
- if (val > low && val < high)
- {
- Zavg += (double) val;
- Xavg += (double) (x-width/2);
- Yavg += (double) (y-height/2);
- sXZ += (double) val * (x-width/2);
- sYZ += (double) val * (y-height/2);
- sXX += (double) (x-width/2)*(x-width/2);
- sYY += (double) (y-height/2)*(y-height/2);
- N++;
- }
- }
- }
-
- Xavg /= N;
- Yavg /= N;
- Zavg /= N;
-
- a = (sXZ - N*Xavg*Zavg)/(sXX - N*Xavg*Xavg);
- b = (sYZ - N*Yavg*Zavg)/(sYY - N*Yavg*Yavg);
- c = Zavg - a*Xavg - b*Yavg;
-
- for (int x=0; x<width; x++)
- for (int y=0; y<height; y++)
- raw(x,y) -= a * (x-width/2) + b*(y-height/2) + c;
-
- //warn( "a,b,c %e %e %e\n", a, b, c);
-}
-
-void ImageData::plane(double b, double a)
-{
- for (int x=0; x<width; x++)
- for (int y=0; y<height; y++)
- raw(x,y) -= a * (x-width/2) + b*(y-height/2);
-}
-
-void ImageData::xflip()
-{
- double tmp[width];
- for(int y = 0; y < height; y++)
- {
- memcpy(tmp,raw_data+y*width,sizeof(double)*width);
- for(int x = 0; x < width; x++)
- raw(x,y) = tmp[width-1-x];
- }
- double tmp2 = xmin;
- xmin = xmax;
- xmax = tmp2;
-}
-
-void ImageData::yflip()
-{
- double tmp[width];
- for (int y=0; y < height/2; y++)
- {
- memcpy(tmp,&raw(0,y),sizeof(double)*width);
- memcpy(&raw(0,y),&raw(0,height-y-1),sizeof(double)*width);
- memcpy(&raw(0,height-y-1),tmp,sizeof(double)*width);
- }
- double tmp2 = ymin;
- ymin = ymax;
- ymax = tmp2;
-}
-
-void ImageData::rotate_cw()
-{
- double *tmp = new double [width*height]; // should not use the stack for large arrays: use new instead
- memcpy(tmp, raw_data, sizeof(double)*width*height);
-
- for (int i=0; i<width; i++)
- for (int j=0; j<height; j++)
- raw_data[i*height+(height-1-j)] = tmp[j*width+i];
-
- double w = width;
- width = height;
- height = w;
-
- string tmpname = xname;
- xname = yname;
- yname = tmpname;
-
- // just trial and error...
- double d1 = ymin;
- double d2 = ymax;
- ymin = xmax;
- ymax = xmin;
- xmin = d1;
- xmax = d2;
- delete [] tmp;
-}
-
-void ImageData::rotate_ccw()
-{
- double *tmp = new double [width*height]; // should not use the stack for large arrays: use new instead
- memcpy(tmp, raw_data, sizeof(double)*width*height);
-
- for (int i=0; i<width; i++)
- for (int j=0; j<height; j++)
- raw_data[(width-1-i)*height+j] = tmp[j*width+i];
-
-
- double w = width;
- width = height;
- height = w;
-
- string tmpname = xname;
- xname = yname;
- yname = tmpname;
-
- // just trial and error...
- double d1 = ymax;
- double d2 = ymin;
- ymin = xmin;
- ymax = xmax;
- xmin = d1;
- xmax = d2;
- delete [] tmp;
-}
-
-void ImageData::pixel_average(int nx, int ny)
-{
- if (nx == 0 || ny == 0) return;
-
- int w = width / nx;
- int h = height / ny;
- double tmp;
-
- // This should work in-place, since we're only overwriting data we
- // don't need anymore
-
- // For in-place to work, we must have the inner loop iterating over
- // i, since this is the data order axis!
-
- for (int j=0; j<h; j++)
- for (int i=0; i<w; i++)
- {
- tmp = 0;
- for (int m=0; m<nx; m++)
- for (int n=0; n<ny; n++)
- tmp += raw(nx*i+m,ny*j+n)/nx/ny;
- raw_data[j*w+i] = tmp;
- }
-
- width = w;
- height = h;
-}
-
-void ImageData::switch_finder(double threshold, int avgwin, bool vert) //note: vert not yet implemented: is there a better way than cut and paste?
-{
- int i,j,m,n;
- double offset = 0;
- double avg1 = 0 ;
- double avg2 = 0 ;
- threshold = fabs(threshold);
- if (avgwin < 1) avgwin = 1;
-
- // In principle, this is a very easy piece of code to write, but the
- // it could be really, really amazingly useful!
- for (j=0; j<height; j++)
- {
- offset = 0;
- for (i=1; i<width; i++)
- {
- // Add running offset to current data
- raw(i,j) += offset;
- // Calculate avg from last "avgwin" points
- for (m=1,n=0,avg1=0; m<=avgwin; m++)
- if (i-m >= 0)
- {
- avg1 += raw(i-m,j);
- n++;
- }
- if (n>0) avg1 = avg1/n;
- // If our next point deviates from the average by enough, then we've got switch
- if (fabs(raw(i,j)-avg1) > threshold)
- {
- // Calculate the average for the next "avgwin" points too, and ignore subsequent points that might be a switch
- avg2 = offset; n = 1;
- for (m=0; m<=avgwin; m++)
- if (i+m < width && fabs(raw(i+m,j)+offset-raw(i,j)) < threshold)
- {
- avg2 += raw(i+m,j) + offset;
- n++;
- }
- avg2 = avg2/n;
- avg2 = raw(i,j);
- offset += avg1 - avg2;
- raw(i,j) += avg1 - avg2;
- }
- }
- }
-}
-
-
-void ImageData::xderv()
-{
- int w = width-1;
- int h = height;
-
- double xstep = (xmax - xmin)/w;
-
- for (int j=0; j<h; j++)
- for (int i=0; i<w; i++)
- raw_data[j*w+i] = (raw(i+1,j) - raw(i,j))/xstep;
- //raw_data[j*w+i] = (xmin<xmax) ? (raw(i+1,j) - raw(i,j)) : (raw(i,j) - raw(i+1,j));
-
- xmin = xmin+(xmax-xmin)/width/2;
- xmax = xmax-(xmax-xmin)/width/2;
- width = w;
- height = h;
-}
-
-void ImageData::crop(int left, int right, int lower, int upper)
-{
- // Let's be a bit clever: negative numbers on lower or right should
- // be interpreted as counting from the left or bottom. Also
- // implement smarter bounds checking (overflow large numbers).
-
- if (left > width-1) left = left % (width);
- if (right > width-1) right = right % (width);
- if (upper > height-1) upper = upper % (height);
- if (lower > height-1) lower = lower % (height);
-
- if (left < 0) left = left + (-left/width+1)*width - 1;
- if (upper < 0) upper = upper + (-upper/height+1)*height - 1;
- if (right <= 0) right = right + (-right/width+1)*width;
- if (lower <= 0) lower = lower + (-lower/height+1)*height;
-
- // Now check that things make sense
- // Modified April 2010 -- the below crashed if right was at edge already.
- if (lower < upper)
- std::swap(upper,lower);
- if (right < left)
- std::swap(left,right);
-
- // Finally, make sure that we aren't cropping to nothing.
- if(lower == upper)
- if(upper > 0)
- upper--;
- else
- lower++;
- if(left == right)
- if(left > 0)
- left--;
- else
- right++;
-
- int w = (right-left);
- int h = (lower-upper);
-
- for (int j=0; j<h; j++)
- for (int i=0; i<w; i++)
- raw_data[j*w+i] = raw(i+left, j+upper);
-
- double newxmin = getX(left);
- double newxmax = getX(right-1);
-
- double newymin = getY(lower-1);
- double newymax = getY(upper);
-
- xmin = newxmin; xmax = newxmax;
- ymin = newymin; ymax = newymax;
-
- width = w;
- height = h;
-}
-
-void ImageData::even_odd(bool even, bool fwd_rev)
-{
- int h = height/2;
- if (!even) h -= height%2;
-
- int off = even ? 0 : 1;
-
- if (even || !fwd_rev)
- {
- for (int j=0; j<h; j++)
- memcpy(&raw(0,j), &raw(0,2*j+off), sizeof(double)*width);
- }
- else
- {
- for (int j=0; j<h; j++)
- for (int i=0; i<width; i++)
- raw(i,j) = raw(width-1-i,2*j+off);
- }
-
-
- height = h;
-}
-
-
-void ImageData::yderv()
-{
- int w = width;
- int h = height-1;
-
- // Another one of those negative signs...
- double ystep = -(ymax - ymin)/h;
-
- for (int j=0; j<h; j++)
- for (int i=0; i<w; i++)
- raw_data[j*w+i] = (raw(i,j+1) - raw(i,j))/ystep;
- //raw_data[j*w+i] = (ymin>ymax) ? (raw(i,j+1) - raw(i,j)) : (raw(i,j) - raw(i,j+1));
-
- ymin = ymin+(ymax-ymin)/height/2;
- ymax = ymax-(ymax-ymin)/height/2;
- width = w;
- height = h;
-}
-
-void ImageData::ederv(double pscale, double nscale)
-{
- int w = width;
- int h = height-1;
- int h0 = -ymin * h / (ymax - ymin);
- printf("ymin is %g, ymax is %g, h is %d, h0 is %d\n",ymin,ymax,h,h0);
- for (int j=0; j<h; j++)
- for (int i=0; i<w; i++)
- {
- int sign=1;
- if(j < h0)
- sign=-1;
- else if ( j == h0 || j+1 == h0) // Not clear what to do exactly at zero.
- sign = 0;
- raw_data[j*w+i] = ((ymin>ymax) ? (raw(i,j+1) - raw(i,j)) : (raw(i,j) - raw(i,j+1))) * sign;
- if(raw_data[j*w+i] < 0)
- raw_data[j*w+i] *= nscale;
- else
- raw_data[j*w+i] *= pscale;
- }
-
- ymin = ymin+(ymax-ymin)/height/2;
- ymax = ymax-(ymax-ymin)/height/2;
- width = w;
- height = h;
-}
-
-void ImageData::grad_mag(double axis_bias)
-{
- printf("%g bias\n",axis_bias);
- int w = width;
- int h = height;
- double *tmpx = (double *)malloc(sizeof(double) * width * height);
-
- memcpy(tmpx,raw_data,sizeof(double)*width*height);
- xderv();
- width = w;
- height = h;
- swap(tmpx,raw_data);
- yderv();
- width = w;
- height = h;
- double *result = (double *)malloc(sizeof(double) * (width-1) * (height-1));
- for(int x = 0; x < width-1; x++)
- for(int y = 0; y < height-1; y++)
- {
- double g1 = tmpx[x+(width-1)*y];
- double g2 = raw_data[x+width*y];
- result[x+(width-1)*y] = sqrt(g1*g1*(1.0-axis_bias)+g2*g2*axis_bias);
- }
- memcpy(raw_data,result,sizeof(double)*(width-1)*(height-1));
- free(result);
- free(tmpx);
- width = width-1;
- height = height-1;
-}
-
-void ImageData::equalize() // Hist. eq.. We work on the quantized data here for simplicity.
-{
- quantize();
- int cumsum[QUANT_MAX+1];
- int mapping[QUANT_MAX+1];
-
- // Generate the cumulative sum.
- memset(cumsum, 0, sizeof(cumsum));
- int *p = quant_data;
- for(int i = 0; i < width*height; i++)
- {
- assert(*p <= QUANT_MAX && *p >= 0);
- cumsum[*p++]++;
- }
- for(int i = 1; i <= QUANT_MAX; i++)
- cumsum[i] += cumsum[i-1];
-
- // Find the minimum value.
- int minval = -1;
- for(int i = 0; i <= QUANT_MAX; i++)
- if(cumsum[i] != 0)
- {
- minval = cumsum[i];
- break;
- }
- assert(minval >= 0);
-
- // Generate the mapping; see http://en.wikipedia.org/wiki/Histogram_equalization
- for(int i = 0; i <= QUANT_MAX; i++)
- {
- mapping[i]=round((1.0*cumsum[i]-1.0*minval)*(QUANT_MAX*1.0)/(1.0*width*height-1.0*minval));
- }
-
- // Apply the mapping using an extra-clever linear interpolation on the floating point data! Yay!
- for(int i = 0; i < width*height; i++)
- {
- double raw = raw_data[i];
- double v = 1.0*(raw-qmin)*QUANT_MAX/(qmax-qmin);
- assert(v >= 0 && floor(v) < QUANT_MAX);
- double dv = v-floor(v);
- assert(dv >= 0);
- assert(dv <= 1.0);
- double quant = mapping[(int)v]*(1.0-dv)+mapping[(int)(v+0.5)]*dv;
- raw_data[i] = quant_to_raw(quant);
- }
-}
-
-void ImageData::dderv(double theta) // theta in degrees!
-{
- int w = width;
- int h = height;
- double *tmpx = (double *)malloc(sizeof(double) * width * height);
-
- memcpy(tmpx,raw_data,sizeof(double)*width*height);
- xderv();
- width = w;
- height = h;
- swap(tmpx,raw_data);
- yderv();
- width = w;
- height = h;
- double *result = (double *)malloc(sizeof(double) * (width-1) * (height-1));
- double t1=cos(theta*M_PI/180.0);
- double t2=sin(theta*M_PI/180.0);
- for(int x = 0; x < width-1; x++)
- for(int y = 0; y < height-1; y++)
- {
- double g1 = tmpx[x+(width-1)*y];
- double g2 = raw_data[x+width*y];
- result[x+(width-1)*y] = g1*t1+g2*t2;
- }
- memcpy(raw_data,result,sizeof(double)*(width-1)*(height-1));
- free(result);
- free(tmpx);
- width = width-1;
- height = height-1;
-}
-
-
-void ImageData::make_lowpass_kernel(double *data, double dev, int size, ImageData::lowpass_kernel_t type)
-{
- double center = floor(size/2.0);
- double sum = 0.0;
- for(int i = 0; i < size; i++)
- {
- double dx = (static_cast<double>(i)-center);
- dx /= dev;
- double y;
- switch(type)
- {
- case LOWPASS_GAUSS:
- y = exp(-(dx*dx)/(2.0));
- break;
- case LOWPASS_EXP:
- y = exp(-fabs(dx)*sqrt(2.0));
- break;
- case LOWPASS_LORENTZ:
- // Lorentzian has no std. dev, so set FWHM = sigma
- y = 1.0/(dx*dx+1.0);
- break;
- case LOWPASS_THERMAL: // Derivative of Fermi function; dev is temperature in pixels
- y = exp(dx)/(dev*(1+exp(dx))*(1+exp(dx)));
- break;
- default:
- assert(0);
- }
- sum += y;
- data[i] = y;
- }
- sum = 1.0/sum;
- for(int i = 0; i < size; i++)
- data[i] *= sum;
-}
-
-// This executes a gaussian blur low pass filter
-void ImageData::lowpass(double xsize, double ysize, ImageData::lowpass_kernel_t type, double mult)
-{
- int kernel_size;
- double sum;
-
- if (xsize == 0 && ysize == 0)
- return;
-
- kernel_size = xsize*mult;
- if (kernel_size > 0 && kernel_size < mult) kernel_size = mult;
-
- if (kernel_size > 0)
- {
- // For really big images, I think it is better not to reallocate an entire 2D image array (?)
- double filtered[width];
- double kernel[kernel_size];
- make_lowpass_kernel(kernel, xsize, kernel_size,type);
- int kernel_offset = -kernel_size/2;
-
- for(int y = 0; y < height; y++)
- {
- for(int x = 0; x < width; x++)
- {
- sum = 0.0;
- for(int k = 0; k < kernel_size; k++)
- {
- int nx = x + k + kernel_offset;
- if(nx < 0) nx = 0;
- if(nx >= width) nx = width-1;
- sum += kernel[k]*raw(nx,y);
- }
- filtered[x] = sum;
- }
- memcpy(&raw(0,y), filtered, sizeof(double)*width);
- }
- }
-
- kernel_size = ysize*mult;
-
- if (kernel_size > 0 && kernel_size < mult) kernel_size = mult;
-
- if (kernel_size > 0)
- {
- double filtered[height];
- double kernel[kernel_size];
- make_lowpass_kernel(kernel, ysize, kernel_size,type);
- int kernel_offset = -kernel_size/2;
-
- for(int x = 0; x < width; x++)
- {
- for(int y = 0; y < height; y++)
- {
- sum = 0.0;
- for(int k = 0; k < kernel_size; k++)
- {
- int ny = y + k + kernel_offset;
- if(ny < 0) ny = 0;
- if(ny >= height) ny = height-1;
- sum += kernel[k]*raw(x,ny);
- }
- filtered[y] = sum;
- }
- for(int y = 0; y < height; y++)
- raw(x,y) = filtered[y]; // can't use memcpy here
- }
- }
-}
-
-// This could be made much more memory efficent if need be; see lowpass.
-void ImageData::highpass(double xsize, double ysize, double passthrough, ImageData::lowpass_kernel_t type, double mult)
-{
- double *d2 = new double[width*height];
- assert(d2);
- memcpy(d2,raw_data,sizeof(double)*width*height);
- lowpass(xsize,ysize,type,mult);
- for(int x = 0; x < width; x++)
- for(int y = 0; y < height; y++)
- raw(x,y)=d2[y*width+x]-(1.0-passthrough)*raw(x,y);
- delete[] d2;
-}
-
-void ImageData::notch(double xlow, double xhigh, double ylow, double yhigh, double mult) // width is width of mask to use measured in units of xsize, ysize
-{
- lowpass(xlow,ylow,LOWPASS_GAUSS,mult);
- highpass(xhigh,yhigh,0.0,LOWPASS_GAUSS,mult);
-}
-
-// Despeckle an image with a median filter
-// Helper functions
-inline static int median_3(double a, double b, double c)
-{
- if(((a <= b) && (b <= c)) || ((c <= b) && (b <= a)))
- return b;
- if(((b <= c) && (c <= a)) || ((a <= c) && (c <= b)))
- return c;
- return a;
-}
-static int compare_doubles(const void *ap, const void *bp)
-{
- double a = *reinterpret_cast<const double *>(ap);
- double b = *reinterpret_cast<const double *>(bp);
- if(a < b)
- return -1;
- if(a == b)
- return 0;
- return 1;
-}
-inline static int median_3x3(double *r1, double *r2, double *r3)
-{
- double tmp[9];
- memcpy(tmp, r1, sizeof(double)*3);
- memcpy(tmp+3, r2, sizeof(double)*3);
- memcpy(tmp+6, r3, sizeof(double)*3);
- qsort(tmp, 9, sizeof(double), compare_doubles);
- return tmp[4];
-}
-// Main functions
-void ImageData::despeckle(bool d_x, bool d_y)
-{
- if(d_x && d_y)
- {
- double *tmp = new double[width * height];
- memcpy(tmp,raw_data,sizeof(double)*width*height);
- for(int x = 1; x < width-1; x++)
- for(int y = 1; y < height-1; y++)
- raw(x,y) = median_3x3(tmp+(y-1)*width+x-1,tmp+y*width+x-1, tmp+(y+1)*width+x-1);
- delete[] tmp;
- }
- else if(d_x)
- {
- double tmp[width];
- for(int y = 0; y < height; y++)
- {
- for(int x = 1; x < (width-1); x++)
- tmp[x] = median_3(raw(x-1,y),raw(x,y),raw(x+1,y));
- for(int x = 1; x < (width-1); x++)
- raw(x,y) = tmp[x];
- }
- }
- else if(d_y)
- {
- double tmp[height];
- for(int x = 0; x < width; x++)
- {
- for(int y = 1; y < (height-1); y++)
- tmp[y] = median_3(raw(x,y-1),raw(x,y),raw(x,y+1));
- for(int y = 1; y < (height-1); y++)
- raw(x,y) = tmp[y];
- }
- }
-}
-
-
-MTX_Data::MTX_Data()
-{
- size[0] = size[1] = size[2] = 0;
- data_loaded = 0;
- progress_gui = true;
- delft_raw_units = true;
- delft_settings = false;
- win = NULL;
-}
-
-MTX_Data::~MTX_Data()
-{
- clear();
-}
-
-void MTX_Data::open_progress_gui()
-{
- if (win == NULL)
- {
- win = new Fl_Double_Window(220,25, "Loading file...");
- win->begin();
- msg = new Fl_Output(0,0,220,25);
- msg->color(FL_BACKGROUND_COLOR);
- win->end();
- }
- win->show();
-}
-
-void MTX_Data::close_progress_gui()
-{
- win->hide();
-}
-
-
-int MTX_Data::load_file(const char *name)
-{
- FILE *fp = fopen(name, "rb");
- if(fp == NULL)
- badfile("Unable to open file \"%s\": %s\n",name,strerror(errno));
- filename = name;
-
- char buf[MTX_HEADER_SIZE];
- int i,j,k;
- fgets(buf, sizeof(buf), fp);
- int bytes = 8;
-
- char units_header[MTX_HEADER_SIZE]; // 256 characters is not long enough...
- int found_units = 0;
-
- // First read the header information, which include the axis ranges and names
-
- if (strncmp(buf, "Units", 5) == 0)
- {
- found_units = 1;
- strncpy(units_header, buf, sizeof(buf));
- fgets(buf, sizeof(buf), fp); // fixme ; check for errors here.
- }
- if (sscanf(buf, "%d %d %d", &size[0], &size[1], &size[2]) != 3)
- badfilec("Malformed mtx header: %s", filename.c_str());
- if (sscanf(buf, "%*d %*d %*d %d", &bytes) != 1)
- warn( "Legacy mtx file found (%s): assuming double data (bytes = %d)\n", filename.c_str(), bytes);
-
- clear();
- data = new double [size[0]*size[1]*size[2]];
- data_loaded = 1;
-
-
- bool progress = (size[0]*size[1]*size[2]) > 100*100*100*5;
-
- int t1 = time(NULL);
-
- if (progress && progress_gui)
- {
- open_progress_gui();
- msg->value("Reading file: 0%");
- }
-
- static char msgbuf[256];
-
- // Now actually read the data in from the file
-
- for (i=0; i<size[0]; i++)
- {
- for (j=0; j<size[1]; j++)
- for (k=0; k<size[2]; k++)
- {
- if (bytes == 4)
- {
- float tmp;
- if (fread(&tmp, bytes, 1, fp) != 1)
- badfilec( "Short read on mtx file: %s", filename.c_str());
- if (isnan(tmp)) warn( "nan at %d %d %d", i, j, k);
- getData(i,j,k) = tmp;
- }
- else if (bytes == 8)
- {
- double tmp;
- if (fread(&tmp, bytes, 1, fp) != 1)
- badfilec( "Short read on mtx file: %s", filename.c_str());
- getData(i,j,k) = tmp;
- }
- else
- badfile( "Unsupported number of bytes %d", bytes);
- }
- if (progress_gui)
- Fl::check();
- if (progress)
- {
- snprintf(msgbuf,sizeof(msgbuf), "Reading File: %.0f%%", 1.0*i/(size[0]-1)*100.0);
- if (progress_gui)
- msg->value(msgbuf);
- else
- info("%s\r", msgbuf);
- }
- }
-
- if (!progress_gui && progress)
- info("\n");
-
- if (progress_gui && progress)
- close_progress_gui();
-
- int t2 = time(NULL);
- // Output timing info here if you want
-
- if (found_units)
- {
- char *p = strtok(units_header, ",");
- p = strtok(0, ",");
- while (isspace(*p)) p++;
- dataname = p;
- for (int i = 0; i<3; i++)
- {
- p = strtok(0, ",");
- while (isspace(*p)) p++;
- axisname[i] = p;
- p = strtok(0, ",");
- while (isspace(*p)) p++;
- sscanf(p, "%lf", &axismin[i]);
- p = strtok(0, ",");
- while (isspace(*p)) p++;
- sscanf(p, "%lf", &axismax[i]);
- }
- }
- else
- {
- dataname = "Data Value";
- axismin[0] = axismin[1] = axismin[2] = 0;
- axismax[0] = size[0]; axisname[0] = "X";
- axismax[1] = size[1]; axisname[1] = "Y";
- axismax[2] = size[2]; axisname[2] = "Z";
- }
-
- data_loaded = 1;
- fclose(fp);
- return 0;
-}
-
-
-// Load data from a gnuplot formatted files into a 3D matrix.
-// Here, we use the index number as the third dimensiont of the 3d matrix.
-// The user must specify which column of the gnuplot file the data should be read from.
-
-int MTX_Data::load_gp_index(const char *name, int colnum)
-{
- vector<double> datavec;
- double datatmp;
- char linebuffer[LINESIZE];
- char *p;
-
-
- char sep[] = " \t\n\r";
-
- FILE *fp = fopen(name, "rb");
- if(fp == NULL)
- badfile("Unable to open file \"%s\": %s\n",name,strerror(errno));
-
- int lines_per_block; // size of the datablocks
- int line;
-
- int blocks_per_index;
- int block;
-
- int num_indices;
-
- bool first_block = true;
- bool first_index = true;
-
- line = lines_per_block = 0;
- block = blocks_per_index = 0;
- num_indices = 0;
-
- int nread = 0;
- bool block_ended = false;
- bool index_ended = false;
- int nptread = 0;
-
- bool found_data;
-
- int t1 = time(NULL);
- if (progress_gui)
- {
- open_progress_gui();
- msg->value("Lines read: 0");
- }
-
- while (1)
- {
- nread++;
- if (fgets(linebuffer, LINESIZE, fp) == NULL)
- break;
-
- // Figure out what kind of line this is
- // Get rid of spaces at beginning of line
- for(p = linebuffer; *p != 0 && isspace(*p); p++)
- ;
- // Ignore comment lines
- if(*p == '#')
- continue;
- // A blank line signals the end of a datablock or of an index
- if (*p == '\n' || *p == 0)
- {
- if (!block_ended) // We have reached the end of a block
- {
- if (first_block) //we found the end of the first block
- {
- if (line == 0) //ignore blank lines at the top of the file
- continue;
- lines_per_block = line;
- first_block = false;
- }
- if (line != lines_per_block)
- {
- info("block %d ended early, assuming incomplete file\n");
- break;
- }
- //badfilec( "block %d at line %d has %d lines < %d\n",
- //block, nread, line, lines_per_block);
- line = 0;
- block_ended = true;
- block++;
- continue;
- }
- if (!index_ended) // this means we have found two blank lines
- {
- if (first_index)
- {
- blocks_per_index = block;
- first_index = false;
- }
- if (block != blocks_per_index)
- badfilec( "index %d at line %d has %d blocks < %d\n",
- num_indices, nread, block, blocks_per_index);
- block = 0;
- index_ended = true;
- num_indices++;
- continue;
- }
- else //discard any addional blank lines after we finish an index
- continue;
- }
-
- // This line contains real data
- index_ended = block_ended = false;
-
- // Parse the line and perform the conversions
- int col = 0;
- found_data = false;
- p = strtok(linebuffer, sep);
- while (p != NULL)
- {
- if (sscanf(p, "%lf", &datatmp) != 1)
- warn("mtx gnuplot: invalid data at line %d col %d: \"%s\", copying last read value\n", nread, col, p);
- if (col == colnum)
- {
- datavec.push_back(datatmp);
- found_data = true;
- break;
- }
- col++;
- p = strtok(0, sep);
- }
-
- if (!found_data)
- badfile( "Failed to find data in column %d at line %d", colnum, nread);
- nptread++;
- line++;
-
- if (nread%100 == 0)
- {
- static char buf[256];
- snprintf(buf, sizeof(buf), "Lines read: %d", nread);
- if (progress_gui)
- {
- msg->value(buf);
- Fl::check();
- }
- else
- info("%s\r", buf);
- }
- }
-
- if (progress_gui)
- close_progress_gui();
- else
- info("\n");
-
- fclose(fp);
-
- int t2 = time(NULL);
-
- info("points: %d of %d\n", nptread, lines_per_block * blocks_per_index * num_indices);
- info("lines: %d of %d\n", line, lines_per_block);
- info("blocks: %d of %d\n", block, blocks_per_index);
- info("indices: %d\n", num_indices);
-
- if (blocks_per_index == 0) // if we're still reading the first index...
- {
- blocks_per_index = block+1;
- info("not yet finished the first index, settigns blocks_per_index to %d", blocks_per_index);
- }
-
- //if (nptread < lines_per_block * blocks_per_index * num_indices)
- if (block != 0 || line != 0) // we didn't find the end of and index or the end of a line.
- {
- num_indices++;
- int npts_needed = lines_per_block * blocks_per_index * num_indices;
- int nadd = npts_needed - nptread;
- info("looks like an incomplete file\n");
- info("will assume size is %d, %d, %d", lines_per_block, blocks_per_index, num_indices);
- info("read %d data points, need %d\n", nptread, npts_needed);
- info("adding %d points with last value found in file %e", nadd, datatmp);
- if (nadd > 0)
- for (int i = 0; i < nadd ; i++)
- datavec.push_back(datatmp);
- }
-
-// info( "lines per block %d blocks per index %d num indices %d\n", lines_per_block, blocks_per_index, num_indices);
-
-// info("Number of points read: %d\n", nptread);
-// info("Number of points expe: %d\n", lines_per_block * blocks_per_index * num_indices);
-// info("Lines per block: %d\n", lines_per_block);
-// info("Line in last block: %d\n", line);
-
- if (lines_per_block == 0 || blocks_per_index == 0 || num_indices == 0)
- return -1;
-
- // When loading data linearly into MTX matrix from gnuplot3d format, we get the following data ordering:
- // X = loop 2 = index nimber
- // Y = loop 1 = block
- // Z = sweep = point number
-
- size[0] = lines_per_block;
- size[1] = blocks_per_index;
- size[2] = num_indices;
-
- if (size[0]*size[1]*size[2] == 0)
- {
- info("file has no complete lines\n");
- return -1;
- }
-
- clear();
- data = new double [size[0]*size[1]*size[2]];
- data_loaded = 1;
-
- for (int k=0; k<size[2]; k++)
- for (int j=0; j<size[1]; j++)
- for (int i=0; i<size[0]; i++)
- getData(i,j,k) = datavec[k*size[1]*size[0]+j*size[0]+i];
-
- dataname = "Data Value";
- axismin[0] = axismin[1] = axismin[2] = 0;
- axismax[0] = size[0]; axisname[0] = "X";
- axismax[1] = size[1]; axisname[1] = "Y";
- axismax[2] = size[2]; axisname[2] = "Z";
- if (parse_txt) parse_delft_txt(name, false);
- return 0;
-}
-
-// Again loading gnuplot formatted data into a 3d matrix
-// However, this time, indices are ignored and the 3rd
-// dimension of the matrix is used to load data from
-// the different columns of the data file.
-
-int MTX_Data::load_gp_cols(const char *name)
-{
- vector<double> datavec;
- double datatmp;
- char linebuffer[LINESIZE];
- char *p;
-
- char sep[] = " \t\n\r";
-
- FILE *fp = fopen(name, "rb");
- if(fp == NULL)
- badfile("Unable to open file \"%s\": %s\n",strerror(errno));
-
- int col;
- int cols_per_line;
-
- int line;
- int lines_per_block;
-
- int num_blocks; // number of datablocks so far (note: we count
- // indexes (ie. blocks separated by two blank
- // lines) also as datablocks
-
- bool first_line = true;
- bool first_block = true;
-
- col = cols_per_line = 0;
- line = lines_per_block = 0;
- num_blocks = 0;
-
- int nread = 0;
-
- int t1 = time(NULL);
- if (progress_gui)
- {
- open_progress_gui();
- msg->value("Lines read: 0");
- }
-
- while (1)
- {
- nread++;
- if (fgets(linebuffer, LINESIZE, fp) == NULL)
- break;
-
- // Figure out what kind of line this is
-
- // Get rid of spaces at beginning of line
- for(p = linebuffer; *p != 0 && isspace(*p); p++)
- ;
-
- // Ignore comment lines
- if(*p == '#')
- continue;
-
- // A blank line signals the end of a datablock
- if (*p == '\n' || *p == 0)
- {
- if (line == 0) //ignore blank lines at the top of the file and extra blank lines between blocks
- continue;
- num_blocks++;
- if (first_block) //we found the end of the first block
- {
- lines_per_block = line;
- first_block = false;
- }
- if (line != lines_per_block) //this is possible if the dataset is not done yet, so we'll be nice and not exit
- {
- info("Block size does not match on datablock %d (line %d)! Ending file read and discarding block.\n", num_blocks, nread);
- num_blocks--;
- break;
- }
- line = 0;
- continue;
- }
-
- // Parse the line and perform the conversions
- col = 0;
- p = strtok(linebuffer, sep);
- while (p != NULL)
- {
- if (sscanf(p, "%lf", &datatmp) != 1)
- info("mtx gnuplot: invalid data at line %d col %d: \"%s\", copying last read value\n", nread, col, p);
- datavec.push_back(datatmp);
- col++;
- if (!first_line && col == cols_per_line)
- break;
- p = strtok(0, sep);
- }
- if (first_line)
- {
- first_line = false;
- cols_per_line = col;
- //info( "gp_cols: found %d columns\n", cols_per_line);
- }
- line++;
-
- if (nread%100 == 0)
- {
- static char buf[256];
- snprintf(buf, sizeof(buf), "Lines read: %d", nread);
- if (progress_gui)
- {
- msg->value(buf);
- Fl::check();
- }
- else
- info("%s\r", buf);
- }
-
- // We will ignore extra columns, but we will be cowardly and exit if
- // we don't find enough columns
- if (col < cols_per_line)
- {
- info("Too few columns at line %d, assuming incomplete file\n", nread);
- break;
- }
- }
-
- fclose(fp);
-
- if (progress_gui)
- close_progress_gui();
- else
- info("\n");
-
- // info( "gp_cols: cols_per_line %d lines_per_block %d num_blocks %d\n",
- // cols_per_line, lines_per_block, num_blocks);
-
- int t2 = time(NULL);
-
- //info("Read %d lines at %.3f thousand lines per second\n", nread, 1.0*nread/(t2-t1)/1e3);
-
- size[0] = cols_per_line;
- size[1] = lines_per_block;
- size[2] = num_blocks;
-
- if (size[0]*size[1]*size[2] == 0)
- {
- warn("file has no complete lines\n");
- return -1;
- }
-
- clear();
- data = new double [size[0]*size[1]*size[2]];
- data_loaded = 1;
-
- for (int k=0; k<size[2]; k++)
- for (int j=0; j<size[1]; j++)
- for (int i=0; i<size[0]; i++)
- getData(i,j,k) = datavec[k*size[1]*size[0]+j*size[0]+i];
-
- dataname = "Data Value";
- axismin[0] = axismin[1] = axismin[2] = 0;
- axismax[0] = size[0]; axisname[0] = "X";
- axismax[1] = size[1]; axisname[1] = "Y";
- axismax[2] = size[2]; axisname[2] = "Z";
- if (parse_txt) parse_delft_txt(name, true);
- return 0;
-}
-
-void MTX_Data::get_settings(const char *comments)
-{
- char *p = strstr(comments, "Loop 2");
- p = strstr(p, "DAC");
-
- info("getting settings\n");
- char buf[256];
- settings = " at ";
- double val;
- for (int i=1; i<= 16; i++)
- {
- //getchar();
- p = strchr(p, ' ');
- if (sscanf(p, "%lf", &val) == 1)
- {
- if (val != 0.0)
- {
- sprintf(buf, "D%d=%g ", i, val);
- settings += buf;
- }
- }
- p = strstr(p, "DAC");
- }
- info("settings:\n%s\n", settings.c_str());
-}
-
-
-
-
-// *ident is the text at the start of the line, line "Sweep " or "Loop 1".
-
-void MTX_Data::parse_comments(char *comments, const char *ident, int *dac, int *size, char *name, double *range)
-{
- double mult;
- char *p;
- char buf[256];
-
- // We never use the pulse stuff: recently modified a copy of the
- // labview to use the pulse drop down items for a second RF
- // generator.
- string extra_names[] = {
- "RF Freq",
- "RF Power",
- "RF2 Freq",
- "RF2 Power",
- "Pulse amp min",
- "Pulse amp max",
- "Pulse amp",
- "Pulse offset",
- "Magnetic Field (T)"};
-
- // First get the "dac" number
- p = strstr(comments, ident);
- sscanf(p+strlen(ident), "%d", dac);
-
- // Now get the number of steps
- p = strstr(comments, ident);
- p = strstr(p, "in ");
- sscanf(p+3, "%d", size);
-
- // If we're sweeping "nothing", then this is easy.
- if (*dac == 0)
- {
- snprintf(name, 256, "%sNumber", ident); //something like "Loop 1 Number"
- range[0] = 0;
- range[1] = *size;
- return;
- }
-
- // If this is a real DAC, then find the DAC name and the multiplier
- // from the comments
- if (*dac < 17)
- {
- int n = *dac - 1; // in commments, DAC1 becomes DAC0...
- snprintf(buf, 256, "DAC%d \"", n);
- p = strstr(comments, buf);
- strncpy(name, p+strlen(buf), 256);
- p = strchr(name, '"');
- *p = 0;
-
- p = strstr(comments, buf);
- p = strchr(p, '"');
- p = strchr(p+1, '"');
- if (sscanf(p+1, "%lf", &mult) != 1)
- {
- warn("error reading mult\n");
- mult = 1;
- }
- }
- else //otherwise, use the hard coded names for RF Freq, ..., Magnetic Field
- {
- mult = 1;
- int n = *dac-17;
- strncpy(name, extra_names[n].c_str(), 256);
- }
-
- // Now find the range
- p = strstr(comments, ident);
- p = strstr(p, "from ");
- sscanf(p+5, "%lf", &range[0]);
- p = strstr(p, "to ");
- sscanf(p+3, "%lf", &range[1]);
-
- if (!delft_raw_units)
- {
- range[0] *= mult;
- range[1] *= mult;
- }
-
- // We're done!
-}
-
-// what a mess...i should really rewrite the labview code to output meta.txt files...
-
-void MTX_Data::parse_var2_comments(char *comments, const char *ident, int *dac, char *name, double *range)
-{
- double mult;
- char *p;
- char buf[256];
-
- info("parsing var2 for %s\n", ident);
-
- string extra_names[] = {
- "RF Freq",
- "RF Power",
- "Pulse Width",
- "Pulse Freq",
- "Pulse amp min",
- "Pulse amp max",
- "Pulse amp",
- "Pulse offset",
- "Magnetic Field (T)"};
-
- // First get the "dac" number
- if ((p = strstr(comments, ident)) == NULL)
- {
- // bug in some versions of the labview...
- if (strcmp(ident, "Loop 1 var2") == 0)
- {
- p = strstr(comments, "Loop 1");
- p = strstr(p, "Sweep var2");
- if (p == NULL)
- {
- info("failed to correct for buggy labview ident %e", ident);
- return;
- }
- }
- else if (strcmp(ident, "Loop 2 var2") == 0)
- {
- p = strstr(comments, "Loop 2");
- p = strstr(p, "Sweep var2");
- if (p == NULL)
- {
- info("failed to correct for buggy labview ident %e", ident);
- return;
- }
- }
- else
- {
- info("failed to find identifier %s\n", ident);
- return;
- }
- }
-
- sscanf(p+strlen(ident), "%d", dac);
-
- // If we're sweeping "nothing", then this is easy.
- if (*dac == 0)
- {
- snprintf(name, 256, "%sNumber", ident); //something like "Loop 1 Number"
- range[0] = 0;
- range[1] = *size;
- return;
- }
-
- // If this is a real DAC, then find the DAC name and the multiplier
- // from the comments
- if (*dac < 17)
- {
- int n = *dac - 1; // in commments, DAC1 becomes DAC0...
- snprintf(buf, 256, "DAC%d \"", n);
- p = strstr(comments, buf);
- strncpy(name, p+strlen(buf), 256);
- p = strchr(name, '"');
- *p = 0;
-
- p = strstr(comments, buf);
- p = strchr(p, '"');
- p = strchr(p+1, '"');
- if (sscanf(p+1, "%lf", &mult) != 1)
- {
- warn("error reading mult\n");
- mult = 1;
- }
- }
- else //otherwise, use the hard coded names for RF Freq, ..., Magnetic Field
- {
- mult = 1;
- int n = *dac-17;
- strncpy(name, extra_names[n].c_str(), 256);
- }
-
- // Now find the range
- if ((p = strstr(comments, ident)) == NULL)
- {
- // bug in some versions of the labview...
- if (strcmp(ident, "Loop 1 var2") == 0)
- {
- p = strstr(comments, "Loop 1");
- p = strstr(p, "Sweep var2");
- if (p == NULL)
- {
- info("failed to correct for buggy labview ident %e", ident);
- return;
- }
- }
- else if (strcmp(ident, "Loop 2 var2") == 0)
- {
- p = strstr(comments, "Loop 2");
- p = strstr(p, "Sweep var2");
- if (p == NULL)
- {
- info("failed to correct for buggy labview ident %e", ident);
- return;
- }
- }
- else
- {
- info("failed to find identifier %s\n", ident);
- return;
- }
- }
-
- p = strstr(p, "from ");
- sscanf(p+5, "%lf", &range[0]);
- p = strstr(p, "to ");
- sscanf(p+3, "%lf", &range[1]);
-
- if (!delft_raw_units)
- {
- range[0] *= mult;
- range[1] *= mult;
- }
-
- // We're done!
-}
-
-void MTX_Data::parse_delft_txt(const char *name, bool columns)
-{
- char txtname[256];
- char *p;
- strncpy(txtname, name, 256);
- if ((p = strstr(txtname, ".dat")) == NULL)
- {
- warn("filename %s does not contain .dat", name);
- return;
- }
- *p=0;
- strcat(txtname, ".txt");
-
- //info("Parsing delft txt file %s\n", txtname);
- FILE *fp = fopen(txtname, "r");
- if (fp == NULL)
- {
- warn("Error opening file %s: %s\n", txtname, strerror(errno));
- return;
- }
-
- char comments[1024*10];
- fread(comments, 1, 1024*10, fp);
- fclose(fp);
-
- // Read sweep settings
- int sweep_steps;
- int loop1_steps;
- int loop2_steps;
-
- double sweep_range[2];
- double loop1_range[2];
- double loop2_range[2];
-
- int sweep_dac;
- int loop1_dac;
- int loop2_dac;
-
- char sweep_name[256];
- char loop1_name[256];
- char loop2_name[256];
-
- parse_comments(comments, "Sweep ", &sweep_dac, &sweep_steps, sweep_name, sweep_range);
- parse_comments(comments, "Loop 1 ", &loop1_dac, &loop1_steps, loop1_name, loop1_range);
- parse_comments(comments, "Loop 2 ", &loop2_dac, &loop2_steps, loop2_name, loop2_range);
-
- double sweep_var2_range[2];
- double loop1_var2_range[2];
- double loop2_var2_range[2];
-
- int sweep_var2_dac;
- int loop1_var2_dac;
- int loop2_var2_dac;
-
- char sweep_var2_name[256];
- char loop1_var2_name[256];
- char loop2_var2_name[256];
-
- parse_var2_comments(comments, "Sweep var2", &sweep_var2_dac, sweep_var2_name, sweep_var2_range);
- parse_var2_comments(comments, "Loop 1 var2", &loop1_var2_dac, loop1_var2_name, loop1_var2_range);
- parse_var2_comments(comments, "Loop 2 var2", &loop2_var2_dac, loop2_var2_name, loop2_var2_range);
-
- char buf[256];
- string sweep_extra = "";
- if (sweep_var2_dac != 0)
- {
- snprintf(buf, 256, "%.3f to %.3f", sweep_var2_range[0], sweep_var2_range[1]);
- sweep_extra = sweep_extra + " and " + sweep_var2_name + " from " + buf;
- }
-
- string loop1_extra = "";
- if (loop1_var2_dac != 0)
- {
- snprintf(buf, 256, "%.3g to %.3g", loop1_var2_range[0], loop1_var2_range[1]);
- loop1_extra = loop1_extra + " and " + loop1_var2_name + " from " + buf;
- }
-
- string loop2_extra = "";
- if (loop2_var2_dac != 0)
- {
- snprintf(buf, 256, "%.3g to %.3g", loop2_var2_range[0], loop2_var2_range[1]);
- loop2_extra = loop2_extra + " and " + loop2_var2_name + " from " + buf;
- }
-
-
- string tmp;
- if (delft_raw_units)
- tmp = " (raw mV)";
- else
- tmp = " (mV)";
-
- //if (delft_settings)
- get_settings(comments);
-
- if (!columns)
- {
- axisname[0] = sweep_name;
- axisname[0].append(tmp);
- axisname[0] += sweep_extra;
- axisname[1] = loop1_name;
- axisname[1].append(tmp);
- axisname[1] += loop1_extra;
- axisname[2] = loop2_name;
- axisname[2].append(tmp);
- axisname[2] += loop2_extra;
-
-
- // set the sweep range
- axismin[0] = sweep_range[0];
- axismax[0] = sweep_range[1];
-
- // flip is now done correctly in load_mtx_cut, so we no longer need to flip...
- axismin[1] = loop1_range[0];
- axismax[1] = loop1_range[1];
-
- // this one is fine.
- axismin[2] = loop2_range[0];
- axismax[2] = loop2_range[1];
- }
-
- else
- {
- axisname[0] = "Column Number";
- axismin[0] = 1;
- axismax[0] = size[0] + 1;
-
- axisname[1] = sweep_name;
- axisname[1].append(tmp);
- axisname[1] += sweep_extra;
-
- axismin[1] = sweep_range[0];
- axismax[1] = sweep_range[1];
-
- // Check for unfinished loop
- if (loop1_steps != size[2])
- {
- //info("loop1 %f %f steps %d size %d\n", loop1_range[0],
- //loop1_range[1], loop1_steps, size[2]);
-
- double tmp = loop1_range[0]
- + (loop1_range[1] - loop1_range[0])
- * 1.0*size[2]/loop1_steps;
- //info("Found incomplete loop: %d vs %d steps\n"
- //"Adjusting endpoint from %e to %e\n",
- //size[2], loop1_steps, loop1_range[1], tmp);
- loop1_range[1] = tmp;
- }
-
- axisname[2] = loop1_name;
- axisname[2].append(tmp);
- axisname[2] += loop1_extra;
-
- // Note: here we need to flip loop 1 endpoints
- // flip is now done correctly in load_mtx_cut, so we no longer need to flip...
- axismin[2] = loop1_range[0];
- axismax[2] = loop1_range[1];
- }
-
- //
- // A reasonable default... :)
- dataname = "Current (pA)";
- if (delft_settings)
- dataname += settings;
-}
-
-int nextline(FILE *fp, char *buf)
-{
- if (fgets(buf, LINESIZE, fp) == NULL)
- return -1;
- while (buf[0] == '#')
- if (fgets(buf, LINESIZE, fp) == NULL)
- return -1;
- //info(buf);
- return 0;
-}
-
-double nextreading(FILE *fp, int col, int &lnum)
-{
- //info("in next reading\n");
- //getchar();
- // char *buf = new char [LINESIZE]; doesn't work under windows? c++ runtime error?
- char *buf = malloc(LINESIZE*sizeof(char));
- double val;
- char *p;
-
- // Find the next line
- while (1)
- {
- lnum++;
- if (fgets(buf, LINESIZE, fp) == NULL)
- {
- val = NAN;
- break;
- }
- // Strip whitespace
- for(p = buf; *p != 0 && isspace(*p); p++);
- //Ignore comments or empty lines
- if (*p == '#' || *p == '\n' || *p == '\r' || *p == 0)
- continue;
- val = parse_reading(buf, col);
- break;
- }
-
- free(buf);
- return val;
-}
-
-double parse_reading(char *line, int col)
-{
- char sep[] = " \t\n\r";
- double val;
- int i;
- char *p;
- char *buf = strdup(line);
-
- // Now try to read the data
- p = strtok(buf, sep);
- for (i=0; i < col; i++)
- if (p != NULL) p = strtok(0,sep);
- if (p == NULL)
- {
- info("trouble parsing row for column %d:\n%s", col, line);
- val = NAN;
- }
- //info("reading: %s\n", p);
- else if (sscanf(p, "%lf", &val) != 1)
- {
- info("trouble converting column value _%s_ to a float", p);
- val = NAN;
- }
- free(buf);
- return val;
-}
-
-
-int MTX_Data::load_dat_meta(const char *name, int col)
-{
- info("read %s col %d\n", name, col);
- char *buf = new char [LINESIZE];
-
- // First open the metadata file and get the stuff we need.
- string metafile = name;
- metafile = search_replace(metafile, ".dat", ".meta.txt");
- FILE *fp = fopen(metafile.c_str(), "r");
- if (fp == NULL) return -1;
-
- // First stuff should be the axis info
- for (int i=0; i<3; i++)
- {
- if (nextline(fp, buf) == -1) return -1;
- if (sscanf(buf, "%d", &size[i]) != 1) return -1;
- if (nextline(fp, buf) == -1) return -1;
- if (sscanf(buf, "%lf", &axismin[i]) != 1) return -1;
- if (nextline(fp, buf) == -1) return -1;
- if (sscanf(buf, "%lf", &axismax[i]) != 1) return -1;
- if (nextline(fp, buf) == -1) return -1;
- axisname[i] = buf; strip_newlines(axisname[i]);
- }
-
- // a recurring theme in spyview: we need to flip the y axis range...
-
- // 19 July 2011: testing now with a file from Vincent, it seems we
- // don't need to flip the y axis?
-
- // Actually, it is handier if we do flip the y axis, otherwise we
- // need to flip the data afterwards for a conventional sweep.
-
- double tmp = axismin[1];
- axismin[1] = axismax[1];
- axismax[1] = tmp;
-
- // The next lines in the metadata file should be the (optional)
- // column names. Start with a default label based on the column
- // number, then replace it if we find a specific column label in the
- // file.
- dataname = str_printf("Column %d", col+1); //Note: column number starts at zero in c...
- while (1)
- {
- int c;
- if (nextline(fp, buf) == -1) break;
- if (sscanf(buf, "%d", &c) != 1) break;
- c--;
- if (nextline(fp, buf) == -1) break;
- if (c == col)
- {
- dataname = buf;
- strip_newlines(dataname);
- }
- }
- //info("dlab _%s_\n", dataname.c_str());
- fclose(fp);
-
- // Ok, now reading the .dat file should be pretty easy.
-
- clear();
- data = new double [size[0]*size[1]*size[2]];
- data_loaded = 1;
- fp = fopen(name, "r");
- if (fp == NULL) return -2;
-
- bool progress = (size[0]*size[1]*size[2]) > 100*100*100*5;
- static char msgbuf[256];
- if (progress && progress_gui)
- {
- open_progress_gui();
- msg->value("Reading file: 0%");
- }
-
- double val, last_val;
- val = last_val = 0;
- int lnum = 0; // line number
- int npoints = 0;
- bool incomplete = false;
-
- int i,j,k;
- int i0, j0, k0;
-
- // In test file from Vincent, the meta.txt code is getting the wrong order?
- // for (k=0; k<size[2]; k++)
- // {
- // for (j=0; j<size[1]; j++)
- // {
- // for (i=0; i<size[0]; i++)
- // {
- for (i=0; i<size[0]; i++)
- {
- for (j=size[1]-1; j>=0; j--) // flip y data around in matrix...
- {
- for (k=0; k<size[2]; k++)
- {
- if (incomplete) // fill matrix
- getData(i,j,k) = last_val;
- else // otherwise try to get new data
- {
- val = nextreading(fp, col, lnum);
- if (isnan(val)) // failed to read a point
- {
- if (npoints == 0)
- {
- info("could not read any points\nassuming empty file, filling with zeros\n");
- last_val = 0;
- getData(i,j,k) = last_val;
- incomplete = true;
- }
- else
- {
- info("Failed to find point number %d from line number %d, i,j,k = %d %d %d.\n"
- "Assuming incomplete file\n"
- "filling matrix with last reading %e\n", npoints, lnum, i, j, k, last_val);
- incomplete = true;
- getData(i,j,k) = last_val;
- }
- }
- else // add the new data to the matrix
- {
- getData(i,j,k) = val;
- last_val = val;
- npoints++;
- }
- }
- }
- if (!incomplete && npoints % 1000 == 0) // update progress gui
- {
- if (progress_gui)
- Fl::check();
- if (progress)
- {
- snprintf(msgbuf,sizeof(msgbuf), "Reading File: %.0f%%", 1.0*k/(size[2]-1)*100.0);
- if (progress_gui)
- msg->value(msgbuf);
- else
- info("%s\r", msgbuf);
- }
- }
- }
- }
- fclose(fp);
- return 0;
-}
+++ /dev/null
-#ifndef ImageData_H
-#define ImageData_H
-
-#include <FL/Fl_Double_Window.H>
-#include <FL/Fl_Output.H>
-
-#include <string>
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <vector>
-#include <math.h>
-#include "message.h"
-
-#define QUANT_MAX 65535
-
-// Checking array limits will help debugging but will increase the
-// execution time. I have benchmarked this by calling load_file() on a
-// 1x801x601 mtx (which load the YZ cut by default), and then
-// reloading the YZ cut. Without limit checking, the excution time as
-// 0.299s. With limit checking, it was 0.370s.
-
-#define CHECK_ARRAY_LIMITS 0
-
-using namespace std;
-
-typedef enum { YZ = 0, XY = 2, XZ = 1 } mtxcut_t;
-typedef enum { COLUMNS = 0, INDEX = 1} gpload_t;
-typedef enum { DROP = 'd', FILL_MEAN = 'm', FILL_ZERO = 'z', EXIT = 'x', COPY_ADJACENT = 'a'} incorrect_column_t;
-typedef enum { MATRIX = 0, GNUPLOT = 1, DELFT_LEGACY = 2, DAT_META = 3} datfile_t;
-typedef enum { PGM = 0, MTX = 1, DAT = 2} fallbackfile_t;
-
-class MTX_Data
-{
-
-public:
-
- string filename;
- double *data;
- string axisname[3];
- string dataname;
- int size[3];
- double axismin[3]; // the ranges for the x, y, and z axes
- double axismax[3]; // the ranges for the x, y, and z axes
- bool data_loaded;
- bool data3d;
- bool parse_txt;
- bool delft_raw_units;
- bool progress_gui;
- bool delft_settings;
-
- string settings;
-
- MTX_Data();
- ~MTX_Data();
-
- int load_file(const char *name);
- int load_gp_index(const char *name, int col);
- int load_gp_cols(const char *name);
- int load_dat_meta(const char *name, int col);
- void parse_delft_txt(const char *name, bool columns);
- void parse_comments(char *comments, const char *ident, int *dac, int *size, char *name, double *range);
- void parse_var2_comments(char *comments, const char *ident, int *dac, char *name, double *range);
- void get_settings(const char *name);
-
- inline double get_coordinate(int axis, int i)
- {
- axis = axis%3;
- if (size[axis] == 1)
- return (axismin[axis]+axismax[axis])/2.0;
- else
- return axismin[axis] + 1.0*i*(axismax[axis]-axismin[axis])/(size[axis]-1);
- //return axismin[axis] + 1.0*i*(axismax[axis]-axismin[axis])/(size[axis]); // why not minus one?
- };
-
- inline double &getData(int i, int j, int k)
- {
-#if CHECK_ARRAY_LIMITS
- if (!data_loaded)
- { fprintf(stderr, "MTX data not yet loaded!\n"); exit(-1);}
- if (i>=size[0] || i < 0)
- { fprintf(stderr, "attempt to access i = %d, size[0] = %d\n", i, size[0]); exit(-1);}
- if (j>=size[1] || j < 0)
- { fprintf(stderr, "attempt to access j = %d, size[1] = %d\n", j, size[1]); exit(-1);}
- if (k>=size[2] || k < 0)
- { fprintf(stderr, "attempt to access k = %d, size[2] = %d\n", k, size[2]); exit(-1);}
-#endif
- return data[k*size[1]*size[0] + j*size[0] + i];
- };
- void clear() { if (data_loaded) delete [] data; data_loaded = 0;};
-
- void open_progress_gui();
- void close_progress_gui();
-
- Fl_Double_Window *win;
- Fl_Output *msg;
-
-private:
-};
-
-class ImageData
-{
-
-public:
-
- double *orig_data;
- double *raw_data;
- int *quant_data;
- int width, height;
- bool *threshold_reject;
-
- MTX_Data mtx;
-
- // Keep track of which mtx index and gp column are loaded
- mtxcut_t mtx_cut_type;
- int mtx_index;
- bool do_mtx_cut_title;
- gpload_t gpload_type;
- int gp_column;
-
- bool auto_quant;
- double auto_quant_percent;
-
- bool data_loaded;
- bool data3d;
-
- datfile_t datfile_type;
- fallbackfile_t fallbackfile_type;
-
-
- double rawmin, rawmax; // the actual min and max of the raw dataset
- double qmin, qmax; // the raw values corresponding to 0 and QUANT_MAX
- double xmin, xmax; // the values of i=0 and i=width-1
- double ymin, ymax; // the values of j=0 and j=height-1
-
- string xname;
- string yname;
- string zname;
-
- // We need to keep track of the orignal stuff for the reset() function
- int orig_width, orig_height;
- double orig_xmin;
- double orig_xmax;
- double orig_ymin;
- double orig_ymax;
- string orig_xname;
- string orig_yname;
-
- // Action on incorrect number of columns when reading DAT files
- incorrect_column_t incorrect_column;
-
- // Constructor will not do much by default
- ImageData();
- ~ImageData();
-
- // Functions for loading new data
-
- // Copy data from an existing fp matrix
- void load_raw(double *data,
- int w, int h,
- double x1=NAN, double x2=NAN,
- double y1=NAN, double y2=NAN);
-
- // Copy data from an existing int matrix
- void load_int(int *data,
- int w, int h,
- double x1=NAN, double x2=NAN,
- double y1=NAN, double y2=NAN,
- double z1=NAN, double z2=NAN);
- // Reset the data back to the original (for reprocesing data without
- // reloading from file)
- void reset();
-
- // Memory allocation
- void clear();
- // reallocated space for arrays according to current width and height
- // this is used when we load new data (will clear all arrays)
- void reallocate();
-
- // So far, we've tried to keep memory allocation to a minimum. This
- // has worked so far because all of the image processing stuff that
- // changes the size of the datasets _shrink_ the dataset. However,
- // with the introduction of the interpolate function, we'll also
- // need to make the storage arrays (like quant_data,
- // threshold_reject) bigger. This is what this function does (note
- // that it will never reallocate them smaller since we need to be
- // able to restore the original data). We will leave the work of
- // allocating raw_data to the image processing function.
- void resize_tmp_arrays(int new_width, int new_height);
-
-
- // Many different functions will support threasholding Using this
- // function, and the threshold_reject array, we will unify all of
- // these to keep them consistent. It will also simplify the other
- // code.
-
- // Type: 0 = whole image, 1 = line, 2 = column, 3 = data value
- void calculate_thresholds(int type, double low, double high,
- double bottom_limit=-INFINITY, double top_limit=INFINITY);
-
- // Generic Load from file (determine filetype from extension)
- // Programs using the this class can either use this function
- // directly, but can also use the helper function directly
- //
- // All load functions will return -1 if the file was not succesfully
- // loaded.
- int load_file(const char *name);
-
- // Helpers to load data from specific files
- int load_STM(const char *name);
- int load_PGM(const char *name);
- int load_DAT(const char *name);
- int load_XL30S_TIF(const char *name); // hacked to read TIF files from XL30S
- int load_Delft(const char *name);
- // For the following functions, user should set the desired
- // mtx_cut_type, mtx_index, gpload_type and gp_column. If they
- // change during load (for example if they are out of range), then
- // the variables in the class will store the correct value.
- // Alternatively, you can use the inline functions below
- int load_MTX(const char *name);
- int load_GP(const char *name);
- // A new function that loads data from a "columns" formatted data
- // file with the help of a new metadata file. The metadata file will
- // be called "file.meta.txt". It will use gp_column number to pick
- // the column. It will load 3D data into an MTX.
- int load_DAT_meta(const char *name);
- void load_mtx_cut();
- void saveMTX(const char *name); // Write the current image data to an MTX file
-
- // Some handy functions:
-
- inline int limit(int A) { if (A<0) return 0; else if (A>QUANT_MAX) return QUANT_MAX; else return A; };
-
- inline int raw_to_quant(double raw) {return limit((int)round(1.0*(raw-qmin)*QUANT_MAX/(qmax-qmin)));}
- inline double quant_to_raw(double quant) {return qmin + 1.0*quant*(qmax-qmin)/QUANT_MAX;};
-
- // Given a pixel coordinate x, return the united coordinate.
- inline double getX(double i) {return xmin + ((width==1) ? 0 : 1.0*i*(xmax-xmin)/(width-1));};
- inline double getY(double j) {return ymin + ((height==1) ? 0 : 1.0*(height-1-j)*(ymax-ymin)/(height-1));}; // ymax is flipped
-
- // Given a united coordinate x, return the un-united.
- inline double getX_inv(double x, double zoom=1.0) { return (width==1) ? 0 : (zoom*(x-xmin)/(xmax-xmin)*(width-1)); }
- inline double getY_inv(double y, double zoom=1.0) { return (height==1) ? 0 : zoom*(height-1-(y-ymin)/(ymax-ymin)*(height-1)); }
- inline double getX_inv(double x, int zoom) { return (width==1) ? 0 : ((zoom > 0 ? zoom : -1.0/zoom)*(x-xmin)/(xmax-xmin)*(width-1)); }
- inline double getY_inv(double y, int zoom) { return (height==1) ? 0 : (zoom > 0 ? zoom : -1.0/zoom)*(height-1-(y-ymin)/(ymax-ymin)*(height-1)); }
-
- // This will rescale the floating point making the old qmin and qmax
- // into the new qmin and qmax. This is the equivalent of changing
- // the zunit settings in the old setup.
-
- void rescale_data(double new_qmin, double new_qmax);
-
- // More convenient functions
-
- inline void load_mtx_cut(int index)
- {mtx_index = index; load_mtx_cut();};
- inline void load_mtx_cut(int index, mtxcut_t type)
- {mtx_index = index; mtx_cut_type = type; load_mtx_cut();};
-
- inline void load_GP_cols(const char *name)
- {gpload_type = COLUMNS; load_GP(name);}
- inline void load_GP_index(const char *name, int colnum)
- {gpload_type = INDEX; gp_column = colnum; load_GP(name);}
-
-
- // Copy original data back into raw data matrix (saves reloading from file)
- inline void reload_orig() { memcpy(raw_data, orig_data, width*height*sizeof(double)); }
-
- // Quantizing the data
- void quantize();
-
- // Image Processing Operations on data:
-
- // Even simpler (inline) functions
-
- inline void scale_axes(double xscale, double yscale)
- {
- //info("scale %e %e %e %e %e %e\n", xmin, xmax, ymin, ymax, xscale, yscale);
- xmin *= xscale;
- xmax *= xscale;
- ymin *= yscale;
- ymax *= yscale;
- //info("scale %e %e %e %e\n", xmin, xmax, ymin, ymax);
- }
-
- inline void offset_axes(double xoff, double yoff)
- {
- info("off %e %e %e %e %e %e\n", xmin, xmax, ymin, ymax, xoff, yoff);
- xmin += xoff;
- xmax += xoff;
- ymin += yoff;
- ymax += yoff;
- info("off %e %e %e %e\n", xmin, xmax, ymin, ymax);
- }
-
- // Very simple functions (one liners)
-
- void log10(bool do_offset, double new_offset);// data[i] = log10(data[i]) for all i
- void magnitude();// data[i] = abs(data[i]) for all i, !using z unit!
- void neg();// data[i] = -(data[i]) for all i, !using z unit!
- void offset(double offset, bool do_auto);// add an offset
- void scale(double factor); // scale the data
- void gamma(double gamma, double epsilon); // gamma scaling operation on 16 bit data
-
- // More complicated functions that preserve the images size
-
- void lbl(double bp=0.0, double tp=0.0, bool whole_image_threashold=false, bool percentiles=true,
- double bottom_limit = -INFINITY, double top_limit = INFINITY); // subtract line average from each line
- void cbc(double bp=0.0, double tp=0.0, bool whole_image_threashold=false, bool percentiles=true,
- double bottom_limit = -INFINITY, double top_limit = INFINITY); // subtract column average from each column
- void sub_linecut(bool horizontal, int pos); // Subtract a specific line form each line.
- void outlier_line(bool horizontal, int pos); // Remove an outlier line
- void norm_lbl(); // Normalize each line individually.
- void norm_cbc(); // Normalize each line individually.
- void fitplane(double bp=0, double tp=0, bool percentiles=true); // subtract a plane
- void plane(double b, double a); // subtract a plane
- void xflip();
- void yflip();
- void rotate_cw();
- void rotate_ccw();
- void grad_mag(double bias); // Replace each pixel with the magnitude of the gradient. 0<bias<1 biases one derv. as more important than the other.
- void dderv(double theta); // Derivative along axis theta *degrees* off the x-axis.
- void shift_data(int after_row, int offset); //designed for gate shifts
-
- // look for "switches": Run across each row of the data: if the data
- // changes by more than "threshold" in one pixel, then we consider
- // this a switch. We the calculate an average over "avgwin" pixels
- // before the switch, we add the difference to a running offset
- // value that we add to all subsequent datapoints in the row.
- void switch_finder(double threshold, int avgwin, bool vert);
-
-
- typedef enum { LOWPASS_GAUSS = 0, LOWPASS_LORENTZ = 1, LOWPASS_EXP = 2 , LOWPASS_THERMAL} lowpass_kernel_t; void make_lowpass_kernel(double *data, double sigma, int size, lowpass_kernel_t type=LOWPASS_GAUSS);
- void lowpass(double xsize, double ysize, lowpass_kernel_t type, double mult=7.0); // width is width of mask to use measured in units of xsize, ysize. FWHM is 2.35, so around 6 works well.
- void highpass(double xsize, double ysize, double passthrough=0.0,lowpass_kernel_t type=LOWPASS_GAUSS, double mult=7.0); // mult is width of mask to use measured in units of xsize, ysize
- void notch(double xlow, double xhigh, double ylow, double yhigh, double width=7.0); // width is width of mask to use measured in units of xsize, ysize
- void equalize(); // Perform histogramic equalization
-
- void despeckle(bool despeckle_x, bool despeckle_y);
-
- void crop(int left, int right, int lower, int upper);
-
- // Functions that change the image size. These are going to be tricky
- // to deal with, especially since we also want to keep the original
- // data around!
-
- // These functions will not shrink the size of the allocated data
- // storage matrices as we want to be able to use reset() to reload
- // the original data using memcpy. They may change the values of
- // width and height, so that raw(i,j) retrieves the correct values
-
- void pixel_average(int nx, int ny); // average adjacent pixels to downsample data
- void xderv(); // take a horizontal derivative
- void yderv(); // take a vertical derivative
- void ederv(double pscale, double nscale); // take a vertical derivative, with sign flipped at y=0
- void even_odd(bool even, bool fwd_rev); // extract either even or odd rows
- void remove_lines(int start, int nlines); // remove lines, vertically shifting the data and adjusting the ymax
- void interpolate(int new_width, int new_height, int type=0); // regrid the data, using bilinear interpolation (maybe bicubic in the future)
- inline void scale_image(double xs, double ys) // an obvious next step...
- { interpolate(width*xs, height*ys); };
-
- void hist2d(double dmin, double dmax, int num_bins); //Transform the y-axis data in to a 2D histogram of datavalues
-
- // Functions for accessing the data with an (i,j) syntax (like
- // Oliver's pixel() function in Image2D) (what does the second one
- // with the const do?)
-
- // I've also added array bounds checking, which may slow it down (?)
- // but should help catch loads of bugs.
-
- inline double &raw(int i, int j)
- {
- #if CHECK_ARRAY_LIMITS
- if (!data_loaded)
- {fprintf(stderr, "Data not loaded!\n"); exit(-1);}
- if (i >= width || i < 0)
- {fprintf(stderr, "attempt to acces i = %d, width = %d\n", i, width); return raw_data[0];}
- if (j >= height || j < 0)
- {fprintf(stderr, "attempt to acces j = %d, height = %d\n", i, height); return raw_data[0];}
-#endif
- return raw_data[j*width+i];
- };
-
- inline const double &raw(int i, int j) const
- {
- #if CHECK_ARRAY_LIMITS
- if (!data_loaded)
- {fprintf(stderr, "Data not loaded!\n"); exit(-1);}
- if (i >= width || i < 0)
- {fprintf(stderr, "attempt to acces i = %d, width = %d\n", i, width); exit(-1);}
- if (j >= height || j < 0)
- {fprintf(stderr, "attempt to acces j = %d, height = %d\n", i, height); exit(-1);}
-#endif
- return raw_data[j*width+i];
- };
-
- inline int &quant(int i, int j)
- {
- #if CHECK_ARRAY_LIMITS
- if (!data_loaded)
- {fprintf(stderr, "Data not loaded!\n"); exit(-1);}
- if (i >= width || i < 0)
- {fprintf(stderr, "attempt to acces i = %d, width = %d\n", i, width); exit(-1);}
- if (j >= height || j < 0)
- {fprintf(stderr, "attempt to acces j = %d, height = %d\n", i, height); exit(-1);}
-#endif
- return quant_data[j*width+i];
- };
-
-
- // How cool an idea is this?
- //
- // Eventually, use bicubic interpolation for the pixels in the middle:
- //
- // http://www.paulinternet.nl/?page=bicubic
- //
- // but then bilinear interpolation for ones at the edges.
- //
- // Start by just using bilinear everywhere...the add the bicubic later. (maybe)
-
- inline double raw_interp(double x, double y)
- {
- int i = (int)floor(x);
- int j = (int)floor(y);
-
- if (i<0 || i > width-1 || j < 0 || j > height-1)
- {
- info("interp outside dataset: %e (%d) %e (%d)\n", x, width-1, y, height-1);
- return NAN;
- }
-
- double dx = x-(double)i;
- double dy = y-(double)j;
-
- // The boundary corner
- if (i == width-1 && j == height-1)
- return raw(i,j);
-
- // The right edge
- if (i == width-1)
- return raw(i,j) + (raw(i,j+1)-raw(i,j))*dy;
-
- // The bottom edge
- if (j == height-1)
- return raw(i,j) + (raw(i+1,j)-raw(i,j))*dx;
-
-
- // The rest (from wikipedia)
- return
- ((raw(i,j)) + //b1
- (raw(i+1,j)-raw(i,j))*dx + // b2*x
- (raw(i,j+1)-raw(i,j))*dy + // b3*y
- (raw(i,j)-raw(i+1,j)-raw(i,j+1)+raw(i+1,j+1))*dx*dy); // b4*x*y
- };
-
-private:
-
- // Some internal functions
- int parse_pgm_comments(const char *ident, const char *fmt, void *val, char *p, const char *filename);
-
- inline int check_loaded() {
- if (data_loaded == 0)
- {
- fprintf(stderr, "data accessed before loading! exiting...\n");
- exit(-1);
- }
- }
-
- void find_raw_limits(); // find the min/max of the raw data: we
-
- void find_threasholds(vector <double> data,
- double bottom_percent, double top_percent,
- double &low, double &high);
- void find_image_threasholds(double bottom_percent, double top_percent,
- double &low, double &high);
- void store_orig();
-};
-
-
-#endif
+++ /dev/null
-#include <sys/types.h>
-#include "ImagePrinter.H"
-#include "ImageWindow.H"
-#include "ImageWindow_LineDraw.H"
-#include "message.h"
-#include "throttle.H"
-#include <algorithm>
-#include <sys/time.h>
-#include "eng.h"
-#include <limits.h>
-#include <libgen.h>
-
-// Violating all rules of abstraction, but I can't figure our any other way to get access to argv[0]
-#include "spyview.H"
-
-static bool Clip(double &x1,double &y1,double &x2,double &y2, double wx1, double wy1, double wx2, double wy2);
-static void setColor(FILE *out, Fl_Color_Chooser *c);
-
-#ifndef WIN32
-#include <sys/wait.h>
-using namespace boost;
-using namespace serialization;
-using namespace std;
-#endif
-
-static const double INCH=72.0; // Inch in points.
-using namespace std;
-std::string Image_Printer::settingsDir;
-
-// Implementation of cohen-sutherland algorithm.
-static const int NONE=0;
-static const int LEFT=1;
-static const int RIGHT=2;
-static const int TOP=4;
-static const int BOTTOM=8;
-
-int wx1,wy1,wx2,wy2;
-
-Image_Printer::Image_Printer(ImageWindow *p_iw, Image_Printer_Control *p_ipc)
-{
- iw = p_iw;
- ipc = p_ipc;
- ipc->ip = this;
- ipc->face->value("Palatino");
- ipc->fontsize->value("24");
- width=7;
- ipc->height->value("7.0");
- xoff=1;
- yoff=1;
- boxwidth=4;
- tickwidth=4;
- ticklength=.25;
- zero=1e-15;
- xspacing=0;
- yspacing=0;
- ipc->xscale->value("1.0");
- ipc->yscale->value("1.0");
- ipc->zscale->value("1.0");
-
- ipc->xticfmt->value("%.2g");
- ipc->yticfmt->value("%.2g");
- ipc->cticfmt->value("%.2g");
- page_width = 11;
- page_height = 8.5;
- ipc->landscape->value(1);
- ipc->colorbar->value(0);
- loadPrintSettings(""); // Load the default settings...
- previewFileName = tmpnam(NULL);
- previewProc = -1;
-
- // Some default settings for the preview & formats, in case the
- // settings file is not found
- ipc->png_dpi->value("300");
-#ifdef WIN32
- ipc->gs_cmd->value("\"c:/Program Files/gs/gs8.64/gswin32c.exe\"");
- ipc->preview_cmd->value("\"c:/Programs Files/Ghostgum/gsview/gsview32.exe\"");
-#else
- ipc->gs_cmd->value("gs");
- ipc->preview_cmd->value("gv --watch");
-#endif
- loadPreviewSettings();
-}
-
-Image_Printer::~Image_Printer()
-{
- info("Cleaning up\n");
-
-#ifndef WIN32
- if(previewProc != -1) // We're about to unlink the preview ps file. Better kill gs first.
- kill(previewProc,SIGTERM);
-#endif
-
- unlink(previewFileName.c_str());
-}
-
-void Image_Printer::do_extra_conversions(string basename)
-{
- string command = "";
- if (ipc->extra_pdf->value())
- {
- command = "";
- command = ipc->gs_cmd->value();
- if (ipc->cmyk->value())
- command += " -dProcessColorModel=/DeviceCMYK ";
- if (ipc->paper_letter->value())
- command += " -sPAPERSIZE=letter ";
- else if (ipc->paper_a4->value())
- command += " -sPAPERSIZE=a4 ";
- command += " -q -sDEVICE=pdfwrite -dBATCH -dNOPAUSE -dEPSCrop ";
- command += " -dAutoFilterColorImages=false -dAutoFilterGrayImages=false ";
- command += " -dColorImageFilter=/FlateEncode -dGrayImageFilter=/FlateEncode ";
- command += " -sOutputFile=\"" + basename + ".pdf\" \"";
- command += basename + ".ps\"";
- info("pdf command:\n%s\n",command.c_str());
- // Don't you just love win32? This is pretty obvious, right?
- // http://jason.diamond.name/weblog/2005/04/14/dont-quote-me-on-this
-#ifdef WIN32
- system(("\""+command+"\"").c_str());
-#else
- system(command.c_str());
-#endif
- }
- if (ipc->extra_png->value())
- {
- command = "";
- command = ipc->gs_cmd->value();
- if (ipc->paper_letter->value())
- command += " -sPAPERSIZE=letter ";
- else if (ipc->paper_a4->value())
- command += " -sPAPERSIZE=a4 ";
- command += " -q -sDEVICE=pngalpha -dBATCH -dNOPAUSE -dEPSCrop ";
- command += " -r";
- command += ipc->png_dpi->value();
- command += " -sOutputFile=\"" + basename + ".png\" \"";
- command += basename + ".ps\"";
- info("png command:\n%s\n",command.c_str());
-#ifdef WIN32
- system(("\""+command+"\"").c_str());
-#else
- system(command.c_str());
-#endif
- }
- if(ipc->extra_svs->value())
- {
- savesettings(basename + ".svs");
- }
-
- if(ipc->extra_set->value())
- {
- savePrintSettings(basename + ".set");
- }
- info("done\n");
-}
-
-void Image_Printer::startPreview()
-{
-#ifndef WIN32
- if(previewProc != -1)
- kill(previewProc,SIGTERM);
-#endif
- updatePreview(true);
-#ifndef WIN32
- previewProc = fork();
-#endif
- if(previewProc == 0) // We're the baby
- execlp("gv","gv",previewFileName.c_str(),"--watch", NULL);
-}
-
-void Image_Printer::updatePreview(bool first)
-{
- static Throttle<Image_Printer> throttle(this,&Image_Printer::updatePreview, 1.0);
- if(!throttle.throttle())
- return;
- //reset_time();
- //validatePreviewCmd();
- if (previewFileName.size() == 0) return;
- if(!first)
- {
- if(previewProc == -1)
- return;
- // If the viewer has quit, exit.
- int stat;
- int ret = 0;
-#ifndef WIN32
- ret = waitpid(previewProc,&stat,WNOHANG);
-#endif
- if(ret != 0)
- {
- warn("PS viewer has quit...\n");
- previewProc = -1;
- unlink(previewFileName.c_str());
- return;
- }
- }
- char *n = tmpnam(NULL);
-
- FILE *out = fopen(n,"w");
- print(out,true);
- fclose(out);
-
- // printf("Took %g seconds to generate preview\n",current_time());
- // No need to unlink the old file; rename is guaranteed to do that atomically.
- // if (unlink(previewFileName.c_str()) != 0)
- // info("error deleteing file \"%s\": %s\n", previewFileName.c_str(), strerror(errno));
- if (rename(n,previewFileName.c_str()) != 0)
- info("error renaming file \"%s\" to \"%s\": %s\n", n, previewFileName.c_str(), strerror(errno));
-#ifndef WIN32
- if(!first)
- kill(previewProc,SIGHUP);
-#endif
-}
-
-double Image_Printer::autospace(double min, double max)
-{
- double range = fabs(min-max);
- if(range*range == 0)
- {
- return 1;
- }
-
- double digitsRange = floor(log10(range));
- double rangeMult = (double)pow(10.0,digitsRange);
-
- double collapsedRange = range/rangeMult;
- if(collapsedRange < 2.5)
- return .25 * rangeMult;
- else if(collapsedRange < 5)
- return .5 * rangeMult;
- else if(collapsedRange <= 10)
- return 1.0 * rangeMult;
- warn("Tick Pick Problem... min %e max %e\n", min, max);
- return 1.0 * rangeMult;
-}
-
-void Image_Printer::pixelToDevice(double &x, double &y)
-{
- double xscale = atof(ipc->xscale->value());
- double yscale = atof(ipc->yscale->value());
-
- y = iw->id.getY(y)*yscale; // Why the hell is this right?
- // Why does spyview have so many coordinate systems, some of which have 0,0 as top-left, some as bottom-left?
- x = iw->id.getX(x)*xscale;
- unitToDevice(x,y);
-}
-void Image_Printer::unitToDevice(double &x, double &y)
-{
- double height = atof((ipc->height->value()));
- double xscale = atof(ipc->xscale->value());
- double yscale = atof(ipc->yscale->value());
- double xmin = iw->id.getX(img_x1)*xscale;
- double xmax = iw->id.getX(img_x2)*xscale;
- double ymin = iw->id.getY(img_y1)*yscale;
- double ymax = iw->id.getY(img_y2)*yscale;
-
- double xrange, xoffset, yrange, yoffset;
- if (ipc->precise_ticks->value())
- {
- xrange=width*(img_xsize-1)/(img_xsize); // xmin is actually 1/2 pixel from the left edge, xmax is 1/2 pixel from the right.
- xoffset = width*(0.5/(img_xsize));
- yrange = height*(img_ysize-1)/(img_ysize);
- yoffset = height*(0.5/(img_ysize));
- }
- else
- {
- yrange = height;
- yoffset = 0;
- xrange=width;
- xoffset=0;
- }
- y = yoff + yrange*(y-ymax)/(ymin-ymax) + yoffset;
- x = xoff + xrange*(x-xmin)/(xmax-xmin) + xoffset;
-}
-// void Image_Printer::validatePreviewCmd()
-// {
-// if(strstr(ipc->preview_cmd->value(),".ps"))
-// {
-// warn("Overriding apparently inappropriate preview command \"%s\" with default of \"%s\"\n",
-// ipc->preview_cmd->value(),defaultPreviewCmd);
-// ipc->preview_cmd->value(defaultPreviewCmd);
-// }
-// }
-
-void Image_Printer::box(FILE *out, double x, double y, double w, double h)
-{
- fprintf(out," %g inch %g inch moveto\n",x,y);
- fprintf(out," %g inch 0 rlineto\n",w);
- fprintf(out," 0 %g inch rlineto\n",h);
- fprintf(out," %g inch 0 rlineto closepath\n",-w);
-}
-void Image_Printer::pushClip(FILE *out, double xoff, double yoff,double width,double height)
-{
- fprintf(out," clipsave\n");
- box(out, xoff,yoff,width,height);
- fprintf(out," clip\n");
-}
-
-/* This function is getting *way* too long and messy. Something needs to be done.. */
-void Image_Printer::print(FILE *out_p, bool preview_p)
-{
- preview = preview_p;
- out = out_p;
-
- // initialize some variables
- computePlotRange();
- max_ytic_width = 0; // for choosing the offset of the y axix label
- max_ctic_width = 0; // for choosing the offset of the colorbar axix label
- height = atof((ipc->height->value()));
- fontsize = atof(ipc->fontsize->value());
- xscale = atof(ipc->xscale->value());
- yscale = atof(ipc->yscale->value());
- zscale = atof(ipc->zscale->value());
-
- write_header();
-
- if (ipc->landscape->value() && !ipc->paper_eps->value())
- fprintf(out, "%d 0 translate 90 rotate\n", bb_ur_x );
-
- if(ipc->watermark->value())
- write_watermark();
-
- draw_image();
- draw_lines();
-
- if (ipc->colorbar->value())
- draw_colorbar();
-
- draw_axis_tics();
-
- // Draw the bounding box
- if(boxwidth > 0)
- {
- fprintf(out,"%% Draw our box around the plot\n");
- setColor(out,ipc->border_color);
- fprintf(out," %g setlinewidth newpath\n",boxwidth);
- box(out,xoff,yoff,width,height);
- fprintf(out," stroke\n");
- }
- else
- fprintf(out,"%% User requested no box\n");
-
- draw_axis_labels();
-
- // By defering the bounding box, we now have access to max_ytic_width and max_ctic_width
- if (ipc->paper_eps->value())
- {
- int label_x = static_cast<int>(- (max_ytic_width+2.5)*fontsize/2.0);
- int label_c = static_cast<int>((max_ctic_width+2.5)*fontsize/2.0);
- // Tricky part: estimate a nice bounding box for an EPS file
- bb_ll_x = (int) (xoff*INCH - (ipc->yaxis_label->value() ? 1 : -1) * fontsize + label_x);
- // the y axis tickmark labels are much wider than the x axis are tall
- bb_ll_y = (int) (yoff*INCH - (ipc->xaxis_label->value() ? 3 : 2) * fontsize);
- if(ipc->colorbar->value())
- bb_ur_x = (int) ((cbar_xoff+cbar_width)*INCH + label_c + (ipc->caxis_label->value() ? fontsize : 0));
- else
- bb_ur_x = (int) ((xoff+width)*INCH + fontsize);
- bb_ur_y = (int) ((yoff+height)*INCH + (ipc->do_title->value() ? 2 : 1) * fontsize);
- }
-
- if (ipc->dir_stamp->value())
- add_dirstamp();
-
- if (preview || !ipc->paper_eps->value()) // If we're using eps, spec says no showpage (adobe maybe disagrees)
- fprintf(out,"showpage\n");
- fprintf(out,"grestore\n");
- fprintf(out,"%%%%Trailer\n");
- fprintf(out, "%%%%Actual BoundingBox was: %d %d %d %d\n", bb_ll_x, bb_ll_y, bb_ur_x, bb_ur_y);
- fprintf(out,"%%%%EOF\n");
-
- info("Label width actual values:\n");
- info("ytic %d ctic %d\n", max_ytic_width, max_ctic_width);
- info("%%%%BoundingBox: %d %d %d %d\n", bb_ll_x, bb_ll_y, bb_ur_x, bb_ur_y);
-}
-
-void Image_Printer::updatePlotRange(Image_Printer_Control *ipc)
-{
- computePlotRange();
- double xscale = atof(ipc->xscale->value());
- double yscale = atof(ipc->yscale->value());
-
- char buf[1024];
- double minx, miny, maxx, maxy;
- //int img_x1, img_y1, img_x2, img_y2; // overriding class variables!!!?
- switch(ipc->plotRange->value())
- {
- case PLOT_ZOOM:
- iw->zoom_window->getSourceArea(img_x1, img_y1, img_x2, img_y2);
- //falling case!
- case PLOT_MANUAL:
- minx = iw->xunit(img_x1);
- maxx = iw->xunit(img_x2);
- miny = iw->yunit(img_y1-1); //strange: why did i need to -1?
- maxy = iw->yunit(img_y2-1);
- break;
- case PLOT_ALL:
- default:
- minx = iw->xunit(0);
- maxx = iw->xunit(iw->w-1);
- miny = iw->yunit(0);
- maxy = iw->yunit(iw->h-1);
- break;
- }
- minx *= xscale;
- miny *= yscale;
- maxx *= xscale;
- maxy *= yscale;
- snprintf(buf,sizeof(buf),"%g,%g",minx,maxx);
- ipc->xrange->value(buf);
- snprintf(buf,sizeof(buf),"%g,%g",maxy,miny);
- ipc->yrange->value(buf);
-}
-
-void Image_Printer::computePlotRange()
-{
- double xscale = atof(ipc->xscale->value());
- double yscale = atof(ipc->yscale->value());
-
- switch(ipc->plotRange->value())
- {
- case PLOT_ALL:
- default:
- img_x1 = 0;
- img_y1 = 0;
- img_x2 = iw->w-1;
- img_y2 = iw->h-1;
- break;
- case PLOT_ZOOM:
- if(iw->zoom_window)
- iw->zoom_window->getSourceArea(img_x1, img_y1, img_x2, img_y2);
- else
- {
- ipc->plotRange->value(PLOT_ALL);
- computePlotRange();
- return;
- }
- break;
- case PLOT_MANUAL:
- {
- double xmin,xmax,ymin,ymax;
- if(sscanf(ipc->xrange->value(),"%lg,%lg",&xmin,&xmax) == 2)
- {
- img_x1 = round(iw->id.getX_inv(xmin / xscale));
- img_x2 = round(iw->id.getX_inv(xmax / xscale));
- if(img_x1 > img_x2)
- swap(img_x1,img_x2);
- }
- else
- {
- warn("Warning: X Range \"%s\" isn't of the form 1.0,2.0\n",ipc->xrange->value());
- img_x1 = 0;
- img_x2 = iw->w-1;
- }
- if(sscanf(ipc->yrange->value(),"%lg,%lg",&ymax,&ymin) == 2)
- {
- img_y1 = round(iw->id.getY_inv(ymin / yscale));
- img_y2 = round(iw->id.getY_inv(ymax / yscale));
- if(img_y1 > img_y2)
- swap(img_y1,img_y2);
- }
- else
- {
- warn("Warning: Y Range \"%s\" isn't of the form 1.0,2.0\n",ipc->yrange->value());
- img_y1 = 0;
- img_y2 = iw->h-1;
- }
- }
- }
- img_xsize = abs(img_x2-img_x1+1);
- img_ysize = abs(img_y2-img_y1+1);
-}
-
-void Image_Printer::updateSettings(Image_Printer_Control *ipc)
-{
- char buf[64];
-
- snprintf(buf,sizeof(buf),"%g",width);
- ipc->width->value(buf);
- snprintf(buf,sizeof(buf),"%g",xoff);
- ipc->xoff->value(buf);
- snprintf(buf,sizeof(buf),"%g",yoff);
- ipc->yoff->value(buf);
-
- snprintf(buf,sizeof(buf),"%g",ticklength);
- ipc->ticklength->value(buf);
- snprintf(buf,sizeof(buf),"%g",xspacing);
- ipc->xspacing->value(buf);
- snprintf(buf,sizeof(buf),"%g",yspacing);
- ipc->yspacing->value(buf);
-
- snprintf(buf,sizeof(buf),"%g",boxwidth);
- ipc->boxwidth->value(buf);
- snprintf(buf,sizeof(buf),"%g",tickwidth);
- ipc->tickwidth->value(buf);
- updatePlotRange(ipc);
- update_page_size();
-}
-
-void Image_Printer::fetchSettings(Image_Printer_Control *ipc)
-{
- width=atof(ipc->width->value());
- xoff=atof(ipc->xoff->value());
- yoff=atof(ipc->yoff->value());
-
- ticklength=atof(ipc->ticklength->value());
- xspacing=atof(ipc->xspacing->value());
- yspacing=atof(ipc->yspacing->value());
-
- boxwidth=atof(ipc->boxwidth->value());
- tickwidth=atof(ipc->tickwidth->value());
-
- updatePreview();
-}
-
-void Image_Printer::update_page_size(int type)
-{
- // This is a pain in the ass because in FLTK, the status of the
- // other radio buttons is not updated until after the callback is
- // executed: during the callback, two radio buttons could both be
- // "1" at the same time...
-
- if (type == -1 && ipc->paper_letter->value())
- type = 1;
- else if (type == -1 && ipc->paper_a4->value())
- type = 2;
-
- if (type == 1)
- {
- page_width = 8.5;
- page_height = 11.0;
- }
-
- else if (type == 2)
- {
- page_width = 8.27;
- page_height = 11.69;
- }
-
- if (ipc->landscape->value())
- {
- double tmp = page_width;
- page_width = page_height;
- page_height = tmp;
- }
-}
-
-void Image_Printer::setAspectRatio(int change_axis)
-{
- double target_width, target_height;
-
- double cur_height = atof(ipc->height->value());
- double cur_width = width;
-
- // define ar as h/w, giving h = ar*w, w = h/ar
- double spyview_ar = 1.0* iw->dozoom(iw->h, iw->yzoom) / iw->dozoom(iw->w, iw->xzoom);
-
- // change axis:
- // 1 = change width, keep left edge
- // 2 = change width, center
- // 3 = change width, keep right edge
- // 4 = change height, keep top edge
- // 5 = change height, center
- // 6 = change height, keep bottom edge
-
-
- if (change_axis < 4) // change width
- {
- target_width = cur_height / spyview_ar;
- target_height = cur_height;
- if (change_axis == 2)
- xoff += (cur_width - target_width)/2;
- else if (change_axis == 3)
- xoff += (cur_width - target_width);
- }
- else
- {
- target_width = cur_width;
- target_height = cur_width * spyview_ar;
- if (change_axis == 4)
- yoff += (cur_height - target_height);
- else if (change_axis == 5)
- yoff += (cur_height - target_height)/2;
- }
-
- width = target_width;
-
- //historically, height is not a local class variable...
- char buf[1024];
- snprintf(buf,sizeof(buf),"%g",target_height);
- ipc->height->value(buf);
- updateSettings(ipc);
- //ipc->center_x->do_callback();
- //ipc->center_y->do_callback();
-}
-
-static void maybe_mkdir(const char *name)
-{
-#ifdef WIN32
- if(mkdir(name) == 0)
-#else
- if(mkdir(name,0777) == 0)
-#endif
-
- switch(errno)
- {
- case EEXIST:
- return;
- default:
- warn("Unable to create directory \"%s\": %s\n",name,strerror(errno));
- return;
- }
-}
-
-void Image_Printer::initSettingsDir()
-{
- string buf;
-#ifdef WIN32
- if(getenv("SPYVIEW_PREF_DIR") != NULL)
- buf = getenv("SPYVIEW_PREF_DIR");
- else
- buf = sharedir;
-#else
- buf = getenv("HOME");
- buf = buf + DIRECTORY_SEPARATOR + ".spyview";
-#endif
- maybe_mkdir(buf.c_str());
- buf = buf + DIRECTORY_SEPARATOR + "print_settings";
- settingsDir = buf;
- maybe_mkdir(buf.c_str());
-}
-
-void Image_Printer::savePreviewSettings()
-{
- string name;
- initSettingsDir();
- if(name.empty())
- name = settingsDir + DIRECTORY_SEPARATOR + "settings.prv";
-
- std::ofstream ofs(name.c_str());
- boost::archive::text_oarchive ar(ofs);
-
- int version;
- ar & version;
- // All this stuff is in version 1
- ar & flcast(ipc->preview_cmd);
- ar & flcast(ipc->gs_cmd);
- ar & flcast(ipc->extra_pdf);
- ar & flcast(ipc->extra_png);
- ar & flcast(ipc->png_dpi);
- ar & flcast(ipc->cmyk);
-}
-
-void Image_Printer::loadPreviewSettings()
-{
- string name;
- initSettingsDir();
- if(name.empty())
- name = settingsDir + DIRECTORY_SEPARATOR + "settings.prv";
-
- std::ifstream ifs(name.c_str());
- if (!ifs.good())
- {
- info("preview settings file _%s_ not found\n", name.c_str());
- return;
- }
- boost::archive::text_iarchive ar(ifs);
-
- int version;
- ar & version;
- ar & flcast(ipc->preview_cmd);
- ar & flcast(ipc->gs_cmd);
- ar & flcast(ipc->extra_pdf);
- ar & flcast(ipc->extra_png);
- ar & flcast(ipc->png_dpi);
- ar & flcast(ipc->cmyk);
-}
-
-
-void Image_Printer::savePrintSettings(std::string name)
-{
- fetchSettings(ipc); // Should be redundant, but paranoia is good.
- initSettingsDir();
- if(name.empty())
- {
- name = settingsDir + DIRECTORY_SEPARATOR + "default.set";
- }
-
- const char *fname = name.c_str();
- std::ofstream ofs(fname);
- try
- {
- if(!ofs.good())
- throw(1);
- }
- catch (...)
- {
- warn("Unable to create or overwrite settings file \"%s\"\n",fname);
- }
-
- try
- {
- boost::archive::text_oarchive oa(ofs);
-
- // For some reason, on WIN32 even have this code compiled into
- // the program, even if it is not executed (!?), causes a
- // crash.
-
- // Upon further inspection, this causes a crash on my machine
- // at work, but not on my machine at home. Also, curiously, on
- // my machine at work, the fltk widgets have now started to be
- // displayed at unix "dark grey" instead of the usual windows
- // "light biege". At home, where the exact same executable is
- // not crashing, the fltk widgets are beige (except for the
- // first warning dialog box!!!)
-
- oa & (*this);
- }
- catch (boost::archive::archive_exception e)
- {
- error("ImagePrinter serialization error: %s",e.what());
- }
- catch (...)
- {
- error("Unknown serialization error\n");
- }
-
-}
-
-void Image_Printer::loadPrintSettings(std::string name)
-{
- initSettingsDir();
- if(name.empty())
- {
- name = settingsDir + DIRECTORY_SEPARATOR + "default.set";
- }
-
- const char *fname = name.c_str();
- try
- {
- std::ifstream ifs(fname);
- if(!ifs.good())
- throw(1);
- boost::archive::text_iarchive ia(ifs);
- ia & (*this);
- updateSettings(ipc);
- }
- catch (boost::archive::archive_exception e)
- {
- error("Serialization error: %s",e.what());
- }
- catch (...)
- {
- warn("Unable to load settings file \"%s\": %s\n",fname,strerror(errno));
- }
-}
-
-
-static inline int chGetCode(double x, double y, double wx1, double wy1, double wx2, double wy2)
-{
- double eps = max(fabs(wx1-wx2),fabs(wy1-wy2))*1e-6;
- int code = NONE;
- if(x<wx1-eps)
- code |= LEFT;
- else if(x>wx2+eps)
- code |= RIGHT;
- if(y<wy1-eps)
- code |= TOP;
- else if(y>wy2+eps)
- code |= BOTTOM;
- return code;
-}
-
-static inline bool SubClip(double &x1,double &y1,double &x2,double &y2, double wx1, double wy1, double wx2, double wy2)
-{
- if(wy2 < wy1)
- swap(wy2,wy1);
- if(wx2 < wx1)
- swap(wx2,wx1);
- if(fabs(x2-x1) < fabs(y2 - y1))
- return SubClip(y1,x1,y2,x2,wy1,wx1,wy2,wx2);
- double m, tx, ty;
- int code1, code2;
- m=(y2-y1)/(float)(x2-x1);
- code1=chGetCode(x1,y1,wx1,wy1,wx2,wy2);
- code2=chGetCode(x2,y2,wx1,wy1,wx2,wy2);
- for(int i = 0; i < 20; i++)
- {
- if(code1 == NONE)
- break;
- if(code1 & LEFT)
- {
- tx=wx1-x1;
- ty=y1+(tx*m);
- x1=wx1; y1=ty;
- code1=chGetCode(x1,y1,wx1,wy1,wx2,wy2);
- }
- if(code1 & RIGHT)
- {
- tx=wx2-x1;
- ty=y1+(tx*m);
- x1=wx2; y1=ty;
- code1=chGetCode(x1,y1,wx1,wy1,wx2,wy2);
- }
- if(code1 & TOP)
- {
- ty=wy1-y1;
- tx=x1+(ty/m);
- x1=tx; y1=wy1;
- code1=chGetCode(x1,y1,wx1,wy1,wx2,wy2);
- }
- if(code1 & BOTTOM)
- {
- ty=wy2-y1;
- tx=x1+(ty/m);
- x1=tx; y1=wy2;
- code1=chGetCode(x1,y1,wx1,wy1,wx2,wy2);
- }
- if((code2 & code1) != 0)
- return false;
- }
- if(code1 != NONE)
- {
- fprintf(stderr,"Bad clip: %g,%g %g,%g [%g,%g]-[%g,%g]\n",x1,y1,x2,y2,wx1,wy1,wx2,wy2);
- return false;
- }
- return true;
-}
-
-static bool Clip(double &x1,double &y1,double &x2,double &y2, double wx1, double wy1, double wx2, double wy2)
-{
- int code1=chGetCode(x1,y1,wx1,wy1,wx2,wy2);
- int code2=chGetCode(x2,y2,wx1,wy1,wx2,wy2);
- if((code1 & code2) != 0)
- return false;
- if((code1 == 0) && (code2 == 0))
- return true;
- // printf("Clipping %g,%g - %g,%g to %g,%g - %g,%g\n",x1,y1,x2,y2,wx1,wy1,wx2,wy2);
- bool res = SubClip(x1,y1,x2,y2,wx1,wy1,wx2,wy2);
- // printf(" Clip %g,%g - %g,%g to %g,%g - %g,%g %s\n",x1,y1,x2,y2,wx1,wy1,wx2,wy2, res ? "true" : "false");
- return res && SubClip(x2,y2,x1,y1,wx1,wy1,wx2,wy2);
-
-
-}
-
-void setColor(FILE *out, Fl_Color_Chooser *c)
-{
- fprintf(out,"%g %g %g setrgbcolor %% Color: %s\n",c->r(),c->g(),c->b(),c->label());
-}
-
-void Image_Printer::write_watermark()
-{
- // The "Watermark" prints a text copy of many of the settings into a small
- // Rectangle clipped to the image area. You can use illustrator to delete
- // the image and see it if you need to duplicate an image.
- static const double ls=5.0/INCH;
- fprintf(out,"%% The following puts a watermark with some info on how the file was made below the image\n");
- setColor(out,ipc->text_color);
- pushClip(out,xoff,yoff,width,height);
- fprintf(out,"/Courier findfont 4 scalefont setfont\n");
- double y = yoff+height-ls;
- char buf[4096];
-
- snprintf(buf,sizeof(buf),"filename %s colormap %s",
- iw->filename.c_str(), iw->colormap_window->label());
- fprintf(out," newpath %g inch %g inch moveto (%s) show\n",
- xoff, y, buf);
- y -= ls;
-
- snprintf(buf,sizeof(buf),"hmin %d %e %s hmax %d %e",
- iw->hmin, iw->id.quant_to_raw(iw->hmin), iw->id.zname.c_str(),
- iw->hmax, iw->id.quant_to_raw(iw->hmax));
- fprintf(out," newpath %g inch %g inch moveto (%s) show\n",
- xoff, y, buf);
- y -= ls;
-
- snprintf(buf,sizeof(buf),"plane_a %g plane_b %g gamma %g gammacenter %g", iw->plane_a, iw->plane_b, iw->gam, iw->gcenter);
- fprintf(out," newpath %g inch %g inch moveto (%s) show\n",
- xoff, y, buf);
- y -= ls;
-
- snprintf(buf,sizeof(buf),"imop \"%s\"", iw->operations_string.c_str());
- fprintf(out," newpath %g inch %g inch moveto (%s) show\n",
- xoff, y, buf);
- y -= ls;
-
- snprintf(buf,sizeof(buf),"box_int (%d,%d)-(%d,%d)", img_x1, img_y1, img_x2, img_y2);
- fprintf(out," newpath %g inch %g inch moveto (%s) show\n",
- xoff, y, buf);
- y -= ls;
-
- snprintf(buf,sizeof(buf),"box (%g,%g)-(%g,%g)", iw->xunit(img_x1)*xscale, iw->yunit(img_y1)*yscale, iw->xunit(img_x2)*xscale, iw->yunit(img_y2)*yscale);
- fprintf(out," newpath %g inch %g inch moveto (%s) show\n",
- xoff, y, buf);
- y -= ls;
-
- snprintf(buf,sizeof(buf),"xscale %g yscale %g", xscale, yscale);
- fprintf(out," newpath %g inch %g inch moveto (%s) show\n",
- xoff, y, buf);
- y -= ls;
-
-
- fprintf(out," cliprestore\n");
-}
-
-void Image_Printer::calculateBoundingBox()
-{
- // Before, we put the bounding box at the end of the file after we
- // calculated all the label widths.
-
- // However, there is an outstanding ghostscript bug that ignores
- // (atend) bounding boxes gv and gsview both have hacked together
- // work arounds however, if we use ghostscript to convert to png or
- // pdf, the bounding box is completely ignored!
-
- // So, now, we have to hack it in here.
-
- // The y values are easy, since the height of the labels is fixed
- bb_ur_y = (int) ((yoff+height)*INCH + (ipc->do_title->value() ? 2 : 1) * fontsize);
- bb_ll_y = (int) (yoff*INCH - (ipc->xaxis_label->value() ? 3 : 2) * fontsize);
-
- // The x values are much harder, since we need to estimate the maximum width of
- // the y axis labels and the colorbar labels.
- //
- // Let's try estimating it from the min an max values of the labels
-
-// double tmp;
-// char buf[128];
-// tmp = iw->yunit((img_y2+img_y1)*0.667)*yscale; // a random uneven number?
-// max_ytic_width = snprintf(buf,sizeof(buf),ipc->yticfmt->value(),tmp);
-// info("%s\n", buf);
-
-// // Same for the colorbar
-
-// tmp = iw->getz((iw->hmin+iw->hmax)*0.667)*zscale;
-// max_ctic_width = snprintf(buf,sizeof(buf),ipc->yticfmt->value(),tmp);
-// info("%s\n", buf);
-
- // the above doesn't work so well either...
- // let's just overestimate the bounding box a bit...
- // it would be better to calculate the tics ahead of time...
-
- max_ytic_width = 10;
- max_ctic_width = 10;
-
- int label_x = static_cast<int>(- (max_ytic_width+2.5)*fontsize/2.0);
- bb_ll_x = (int) (xoff*INCH - (ipc->yaxis_label->value() ? 1 : -1) * fontsize + label_x);
-
- int label_c = static_cast<int>((max_ctic_width+2.5)*fontsize/2.0);
- cbar_width = ipc->cbar_width->value();
- cbar_xoff = xoff + width + 0.3;
-
- if(ipc->colorbar->value())
- bb_ur_x = (int) ((cbar_xoff+cbar_width)*INCH + label_c + (ipc->caxis_label->value() ? fontsize : 0));
- else
- bb_ur_x = (int) ((xoff+width)*INCH + fontsize);
-
- info("Label width estimates:\n");
- info("ytic %d ctic %d\n", max_ytic_width, max_ctic_width);
- info("%%%%BoundingBox: %d %d %d %d\n", bb_ll_x, bb_ll_y, bb_ur_x, bb_ur_y);
-
- max_ytic_width = 0;
- max_ctic_width = 0;
-}
-
-void Image_Printer::write_header()
-{
-
- // First, reset the bouding box
- bb_ll_x = bb_ll_y = 0;
-
- // Now that we to include support for printing the area selected
- // using the zoom window (or a manually set area), we will create
- // some variables here that store the area of the image
-
- if (ipc->paper_eps->value() && (!preview))
- fprintf(out,"%%!PS-Adobe-3.0 EPSF-3.0\n");
- else
- fprintf(out,"%%!PS-Adobe-3.0\n");
-
- // Add a paper description and orientation for nice cooperation with
- // gs: however, for some reason, ps2pdf seems to ignore the paper
- // settings we put in the postscript file and just uses Letter...
- if (ipc->paper_letter->value())
- {
- bb_ur_x = 612;
- bb_ur_y = 792;
- }
- else if (ipc->paper_a4->value())
- {
- bb_ur_x = 595;
- bb_ur_y = 842;
- }
-
- if (ipc->paper_eps->value())
- {
- calculateBoundingBox();
- fprintf(out, "%%%%BoundingBox: %d %d %d %d\n", bb_ll_x, bb_ll_y, bb_ur_x, bb_ur_y);
- if(preview)
- fprintf(out, "%%%%Pages: 1\n");
- else
- fprintf(out, "%%%%Pages: 0\n");
- fprintf(out,"%%%%Orientation: Portrait\n");
- }
- else
- {
- // The PNG and PDF files will be displayed with rotated pages if we do this.
- //if (ipc->landscape->value())
- //{
- // int tmp = bb_ur_x;
- // bb_ur_x = bb_ur_y;
- // bb_ur_y = tmp;
- //}
- // the above doesn't really work...
- if (ipc->paper_letter->value())
- fprintf(out, "%%%%DocumentMedia: Letter %d %d 0 () ()\n", bb_ur_x,bb_ur_y);
- else if (ipc->paper_a4->value())
- fprintf(out, "%%%%DocumentMedia: A4 %d %d 0 () ()\n",bb_ur_x,bb_ur_y);
-
- fprintf(out, "%%%%Orientation: %s\n", ipc->landscape->value() ? "Landscape" : "Portrait");
- fprintf(out, "%%%%Pages: 1\n");
- }
-
- // DSC comments that don't change with ps/eps...
- fprintf(out,"%%%%DocumentData: Clean7Bit\n");
- fprintf(out,"%%%%Creator: Spyview PS Output\n");
- fprintf(out,
- "%%%% Spyview parameters:\n"
- "%%%% colorplotmin = %e ; colorplotmax = %e\n"
- "%%%% gamma = %e\n"
- "%%%% rawdata_min = %e, rawdata_max = %e\n",
- iw->getz(iw->hmin)*zscale, iw->getz(iw->hmax)*zscale,
- iw->gam, iw->id.rawmin, iw->id.rawmax);
- fprintf(out,"%%%%EndComments\n\n");
-
-
- // Distiller magic
- fprintf(out,
- "%%%%BeginSetup\n"
- "%% The following makes distiller not jpeg compress the spyview image.\n"
- "systemdict /setdistillerparams known {\n"
- "<< /AutoFilterColorImages false /ColorImageFilter /FlateEncode >>\n"
- "setdistillerparams\n"
- "} if\n"
- "/inch {72 mul} bind def\n"
- "/rightshow %% stk: string; show a string right aligned at the current location\n"
- "{ dup stringwidth pop 0 exch sub 0 rmoveto show } def\n"
- "/centershow %% stk: string show a string centered horizontally at the current location\n"
- "{ dup stringwidth pop 0 exch sub 0.5 mul 0 rmoveto show } def\n"
- "%%%%EndSetup\n");
-
- if(ipc->paper_eps->value())
- {
- // Tricky part: estimate a nice bounding box for an EPS file; the pagesize will crop the output pdf nicely if we get it close.
- int label_c = static_cast<int>((6)*fontsize/2.0);
- if(ipc->colorbar->value())
- bb_ur_x = (int) ((cbar_xoff+cbar_width)*INCH + label_c + (ipc->caxis_label->value() ? fontsize : 0));
- else
- bb_ur_x = (int) ((xoff+width)*INCH + fontsize);
- bb_ur_y = (int) ((yoff+height)*INCH + (ipc->do_title->value() ? 2 : 1) * fontsize);
-
- // This is causing problems with ghostscript 8.54: strictly
- // speaking, EPS files should not have a page size. In newer
- // versions of ghostscript, if a page size is found, it
- // overrides the bounding box for conversion to, for example,
- // PDF and PNG files.
- //fprintf(out,"<< /PageSize [%d %d] >> setpagedevice\n",bb_ur_x,bb_ur_y);
- }
-
- if (!ipc->paper_eps->value() || preview)
- fprintf(out, "%%%%Page: 1 1\n");
- fprintf(out,"gsave\n");
-}
-
-void Image_Printer::draw_image()
-{
-
- // Draw the image
- fprintf(out,"%% Draw the image\n");
- //fprintf(out,"/imgstr %d string def\n\n", iw->w);
- fprintf(out,"/imgstr %d string def\n\n", img_xsize);
- fprintf(out,"gsave\n %g inch %g inch translate\n", xoff,yoff);
- fprintf(out," %g inch %g inch scale\n",width,height);
- //fprintf(out," %d %d %% Columns and Rows\n", iw->w, iw->h);
- fprintf(out," %d %d %% Columns and Rows\n", img_xsize, img_ysize);
- fprintf(out," 8 %% bits per color channel\n");
- //fprintf(out," [%d 0 0 %d 0 0]\n",iw->w, iw->h); // Map the unit square to our image
- fprintf(out," [%d 0 0 %d 0 0]\n",img_xsize, img_ysize); // Map the unit square to our image
- fprintf(out," { currentfile imgstr readhexstring pop } false 3 colorimage\n");
- fprintf(out," ");
-
- // number of columns before a newline in the postscript image
- static const int maxcol=72;
-
- for(int i = img_y2; i >= img_y1; i--)
- {
- int c = 0;
- for(int j = img_x1; j <= img_x2; j++)
- {
- c += 6;
- if(c > maxcol)
- {
- fprintf(out,"\n ");
- c = 6;
- }
- unsigned char r,g,b;
- if(i >= 0 && i < iw->h && j >= 0 && j < iw->w) // This is a horrible hack, but I'm too lazy to work out the right bounds.
- iw->getrgb(i,j,r,g,b);
- else
- {
- r = g = b = 255;
- }
- fprintf(out,"%02x%02x%02x",r,g,b);
-
- }
- fprintf(out,"\n ");
- }
- fprintf(out," grestore\n\n");
-}
-
-void Image_Printer::draw_lines()
-{
- // We want to draw the linecut before the bounding box and the tic
- // marks, so it comes out beneath them.
- bool clipped=false;
-
- if(ipc->plotLineCut->value() && (iw->line_cut_type != NOLINE)) // Plot the line for the linecut. We use the ticmark settings at the moment, which is stupid but easy.
- {
- pushClip(out,xoff,yoff,width,height);
- clipped=true;
- fprintf(out,"%% Plot the linecut location\n");
- setColor(out, ipc->linecut_color);
- fprintf(out," %g setlinewidth newpath\n",tickwidth);
- double x1,y1,x2,y2,t;
- switch(iw->line_cut_type)
- {
- case HORZLINE:
- x1 = xoff; x2 = xoff + width;
- y1=iw->line_cut_yp;
- pixelToDevice(t,y1);
- y2=y1;
- break;
- case VERTLINE:
- x1=iw->line_cut_xp;
- pixelToDevice(x1,t);
- x2=x1;
- y1 = yoff; y2 = yoff + height;
- break;
- case OTHERLINE:
- x1=iw->lcx1;
- x2=iw->lcx2;
- y1=iw->lcy1;
- y2=iw->lcy2;
- pixelToDevice(x1,y1);
- pixelToDevice(x2,y2);
- break;
- default:
- warn("Unknown line cut type!\n");
- exit(1);
- }
- fprintf(out," %g inch %g inch moveto\n",x1,y1);
- fprintf(out," %g inch %g inch lineto\n",x2,y2);
- fprintf(out,"stroke\n");
- }
-
- if(ipc->plotZoomBox->value() && iw->zoom_window && iw->zoom_window->visible())
- {
- int x1,y1,x2,y2;
- iw->zoom_window->getSourceArea(x1,y1,x2,y2);
- double x1d, y1d, x2d, y2d;
- x1d = x1; y1d = y1; x2d = x2; y2d = y2;
- pixelToDevice(x1d,y1d);
- pixelToDevice(x2d,y2d);
- setColor(out,ipc->zoombox_color);
- fprintf(out," %g setlinewidth newpath\n",tickwidth);
- fprintf(out," %g inch %g inch moveto\n",x1d,y1d);
- fprintf(out," %g inch %g inch lineto\n",x1d,y2d);
- fprintf(out," %g inch %g inch lineto\n",x2d,y2d);
- fprintf(out," %g inch %g inch lineto\n",x2d,y1d);
- fprintf(out," %g inch %g inch lineto\n",x1d,y1d);
- fprintf(out," stroke\n");
- }
- if (ipc->plotLines->value() && !LineDrawer->lines.empty())
- {
- if(!clipped)
- pushClip(out,xoff,yoff,width,height);
- clipped=true;
- fprintf(out,"%% Plot the lines\n");
- setColor(out,ipc->overlay_color);
- fprintf(out,"%g setlinewidth newpath\n",tickwidth);
- double lx = NAN;
- double ly = NAN;
-
- for(LineDraw::lines_t::iterator i = LineDrawer->lines.begin(); i != LineDrawer->lines.end(); i++)
- {
- double x1,y1,x2,y2;
- x1=i->x1*xscale;
- x2=i->x2*xscale;
- y1=i->y1*yscale;
- y2=i->y2*yscale;
- unitToDevice(x1,y1);
- unitToDevice(x2,y2);
- if(Clip(x1,y1,x2,y2,xoff,yoff,xoff+width,yoff+height))
- {
- if(!(isnan(x1) || isnan(y1) || isnan(x2) || isnan(y2)))
- {
- if((x1 != lx) || (y1 != ly)) // Skip unnecessary moves.
- fprintf(out," %g inch %g inch moveto\n",x1,y1);
- fprintf(out," %g inch %g inch lineto\n",x2,y2);
- }
- lx = x2;
- ly = y2;
- }
- else
- {
- lx = NAN;
- ly = NAN;
- }
- }
- fprintf(out,"stroke\n");
- }
- if(clipped)
- {
- fprintf(out," cliprestore\n");
- clipped=false;
- }
-}
-
-void Image_Printer::draw_colorbar()
-{
- int cbimgx, cbimgy;
- if (ipc->rotate_cbar->value())
- {
- cbar_height = ipc->cbar_width->value();
- cbar_width = height*ipc->cbar_height_per->value()/100.0;
- cbar_xoff = xoff + (width-cbar_width)/2;
- cbar_yoff = yoff + height+0.3;
- cbimgx = iw->colormap_length;
- cbimgy = 1;
- }
- else
- {
- cbar_width = ipc->cbar_width->value();
- cbar_height = height*ipc->cbar_height_per->value()/100.0;
- cbar_xoff = xoff + width + 0.3;
- cbar_yoff = yoff + (height - cbar_height)/2;
- cbimgx = 1;
- cbimgy = iw->colormap_length;
- }
-
-
-
- if (!ipc->linear_cmap->value())
- {
- // Draw a colorbar with a non-linear color mapping but a linear tic spacing
-
- fprintf(out,"%% Draw the colorbar\n");
- fprintf(out,"/imgstr %d string def\n\n", 1);
- fprintf(out,"gsave\n %g inch %g inch translate\n", cbar_xoff, cbar_yoff);
- fprintf(out," %g inch %g inch scale\n",cbar_width, cbar_height);
- fprintf(out," %d %d %% Columns and Rows\n", cbimgx, cbimgy);
- fprintf(out," 8 %% bits per color channel\n");
- fprintf(out," [%d 0 0 %d 0 0]\n", cbimgx, cbimgy); // Map the unit square to our image
- fprintf(out," { currentfile imgstr readhexstring pop } false 3 colorimage\n");
-
- int tmp;
- for(int i = 0; i < iw->colormap_length; i++)
- {
- unsigned char r,g,b;
- tmp = iw->gammatable[i];
- r = iw->colormap[3*tmp];
- g = iw->colormap[3*tmp+1];
- b = iw->colormap[3*tmp+2];
- fprintf(out,"%02x%02x%02x",r,g,b);
- fprintf(out,"\n ");
- }
- fprintf(out," grestore\n\n");
-
- // Draw the colorbar box
-
- if (boxwidth > 0)
- {
- fprintf(out, "%% Draw the box around the colorbar\n");
- setColor(out,ipc->border_color);
- fprintf(out," %g setlinewidth newpath\n",boxwidth);
- box(out,cbar_xoff,cbar_yoff,cbar_width,cbar_height);
- fprintf(out," stroke\n");
- }
-
- // Draw the tic marks on the colorbox
- fprintf(out,"/%s findfont %g scalefont setfont\n",ipc->face->value(),fontsize);
- fprintf(out," %g setlinewidth\n", tickwidth);
- if(ipc->cticfmt->size() != 0)
- {
- double cs;
- double cmin = iw->getz(iw->hmin)*zscale;
- double cmax = iw->getz(iw->hmax)*zscale;
- int tic_width;
-
- if(ipc->cspacing->value() != 0)
- cs = fabs(ipc->cspacing->value());
- else
- cs=autospace(cmin,cmax);
-
- if(cmin > cmax)
- cs=-cs;
-
- // Tic marks should be on integers (1.0, 1.5,... not 1.37,1.87,...) and should not be outside the frame
- double min = cs*ceil(cmin/cs);
- double tic_offset, wrange;
- if (ipc->precise_ticks->value())
- {
- wrange=cbar_height*(iw->colormap_length-1)/(iw->colormap_length); // cmin is actually 1/2 picel from the left edge, xmax is 1/2 pixel from the right.
- tic_offset = cbar_height*(0.5/(iw->colormap_length));
- }
- else
- {
- wrange=cbar_height;
- tic_offset=0;
- }
- // warn("min %g cmin %g cmax %g cs %g zero %g\n",min,cmin,cmax,cs,zero);
- for(double c = min; c*cs <= cmax*cs + zero*cs*fabs(cs); c += cs)
- {
- // warn("%g %g %g %g\n",c,c*cs,cmax*cs,zero*cs*abs(cs));
- //if(x < xmin)
- //continue;
- char buf[128];
- buf[0] = 0; // a good default
- if (ipc->cticfmt->value()[0] == 'e')
- {
- char *p = ipc->cticfmt->value()+1;
- long int dig = strtol(p, (char **)NULL, 10); // strtol returns zero if no digits are found
- if (dig == 0) dig = 2; // a reasonable default?
- strncpy(buf, eng(c, dig, 1), 128);
- }
- else if (ipc->cticfmt->value()[0] == 's')
- {
- char *p = ipc->cticfmt->value()+1;
- long int dig = strtol(p, (char **)NULL, 10); // strtol returns zero if no digits are found
- if (dig == 0) dig = 2; // a reasonable default?
- strncpy(buf, eng(c, dig, 0), 128);
- }
- else
- {
- if(fabs(c/cs) < zero)
- snprintf(buf,sizeof(buf),ipc->cticfmt->value(),0.0);
- else
- snprintf(buf,sizeof(buf),ipc->cticfmt->value(),c);
- }
- info("cvalue %e label '%s'\n", c, buf);
- tic_width = strlen(buf);
-
- if (tic_width > max_ctic_width) max_ctic_width = tic_width;
-
- double psx = cbar_xoff+cbar_width+0.25*fontsize/INCH; //
- double psy = cbar_yoff + wrange * ((c-cmin)/(cmax-cmin)) + tic_offset;
- setColor(out,ipc->text_color);
- fprintf(out," newpath %g inch %g inch moveto (%s) show\n",psx,psy-0.25*fontsize/INCH,buf);
-
- if(ipc->fancy_ticks->value())
- {
- setColor(out,ipc->large_tick_color);
- fprintf(out,"%g setlinewidth newpath\n",tickwidth*2);
- fprintf(out," newpath %g inch %g inch moveto %g inch 0 rlineto stroke\n",cbar_xoff,psy,ticklength+tickwidth/72.0);
- fprintf(out," newpath %g inch %g inch moveto %g inch 0 rlineto stroke\n",cbar_xoff+cbar_width,psy,-ticklength-tickwidth/72.0);
- setColor(out,ipc->small_tick_color);
- fprintf(out,"%g setlinewidth newpath\n",tickwidth);
- fprintf(out," newpath %g inch %g inch moveto %g inch 0 rlineto stroke\n",cbar_xoff,psy,ticklength);
- fprintf(out," newpath %g inch %g inch moveto %g inch 0 rlineto stroke\n",cbar_xoff+cbar_width,psy,-ticklength);
- }
- else
- {
- setColor(out,ipc->small_tick_color);
- fprintf(out," newpath %g inch %g inch moveto %g inch 0 rlineto stroke\n",cbar_xoff,psy,ticklength);
- fprintf(out," newpath %g inch %g inch moveto %g inch 0 rlineto stroke\n",cbar_xoff+cbar_width,psy,-ticklength);
- }
- }
- }
- }
- else // Draw a colorbar with a linear color scale but with a non-linear tic mark scale
- {
-
- // First draw the image for inside the colorbar
-
- int length = iw->colormap_length;
- int start = ipc->cmin->value()*length;
- int end = ipc->cmax->value()*length;
-
- fprintf(out,"%% Draw the colorbar\n");
- fprintf(out,"/imgstr %d string def\n\n", 1);
- fprintf(out,"gsave\n %g inch %g inch translate\n", cbar_xoff, cbar_yoff);
- fprintf(out," %g inch %g inch scale\n",cbar_width, cbar_height);
- fprintf(out," %d %d %% Columns and Rows\n", 1, end-start);
- fprintf(out," 8 %% bits per color channel\n");
- fprintf(out," [%d 0 0 %d 0 0]\n", 1, end-start); // Map the unit square to our image
- fprintf(out," { currentfile imgstr readhexstring pop } false 3 colorimage\n");
-
- for(int i = start; i < end; i++)
- {
- unsigned char r,g,b;
- r = iw->colormap[3*i];
- g = iw->colormap[3*i+1];
- b = iw->colormap[3*i+2];
- fprintf(out,"%02x%02x%02x",r,g,b);
- fprintf(out,"\n ");
- }
- fprintf(out," grestore\n\n");
-
- // Draw the colorbar box
-
- if (boxwidth > 0)
- {
- setColor(out,ipc->border_color);
- fprintf(out, "%% Draw the box around the colorbar\n");
- fprintf(out," %g setlinewidth newpath\n",boxwidth);
- box(out,cbar_xoff,cbar_yoff,cbar_width,cbar_height);
- fprintf(out," stroke\n");
- }
-
- // Now, we want to do something a bit tricky: map the colors on
- // the "linear" color scale onto actual data values for tick
- // marks. The first thing we need to do is make what I will call
- // a "reverse map". Using this table, we can get a datapoint
- // value based on it's color value
-
- // We have to be a bit careful with rounding, particularly for
- // small gammas
- int l = iw->colormap_length;
- int reverse_map[l];
- for (int i=0; i<l; i++)
- reverse_map[i] = -1;
- for (int i=iw->hmin; i<iw->hmax; i++)
- {
- int index = 1.0*iw->imagehist[i]*(l-1)/LMAX;
- if (reverse_map[index] == -1) reverse_map[index] = i;
- }
- reverse_map[0] = iw->hmin;
- for (int i=0; i<l; i++)
- if (reverse_map[i] == -1) reverse_map[i] = reverse_map[i-1];
-
- // Now try to work out what the beginning color should be such
- // that we try to end up with a label at the value that the user
- // has asked for
-
- // TODO: FIX this at some point...
-
- double definitive_label = ipc->cbegin->value(); // will leave this name unchanged to avoid having to rewrite settings code...
- double c1=-1;
- // Get the quantized value from the raw value
- int val_quant = iw->id.raw_to_quant(definitive_label);
- // Get the position in the un-gammed colormap (float between 0 and 1)
- double cmap_position = iw->imagehist[val_quant]/LMAX;
- info("estimated cmap position is %f\n", cmap_position);
- if (c1 < ipc->cmin->value()) c1 = ipc->cmin->value();
-
- // Draw the tic marks on the colorbox
- fprintf(out,"/%s findfont %g scalefont setfont\n",ipc->face->value(),fontsize);
- fprintf(out," %g setlinewidth\n", tickwidth);
- char buf[256];
- if(ipc->cticfmt->size() != 0)
- {
- for (double c=c1; c < ipc->cmax->value(); c += ipc->clabelspacing->value())
- {
- int i = (int) (c*(l-1));
- double val = iw->id.quant_to_raw(reverse_map[i]);
-
- buf[0] = 0; // a good default
- if (ipc->cticfmt->value()[0] == 'e')
- {
- char *p = ipc->cticfmt->value()+1;
- long int dig = strtol(p, (char **)NULL, 10); // strtol returns zero if no digits are found
- if (dig == 0) dig = 2; // a reasonable default?
- strncpy(buf, eng(c, dig, 1), 128);
- }
- else if (ipc->cticfmt->value()[0] == 's')
- {
- char *p = ipc->cticfmt->value()+1;
- long int dig = strtol(p, (char **)NULL, 10); // strtol returns zero if no digits are found
- if (dig == 0) dig = 2; // a reasonable default?
- strncpy(buf, eng(c, dig, 0), 128);
- }
- else
- snprintf(buf,sizeof(buf),ipc->cticfmt->value(),c);
- info("cvalue %e label '%s'\n", c, buf);
- int tic_width = strlen(buf);
-
- if (tic_width > max_ctic_width) max_ctic_width = tic_width;
-
- double psx = cbar_xoff + cbar_width + 0.25*fontsize/INCH;
- double psy = cbar_yoff + cbar_height * ((c-ipc->cmin->value())/(ipc->cmax->value()-ipc->cmin->value()));
-
- // Draw the label
- setColor(out,ipc->text_color);
- fprintf(out," newpath %g inch %g inch moveto (%s) show\n",psx,psy-0.25*fontsize/INCH,buf);
-
- // Draw the tic lines
- if(ipc->fancy_ticks->value())
- {
- setColor(out,ipc->large_tick_color);
- fprintf(out,"%g setlinewidth newpath\n",tickwidth*2);
- fprintf(out," newpath %g inch %g inch moveto %g inch 0 rlineto stroke\n",cbar_xoff,psy,ticklength+tickwidth/72.0);
- fprintf(out," newpath %g inch %g inch moveto %g inch 0 rlineto stroke\n",cbar_xoff+cbar_width,psy,-ticklength-tickwidth/72.0);
- setColor(out,ipc->small_tick_color);
- fprintf(out,"%g setlinewidth newpath\n",tickwidth);
- fprintf(out," newpath %g inch %g inch moveto %g inch 0 rlineto stroke\n",cbar_xoff,psy,ticklength);
- fprintf(out," newpath %g inch %g inch moveto %g inch 0 rlineto stroke\n",cbar_xoff+cbar_width,psy,-ticklength);
- }
- else
- {
- setColor(out,ipc->small_tick_color);
- fprintf(out," newpath %g inch %g inch moveto %g inch 0 rlineto stroke\n",cbar_xoff,psy,ticklength);
- fprintf(out," newpath %g inch %g inch moveto %g inch 0 rlineto stroke\n",cbar_xoff+cbar_width,psy,-ticklength);
- }
- }
- }
- }
-}
-
-void Image_Printer::draw_axis_tics()
-{
-
- // *****************
- // Draw the xtics
- // *****************
-
- // Draw the tick marks
- fprintf(out,"/%s findfont %g scalefont setfont\n",ipc->face->value(),fontsize);
- fprintf(out," %g setlinewidth\n", tickwidth);
- if(ipc->xticfmt->value()[0] != '\0')
- {
- double xs;
- double xmin = iw->xunit(img_x1)*xscale;
- double xmax = iw->xunit(img_x2)*xscale;
-
- if(xspacing != 0)
- xs = fabs(xspacing);
- else
- xs=autospace(xmin,xmax);
-
- if(xmin > xmax)
- xs=-xs;
-
- // Tic marks should be on integers (1.0, 1.5,... not 1.37,1.87,...) and should not be outside the frame
- double min = xs*ceil(xmin/xs);
- double tic_offset, wrange;
- if (ipc->precise_ticks->value())
- {
- wrange=width*(img_xsize-1)/(img_xsize); // xmin is actually 1/2 pixel from the left edge, xmax is 1/2 pixel from the right.
- tic_offset = width*(0.5/(img_xsize));
- }
- else
- {
- wrange=width;
- tic_offset=0;
- }
- for(double x = min; x*xs <= xmax*xs + zero*xs*fabs(xs); x += xs)
- {
- //if(x < xmin)
- //continue;
- char buf[128];
- buf[0] = 0; // a good default
- if (ipc->xticfmt->value()[0] == 'e')
- {
- char *p = ipc->xticfmt->value()+1;
- long int dig = strtol(p, (char **)NULL, 10); // strtol returns zero if no digits are found
- if (dig == 0) dig = 2; // a reasonable default?
- strncpy(buf, eng(x, dig, 1), 128);
- }
- else if (ipc->xticfmt->value()[0] == 's')
- {
- char *p = ipc->xticfmt->value()+1;
- long int dig = strtol(p, (char **)NULL, 10); // strtol returns zero if no digits are found
- if (dig == 0) dig = 2; // a reasonable default?
- strncpy(buf, eng(x, dig, 0), 128);
- }
- else
- {
- if(fabs(x/xs) < zero)
- snprintf(buf,sizeof(buf),ipc->xticfmt->value(),0.0);
- else
- snprintf(buf,sizeof(buf),ipc->xticfmt->value(),x);
- }
- //info("xvalue %e label '%s'\n", x, buf);
-
- double psy = yoff-1.0*fontsize/INCH; //
- double psx = xoff + wrange * ((x-xmin)/(xmax-xmin)) + tic_offset;
- setColor(out,ipc->text_color);
- fprintf(out," newpath %g inch %g inch moveto (%s) centershow\n",psx,psy,buf);
- if(ipc->fancy_ticks->value())
- {
- setColor(out,ipc->large_tick_color);
- fprintf(out,"%g setlinewidth newpath\n",tickwidth*2);
- fprintf(out," newpath %g inch %g inch moveto 0 %g inch rlineto stroke\n",psx,yoff,ticklength+tickwidth/72.0);
- fprintf(out," newpath %g inch %g inch moveto 0 %g inch rlineto stroke\n",psx,yoff+height,-ticklength-tickwidth/72.0);
- setColor(out,ipc->small_tick_color);
- fprintf(out,"%g setlinewidth newpath\n",tickwidth);
- fprintf(out," newpath %g inch %g inch moveto 0 %g inch rlineto stroke\n",psx,yoff,ticklength);
- fprintf(out," newpath %g inch %g inch moveto 0 %g inch rlineto stroke\n",psx,yoff+height,-ticklength);
- }
- else
- {
- setColor(out,ipc->small_tick_color);
- fprintf(out," newpath %g inch %g inch moveto 0 inch %g inch rlineto stroke\n",psx,yoff,ticklength);
- fprintf(out," newpath %g inch %g inch moveto 0 inch %g inch rlineto stroke\n",psx,yoff+height,-ticklength);
- }
- }
-
-
- }
-
- // *****************
- // Draw the ytics
- // *****************
-
- if(ipc->yticfmt->value()[0] != '\0')
- {
- double ys;
- // we have some issues due to the fact that "y=0" for the fltk
- // drawing routines is at the top of the screen...we must
- // remember that ymax = y1 and ymin = y2...
- double ymin = iw->yunit(img_y2)*yscale;
- double ymax = iw->yunit(img_y1)*yscale;
-
- if(yspacing != 0)
- ys = fabs(yspacing);
- else
- ys=autospace(ymin,ymax);
-
- if(ymin > ymax)
- ys=-ys;
-
- int tic_width;
-
- // This is horrible; everything changes when ys and ymin change sign.
- double min = ys*ceil(ymin/ys);
- double hrange, tic_offset;
- if (ipc->precise_ticks->value())
- {
- hrange = height*(img_ysize-1)/(img_ysize);
- tic_offset = height*(0.5/(img_ysize));
- }
- else
- {
- hrange = height;
- tic_offset = 0;
- }
- for(double y = min; y*ys <= ymax*ys + zero*ys*fabs(ys); y += ys)
- {
- // warn("%g\n",y);
- char buf[128];
- buf[0] = 0; // a good default
- if (ipc->yticfmt->value()[0] == 'e')
- {
- char *p = ipc->yticfmt->value()+1;
- long int dig = strtol(p, (char **)NULL, 10); // strtol returns zero if no digits are found
- if (dig == 0) dig = 2; // a reasonable default?
- strncpy(buf, eng(y, dig, 1), 128);
- }
- else if (ipc->yticfmt->value()[0] == 's')
- {
- char *p = ipc->yticfmt->value()+1;
- long int dig = strtol(p, (char **)NULL, 10); // strtol returns zero if no digits are found
- if (dig == 0) dig = 2; // a reasonable default?
- strncpy(buf, eng(y, dig, 0), 128);
- }
- else
- {
- if(fabs(y/ys) < zero)
- snprintf(buf,sizeof(buf),ipc->yticfmt->value(),0.0);
- else
- snprintf(buf,sizeof(buf),ipc->yticfmt->value(),y);
- }
- //info("yvalue %e label '%s'\n", y, buf);
- tic_width = strlen(buf);
-
- if (tic_width > max_ytic_width) max_ytic_width = tic_width;
- double psx = xoff-0.25*fontsize/INCH; //
- double psy = yoff + hrange * ((y-ymin)/(ymax-ymin)) + tic_offset;
- setColor(out,ipc->text_color);
- fprintf(out," newpath %g inch %g inch moveto (%s) rightshow\n",psx,psy-0.25*fontsize/INCH,buf);
-
- if(ipc->fancy_ticks->value())
- {
- setColor(out,ipc->large_tick_color);
- fprintf(out,"%g setlinewidth newpath\n",tickwidth*2);
- fprintf(out," newpath %g inch %g inch moveto %g inch 0 rlineto stroke\n",xoff,psy,ticklength+tickwidth/72.0);
- fprintf(out," newpath %g inch %g inch moveto %g inch 0 rlineto stroke\n",xoff+width,psy,-ticklength-tickwidth/72.0);
- setColor(out,ipc->small_tick_color);
- fprintf(out,"%g setlinewidth newpath\n",tickwidth);
- fprintf(out," newpath %g inch %g inch moveto %g inch 0 rlineto stroke\n",xoff,psy,ticklength);
- fprintf(out," newpath %g inch %g inch moveto %g inch 0 rlineto stroke\n",xoff+width,psy,-ticklength);
- }
- else
- {
- setColor(out,ipc->small_tick_color);
- fprintf(out," newpath %g inch %g inch moveto %g inch 0 rlineto stroke\n",xoff,psy,ticklength);
- fprintf(out," newpath %g inch %g inch moveto %g inch 0 rlineto stroke\n",xoff+width,psy,-ticklength);
- }
- }
- }
-}
-
-void Image_Printer::draw_axis_labels()
-{
-
- // Draw the labels
-
- double label_x, label_y;
-
- setColor(out,ipc->text_color);
- if (ipc->yaxis_label->value())
- {
- // Notes: as a nasty hack, assume an average font aspect ration
- // of 2:1. Also, offset us by an extra 3.5 font widths (note
- // max_ytic_width includes terminating null)
-
- // Would probably be better to keep a copy of the longest ytic
- // string and then have the postscript interpret the
- // width for us...but this seems to work reasonably well.
-
- label_x = xoff - (max_ytic_width+2.5)*fontsize/2.0/INCH;
- label_y = yoff + height/2;
- fprintf(out, " newpath %g inch %g inch moveto (%s) 90 rotate centershow -90 rotate\n", label_x, label_y, iw->id.yname.c_str());
- }
-
- if (ipc->caxis_label->value() && ipc->colorbar->value())
- {
- label_x = cbar_xoff + cbar_width + (max_ctic_width+3.5)*fontsize/2.0/INCH;
- label_y = cbar_yoff + cbar_height/2;
- fprintf(out, " newpath %g inch %g inch moveto (%s) 90 rotate centershow -90 rotate\n", label_x, label_y, iw->id.zname.c_str());
- }
-
- if (ipc->xaxis_label->value())
- {
- label_x = xoff + width/2;
- label_y = yoff - 2.5*fontsize/INCH;
- fprintf(out, " newpath %g inch %g inch moveto (%s) centershow\n", label_x, label_y, iw->id.xname.c_str());
- }
-
- if (ipc->do_title->value())
- {
- label_x = xoff + width/2;
- label_y = yoff + height + 1.0*fontsize/INCH;
- char buf[1024];
- char bn[1024];
- strncpy(bn, iw->output_basename, sizeof(bn));
- char *p = basename(bn);
- info("%s -> %s\n", iw->output_basename, p);
- snprintf(buf, 1024, ipc->title->value(), p, iw->id.zname.c_str());
- // Postscript needs to have double \\ to display properly
- string name = buf;
- string::size_type pos=0;
- while ((pos = name.find("\\", pos+2)) != string::npos)
- name.replace(pos, 1, "\\\\");
- fprintf(out, " newpath %g inch %g inch moveto (%s) centershow\n", label_x, label_y, name.c_str());
- }
-}
-
-void Image_Printer::add_dirstamp()
-{
- double label_x, label_y;
- if (ipc->paper_eps->value())
- {
- label_x = bb_ur_x/INCH - 0.25;
- label_y = bb_ll_y/INCH - 0.25;
- bb_ll_y -= 0.25*INCH + 5;
- }
- else
- {
- label_x = page_width - 0.25;
- label_y = 0.25;
- }
- char buf[PATH_MAX];
- getcwd(buf, PATH_MAX);
- string name = buf;
- string::size_type pos=0;
- while ((pos = name.find("\\", pos+2)) != string::npos)
- name.replace(pos, 1, "\\\\");
- fprintf(out,"/%s findfont %g scalefont setfont\n",ipc->face->value(),10.0);
- fprintf(out, " newpath %g inch %g inch moveto (%s) rightshow\n", label_x, label_y, name.c_str());
-}
+++ /dev/null
-#include <assert.h>
-#include <string>
-#include <FL/fl_ask.H>
-#include <sys/time.h>
-#include "ImageWindow.H"
-#include "ImagePrinter.H"
-#include "math.h"
-#include "message.h"
-#include <FL/Fl_Color_Chooser.H>
-#include <stdarg.h>
-#include "throttle.H"
-#include "ImageWindow_Module.H"
-#include <ctype.h>
-
-#ifdef WIN32
-
-#include <windows.h>
-
-// For win32 gettimeofday():
-// Copied from http://www.cpp-programming.net/c-tidbits/gettimeofday-function-for-windows/
-#include <time.h>
-#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
-#define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64
-#else
-#define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL
-#endif
-
-#endif
-
-// Bitwise if and only if
-//#define iff(A,B) ((A & B) && !(A & !B))
-// not as useful as I thought since events also include numlock...
-
-#define ctrl(state) ( (state & FL_CTRL) && !(state & FL_SHIFT) && !(state & FL_ALT))
-#define shift(state) (!(state & FL_CTRL) && (state & FL_SHIFT) && !(state & FL_ALT))
-#define alt(state) (!(state & FL_CTRL) && !(state & FL_SHIFT) && (state & FL_ALT))
-#define none(state) (!(state & FL_CTRL) && !(state & FL_SHIFT) && !(state & FL_ALT))
-
-using namespace std;
-
-FILE *fopenwarn(const char *name, const char *mode)
-{
- FILE *fp = fopen(name, mode);
-
- if (fp == NULL)
- warn("Could not open file %s in mode \"%s\": %s\n", name, mode, strerror(errno));
- return fp;
-}
-
-static void nognuplot()
-{
- static bool warned = false;
- if(warned)
- return;
-#ifdef WIN32
- warn("Gnuplot is not available. Please install gnuplot for windows and put it on your path.\n");
-#else
- warn("Unable to open gnuplot\n");
-#endif
-}
-
-
-void ImageWindow::make_tmpfiles()
-{
-
- // If we can, we will use local files xsection.dat, hist.dat and
- // cmap.dat in the current directory, as a convenient way to give
- // the user access to this data
- //
- // If we can't (ie. directory is read only), we will use files in /tmp.
-
- FILE *fp;
- static int ntries;
-
- snprintf(xsection_fn, sizeof(xsection_fn), "%sxsection.%d.dat.%d", Gnuplot_Interface::tmpdir(), ntries, getpid());
- if ((fp = fopen(xsection_fn, "w")) == NULL)
- { error("Failed to create tempfile %s: %s\n", xsection_fn, strerror(errno)); }
- else fclose(fp);
-
- snprintf(xsection_tmp_fn, sizeof(xsection_fn), "%sxsection.%d.dat.tmp_%d", Gnuplot_Interface::tmpdir(), ntries, getpid());
- if ((fp = fopen(xsection_fn, "w")) == NULL)
- { error("Failed to create tempfile %s: %s\n", xsection_tmp_fn, strerror(errno)); }
- else fclose(fp);
-
- snprintf(cmap_fn, sizeof(cmap_fn), "%scmap.%d.dat.%d", Gnuplot_Interface::tmpdir(), ntries, getpid());
- if ((fp = fopen(cmap_fn, "w")) == NULL)
- { error("Failed to create tempfile %s: %s\n", cmap_fn, strerror(errno)); }
- else fclose(fp);
-
- snprintf(hist_fn, sizeof(hist_fn), "%shist.%d.dat.%d", Gnuplot_Interface::tmpdir(), ntries, getpid());
- if ((fp = fopen(hist_fn, "w")) == NULL)
- { error("Failed to create tempfile %s: %s\n", hist_fn, strerror(errno)); }
- else fclose(fp);
-
- info("Locations of temporary files:\n%s\n%s\n%s\n", xsection_fn, cmap_fn, hist_fn);
-}
-
-ImageWindow::ImageWindow(int w, int h, const char *title) :
- Fl_Overlay_Window(w,h) , ipc(this) , pfc(this)
-{
- stupid_windows_focus = getenv("SPYVIEW_CLICKY") == NULL;
-
- gplinecut.bidirectional=true;
- line_cut_limit = HORZLINE | VERTLINE | OTHERLINE | NOLINE;
- //size_range(1,1);
- zoomWindowDragging = ZOOM_NO;
- statusCallback = NULL;
- datamin = 0; datamax = LMAX;
- hmin = 0; hmax = LMAX;
-
- xzoom = yzoom = 1;
- swap_zoom_state=false;
- square = 0;
- line_cut_type = NOLINE;
- line_cut_xauto = 1;
- plot_hist = false;
- plot_cmap = false;
- bpercent = 0.1; wpercent = 0.1;
- // plane_a = plane_b = plane_c = 0;
- process_queue = NULL;
- controls_window = NULL;
- external_update = NULL;
- drag_n_drop = NULL;
- window_size_action = KEEPZOOM;
- cmap_min = 0.0;
- cmap_max = 1.0;
-
- sprintf(gp_using_string, "1:2");
- gp_with_string = "lp";
-
- lc_axis = DISTANCE;
-
- make_tmpfiles();
-
- // By default, install an 8 bit greyscale colormap.
- colormap_length = 256;
- colormap = new uchar[colormap_length*3];
- gammatable = new int[colormap_length];
-
- for (int i=0; i<256; i++)
- colormap[3*i] = colormap[3*i+1] = colormap[3*i+2] = i;
-
- gam = 1;
- gcenter = 0.0;
- for (int i=0; i<256; i++)
- gammatable[i] = i;
-
- // Create the colormap window
- colormap_window = new ColormapWindow(256,25);
- colormap_window->img = this;
- colormap_window->label("Colormap");
- // Colormap window is now controlled from UI. Don't show by default.
- // colormap_window->show();
-
- imageprinter = new Image_Printer(this, &ipc);
-
- // Note: pfc is initialized with the constructor of ImageWindow
- pf = new PeakFinder(this, &pfc);
-}
-
-void ImageWindow::resize(int x, int y, int wp, int hp)
-{
- int target_xzoom, target_yzoom;
-
- // This is tricky...
-
- if (wp == w) target_xzoom = 1; // Zoom should be 1
- else if (wp*(-xzoom) == w) target_xzoom = -w/wp; // Requested size corresponds exactly to a negative zoom
- else if (wp < w && wp*(-xzoom) != w) target_xzoom = -w/(wp+1)-1; //Negative zoom, need to trucate downwards (-1) and be careful of images with odd number of points (wp+1)
- else target_xzoom = wp/w; // Positive zoom: truncation has desired effect, odd number of points not a problem.
-
- if (hp == h) target_yzoom = 1;
- else if (hp < h && hp*(-yzoom) != h) target_yzoom = -h/(hp+1)-1;
- else if (hp*(-yzoom) == h) target_yzoom = -h/hp;
- else target_yzoom = hp/h;
-
- if (xzoom != target_xzoom || yzoom != target_yzoom)
- {
- xzoom = target_xzoom;
- yzoom = target_yzoom;
- allocateImage();
- }
-
- external_update();
- size_range(1,1);
- Fl_Overlay_Window::resize(x,y,wp,hp);
-}
-
-ImageWindow::~ImageWindow()
-{
- if(imageprinter)
- delete imageprinter;
- unlink(xsection_fn);
- unlink(cmap_fn);
- unlink(hist_fn);
- unlink(xsection_tmp_fn);
- unlink("xsection.dat");
- unlink("cmap.dat");
- unlink("hist.dat");
-}
-
-void ImageWindow::draw()
-{
- if (!id.data_loaded) return;
- imageprinter->updatePreview();
-
- // data = original data read from file
- //
- // databuf = copy of data[] to store grey data in after we've performed integer
- // operations, like rescaling the contrast using the imagehist lookup
- // table, appling the gamma scaling using the gammatable lookup
- // table, and performing the plane subtraction.
- //
- // Data starts off in data[] in whatever range of values that is
- // occupied in the input image.
- //
- // After plane subtraction, data may exceed LMAX or be less than 0,
- // so we need to trucate these values.
- //
- // The data between hmin and hmax then gets mapped to 0 to LMAX by
- // the imagehist lookup table.
- //
- // The gammatable lookup is then applied, and each pixel in the
- // databuf array will then have a value that ranges from 0 to
- // colormap_length-1.
- //
- // In the final step, the colormap lookup table is applied, which is
- // used to map the data onto a 8x8x8 bit RGB image.
-
- // warn("Drawing %dx%d image, xzoom=%d, yzoom=%d, total=%dx%d (%d bytes)\n",
- // w,h,xzoom,yzoom,w*xzoom,h*yzoom,3*(w*xzoom+h*yzoom));
-
- // This next chunk of code centers the image. It should only matter if we're displaying an image bigger than
- // 255x255, in which case by resizing the window manually, the user can make the window not be an intereger
- // zoom of the original image.
- // Zooming by using < and > will still always give an integer zoom.
- int ox, oy; // X and Y offsets.
- ox = Fl_Overlay_Window::w() - w*xzoom;
- oy = Fl_Overlay_Window::h() - h*yzoom;
- if(ox != 0 || oy != 0)
- {
- ox /= 2; // Center the image. We don't do this outside the if so if the image is only 1 pixel too small,
- oy /= 2; // we still fill in the border in black.
- fl_color(FL_BLACK);
- fl_rectf(0,0,Fl_Overlay_Window::w(), Fl_Overlay_Window::h());
- }
- ox=0; // Argh! Centering the image kills the line cuts! Too lazy to fix this right.
- oy=0;
-
- // Ok, let's finally clean this up a bit. I will now make this
- // compatible with "negative" zoom (ie. shrinking the image). To
- // keep things simple at first, I will do this by just skipping
- // points (a smarter thing to do would be to average).
-
- int row, col; // column and row in the data file
- int imgcol, imgrow; // column and row in the image output file
- int n, m; // repeat indices for col and row
- int iw, ih;
-
- iw = dozoom(w,xzoom);
- ih = dozoom(h,yzoom);
-
- row = 0; n = 0;
- while (row<h) // loop through rows (col = 0; col <h; col++)
- {
- if (yzoom < 0)
- {
- if (row%(-yzoom) != 0)
- {
- row++;
- continue;
- }
- else imgrow = row/(-yzoom);
- }
- else imgrow = yzoom*row + n;
- if (imgrow > ih-1) break;
-
- col = 0; m = 0;
- while (col<w) // now loop through columns
- {
- if (xzoom < 0)
- {
- if (col%(-xzoom) != 0)
- {
- col++;
- continue;
- }
- else imgcol = col/(-xzoom);
- }
- else imgcol = xzoom*col + m;
- if (imgcol > iw-1) break;
-
- // Now actually decide on a color for the pixel
-
- unsigned char r,g,b;
- getrgb(row,col,r,g,b);
-
- image[3*imgrow*iw+3*imgcol] = r;
- image[3*imgrow*iw+3*imgcol+1] = g;
- image[3*imgrow*iw+3*imgcol+2] = b;
-
- if (3*imgrow*iw+3*imgcol+2 > dozoom(w,xzoom)*dozoom(h,yzoom)*3)
- {
- warn( "row %d col %d n %d m %d ir %d ic %d iw %d ih %d iw*ih*3 %d over bounds %d > %d\n",
- row, col, n, m, imgrow, imgcol, iw, ih, iw*ih*3, 3*imgrow*iw+3*imgcol+2,
- dozoom(w,xzoom)*dozoom(h,yzoom)*3);
- exit(-1);
- }
- if (xzoom < 0 || m == xzoom-1)
- {
- m=0; col++;
- if (col == w) break;
- else continue;
- }
- else
- {
- m++; continue;
- }
- }
-
- if (yzoom < 0 || n == yzoom-1)
- {
- n=0; row++;
- if (row == h) break;
- else continue;
- }
- else
- {
- n++; continue;
- }
- }
-
- fl_draw_image(image, ox, oy, iw, ih, 3, 0);
- if(zoom_window)
- zoom_window->redraw();
-}
-
-void ImageWindow::draw_overlay()
-{
- if (pfc.hide_data->value())
- fl_rectf(0,0,dozoom(w,xzoom),dozoom(h,yzoom),0,0,0);
-
- imageprinter->updatePreview();
- if (line_cut_type)
- {
- fl_color(FL_RED);
- if (line_cut_type == HORZLINE)
- fl_line(dozoom(w,xzoom),dozoom(line_cut_yp,yzoom)+dozoom(1,yzoom)/2,
- 0,dozoom(line_cut_yp,yzoom)+dozoom(1,yzoom)/2);
- else if (line_cut_type == VERTLINE)
- fl_line(dozoom(line_cut_xp,xzoom)+dozoom(xzoom,1)/2,0,
- dozoom(line_cut_xp,xzoom)+dozoom(xzoom,1)/2,dozoom(h,yzoom));
- else if (line_cut_type == OTHERLINE)
- fl_line(dozoom(lcx1,xzoom)+dozoom(1,xzoom)/2,
- dozoom(lcy1,yzoom)+dozoom(1,yzoom)/2,
- dozoom(lcx2,xzoom)+dozoom(1,xzoom)/2,
- dozoom(lcy2,yzoom)+dozoom(1,yzoom)/2);
- }
-
- if((zoom_window && zoom_window->visible()) || (zoomWindowDragging))
- {
- fl_color(FL_GREEN);
- if(!zoomWindowDragging)
- zoom_window->getSourceArea(zwd_x1,zwd_y1,zwd_x2,zwd_y2);
- int x2off = (xzoom > 0) ? 1 : 0;
- int y2off = (yzoom > 0) ? 1 : 0;
- fl_line(dozoom(zwd_x1,xzoom),
- dozoom(zwd_y1,yzoom),
- dozoom(zwd_x2,xzoom)-x2off,
- dozoom(zwd_y1,yzoom));
- fl_line(dozoom(zwd_x2,xzoom)-x2off,
- dozoom(zwd_y1,yzoom),
- dozoom(zwd_x2,xzoom)-x2off,
- dozoom(zwd_y2,yzoom)-y2off);
- fl_line(dozoom(zwd_x2,xzoom)-x2off,
- dozoom(zwd_y2,yzoom)-y2off,
- dozoom(zwd_x1,xzoom),
- dozoom(zwd_y2,yzoom)-y2off);
- fl_line(dozoom(zwd_x1,xzoom),
- dozoom(zwd_y2,yzoom)-y2off,
- dozoom(zwd_x1,xzoom),
- dozoom(zwd_y1,yzoom));
- }
-
- if(pf->peaks != NULL && (pfc.plot_peaks->value() || pfc.plot_valleys->value()))
- {
- for (int j=0; j<h; j++)
- {
- for (int i=0; i<w; i++)
- {
- if (i>=pf->w || j>=pf->h)
- // So that we can plot peaks from previous IP settings
- // on top of current data without a segfault
- continue;
- if (pf->peaks[j*w+i] == 1 && pfc.plot_peaks->value())
- draw_overlay_pixel(i,j,pfc.peak_color_box->color());
- else if (pf->peaks[j*w+i] == -1 && pfc.plot_valleys->value())
- draw_overlay_pixel(i,j,pfc.valley_color_box->color());
- }
- }
- }
-
- for(modules_t::iterator i = modules.begin(); i != modules.end(); i++)
- (*i)->overlay_callback();
-}
-
-void ImageWindow::draw_overlay_pixel(int i, int j, Fl_Color color)
-{
- int rw = (xzoom < 0) ? 1 : xzoom;
- int rh = (yzoom < 0) ? 1 : yzoom;
- fl_color(color);
- fl_rectf(dozoom(i,xzoom), dozoom(j,yzoom), rw, rh);
-}
-
-void ImageWindow::draw_overlay_pixel(int i, int j, uchar r, uchar g, uchar b)
-{
- int rw = (xzoom < 0) ? 1 : xzoom;
- int rh = (yzoom < 0) ? 1 : yzoom;
- fl_color(r,g,b);
- fl_rectf(dozoom(i,xzoom), dozoom(j,yzoom), rw, rh);
-}
-
-void ImageWindow::makeZoomWindow()
-{
- if(zoom_window == NULL)
- {
- zoom_window = new ZoomWindow(dozoom(w,xzoom)/5,dozoom(h,yzoom)/5); // *.1 * 2 = /5, 10% of image size (default zoom is 2)
- zoom_window->img = this;
- zoom_window->size_range(1,1);
- if (xzoom > 1) zoom_window->xscale *= xzoom;
- if (yzoom > 1) zoom_window->yscale *= yzoom;
- }
-}
-void ImageWindow::showZoomWindow(bool toggle)
-{
- makeZoomWindow();
- if(zoom_window->visible() && toggle)
- zoom_window->hide();
- else
- zoom_window->show();
-}
-
-// Helper function for the middle-shift button below.
-inline static double distance_squared(double x1, double y1, double x2, double y2)
-{
- x1 -= x2;
- y1 -= y2;
- return x1*x1+y1*y1;
-}
-
-// Check to see if (x1,y1) is closer to (x2,y2) than squared-distance distance. If it is, update
-// distance to the distance between them, and set zoomWindowDragging to zw
-// Helper function for the middle-shift button below.
-void ImageWindow::tryZoomCorner(int x1, int y1, int x2, int y2, zoomWindowDragging_t zw, double &dist)
-{
- double nd = distance_squared(x1,y1,x2,y2);
- if(nd < dist)
- {
- dist = nd;
- zoomWindowDragging = zw;
- }
-}
-
-// adapted from from http://www.cpp-programming.net/c-tidbits/gettimeofday-function-for-windows/
-double current_time()
-{
- struct timeval stop;
-#ifndef WIN32
- gettimeofday(&stop, NULL);
-#else
- FILETIME ft;
- unsigned __int64 tmpres = 0;
- GetSystemTimeAsFileTime(&ft);
- tmpres |= ft.dwHighDateTime;
- tmpres <<= 32;
- tmpres |= ft.dwLowDateTime;
- /*converting file time to unix epoch*/
- tmpres /= 10; /*convert into microseconds*/
- tmpres -= DELTA_EPOCH_IN_MICROSECS;
- stop.tv_sec = (long)(tmpres / 1000000UL);
- stop.tv_usec = (long)(tmpres % 1000000UL);
-#endif
- double time = (((double)(stop.tv_sec)) + ((double)(stop.tv_usec) * 1e-6));
- if (!isnormal(time))
- info("time %e sec %d usec %d\n", time, stop.tv_sec, stop.tv_usec);
- return time;
-}
-
-int ImageWindow::handle(int event)
-{
- static double lastFocus = 0; // Time when we got the focus, or NAN if we don't have the focus.
- static double t0Focus = current_time(); // Just a handy offset for debug messages
- static bool hungryFocus = false; // If this is true, we're eating push/drag events because this was the click that focused the mouse.
- static bool inFocus = false; // This is set to true when we get a focus event
- //if (event == FL_ENTER)
- // info("got FL_ENTER\n");
- //if (event == FL_MOVE)
- // info("got FL_MOVE\n");
- //Fl_Window::handle() was stealing our FL_ENTER and FL_MOVE events
- //if (Fl_Window::handle(event)) return 1;
-
- for(modules_t::iterator i = modules.begin(); i != modules.end(); i++)
- {
- int r = (*i)->event_callback(event);
- if(r)
- return r;
- }
-
- int n;
- int button = Fl::event_button();
-
- if ((button == 3) && (Fl::event_state() & FL_ALT))
- button = 2;
-
- switch (event)
- {
- // Drag and drop
- case FL_DND_ENTER: // return(1) for these events to 'accept' dnd
- case FL_DND_DRAG:
- case FL_DND_RELEASE:
- return(1);
- case FL_PASTE: // handle actual drop (paste) operation
- (*drag_n_drop)(Fl::event_text());
- return(1);
- case FL_SHOW:
- // Use a cross cursor
- cursor(FL_CURSOR_CROSS);
- break;
- case FL_KEYUP:
- n = Fl::event_key();
- if(statusCallback)
- statusCallback(n,false);
- break;
- case FL_KEYDOWN:
- n = Fl::event_key();
- if(statusCallback)
- statusCallback(n,true);
- switch(n)
- {
-// case 'd':
-// dumpColormap();
-// return 1;
- case 's':
- switch(Fl::event_state() & (FL_SHIFT | FL_CTRL | FL_ALT))
- {
- case FL_ALT:
- // Snap the window size to the actual image size
- size(dozoom(w,xzoom), dozoom(h,yzoom));
- return 1;
- case FL_CTRL:
- if(zoom_window)
- {
- zoom_window->autonormalize = !zoom_window->autonormalize;
- return 1;
- }
- // Falling case
- case FL_SHIFT:
- normalizeOnZoom();
- return 1;
- }
- break;
- case 'z':
- if (Fl::event_state() & FL_CTRL)
- exportMTX(false, true);
- else
- showZoomWindow(true);
- return 1;
- break;
- case '.':
- if (Fl::event_state() & FL_SHIFT)
- {
- setXZoom(xzoom+1);
- damage(FL_DAMAGE_ALL);
- }
- else if (Fl::event_state() & FL_CTRL)
- {
- setYZoom(yzoom+1);
- damage(FL_DAMAGE_ALL);
-
- }
- else
- {
- setXZoom(xzoom+1);
- setYZoom(yzoom+1);
- damage(FL_DAMAGE_ALL);
- }
- return 1;
- case ',':
- if (Fl::event_state() & FL_SHIFT)
- {
- setXZoom(xzoom-1);
- damage(FL_DAMAGE_ALL);
- }
-
- else if (Fl::event_state() & FL_CTRL)
- {
- setYZoom(yzoom-1);
- damage(FL_DAMAGE_ALL);
-
- }
- else
- {
- setXZoom(xzoom-1);
- setYZoom(yzoom-1);
- damage(FL_DAMAGE_ALL);
- }
- return 1;
- case '1':
- if (Fl::event_state() & FL_SHIFT)
- (xzoom > yzoom) ? setXZoom(yzoom) : setYZoom(xzoom);
- else
- (xzoom > yzoom) ? setYZoom(xzoom) : setXZoom(yzoom);
- damage(FL_DAMAGE_ALL);
- return 1;
-// case 'i':
-// invert = !invert;
-// plotCmap();
-// redraw();
-// colormap_window->update();
-// if (external_update != NULL)
-// (*external_update)();
-// return 1;
-// case 'h':
-// plot_hist = !plot_hist;
-// plotHist();
-// if (external_update != NULL)
-// (*external_update)();
-// return 1;
- default:
- if(isalpha(n))
- {
- char buf[4096];
- const char *cmd = getenv("SPYVIEW_EXTERNAL");
- if(cmd == NULL)
- break;
- int ix = get_event_x();
- int iy = get_event_y();
- snprintf(buf,sizeof(buf),"%s %c %g %g %d %d", cmd, n, id.getX(ix), id.getY(iy),ix, iy);
- int res = system(buf);
- if(res == -1)
- warn("Unable to run command: \"%s\": %s\n",buf, strerror(errno));
- if(res == 0)
- {
- info("Reloading: \"%s\"\n",filename.c_str());
- string s = filename; // We copy here because loadData nukes filename right away.
- loadData(s.c_str());
- }
- }
- break;
-
- }
- break;
-
- case FL_MOVE:
- if(statusCallback)
- statusCallback(-1,true);
- break;
-
- case FL_FOCUS:
- lastFocus = current_time();
- inFocus = true;
- //info("focus event time %g\n", lastFocus);
- //fprintf(stderr,"recieved focus %g time %g t0 %g\n",lastFocus-t0Focus, lastFocus, t0Focus);
- return Fl_Overlay_Window::handle(event);
-
- case FL_UNFOCUS:
- lastFocus = NAN;
- inFocus = false;
- //fprintf(stderr,"Defocus %g at time %g t0 %g\n",current_time()-t0Focus, current_time(), t0Focus);
- return Fl_Overlay_Window::handle(event);
-
-/* Focus logic:
- When we are focused, ignore the *FIRST* mouse click if it occurs within 50 ms of becoming focused. This way, if the user
- focuses the window with a non-mouse click action (alt-tab), we're in good shape as long as they're not *really* fast. In
- practice, I usually see the click event comes within a few microseconds (!) of the focus event (under wine)
- If we ignored a click, ignore follow-up drag and release events, unless the user keeps the button down for at least
- one second. If they do, assume they're frustrated and give in.
- If we get a click when unfocused, assume it's an immediate prelude to being focused and treat it as a click within 50ms of
- getting focused. This never seems to happen (under my WM in Linux and wine. Probably smart to leave the logic in)
-*/
-
- case FL_PUSH:
- if(isnan(lastFocus) && stupid_windows_focus)
- {
- fprintf(stderr,"Ate unfocused click. This apparently never happens.\n");
- hungryFocus = true;
- lastFocus = current_time();
- return Fl_Overlay_Window::handle(event);
- }
- // Warning: you can have an unfocused drag or release under linux; we shouldn't eat these!
- // For this reason, we will only eat things if we are in focus
- case FL_DRAG: // Falling case!
- case FL_RELEASE:
-
- // For FL_DRAG, we cannot rely on Fl::event_button() (although
- // it seems to work on unix) I don't know why I can't replace
- // the Fl::event_buttion() above with this, but if I do, the
- // zoom window stops working...
- if (Fl::event_state() & FL_BUTTON1)
- button = 1;
- else if (Fl::event_state() & FL_BUTTON2)
- button = 2;
- else if (Fl::event_state() & FL_BUTTON3)
- {
- if (Fl::event_state() & FL_ALT)
- button = 2;
- else
- button = 3;
- }
- // Let's only eat a non-modified button 1 click
- if(stupid_windows_focus && (button == 1) && !(Fl::event_state() & FL_SHIFT) && !(Fl::event_state() & FL_CTRL))
- {
- if (hungryFocus)
- {
- if (inFocus)
- {
- if(event == FL_RELEASE || (current_time() - lastFocus >= 0.1))
- {
- //fprintf(stderr,"Focus eating is done (100 ms after initial click) %g\n",current_time()-lastFocus);
- lastFocus = 0;
- hungryFocus = false;
- return Fl_Overlay_Window::handle(event);
- }
- else
- {
- fprintf(stderr,"Ate drag/release event, t<100 ms after focus click %g\n",current_time()-lastFocus);
- return Fl_Overlay_Window::handle(event);
- }
- }
- }
- else if ((current_time() - lastFocus < 0.05))
- {
- //fprintf(stderr,"Ate initial click (%g) last %g t0 %g\n",lastFocus-t0Focus, lastFocus, t0Focus);
- hungryFocus = true;
- return Fl_Overlay_Window::handle(event);
- }
- }
-
- if(statusCallback)
- statusCallback(-1,true);
-
- int state = Fl::event_state();
- int tmp;
- double d1,d2;
- if (none(state) || alt(state)) // horz/vert LC
- switch(button)
- {
- case 1:
- tmp = get_event_y();
- if (tmp > h-1)
- tmp = h-1;
- if (line_cut_yp < 0)
- tmp = 0;
- if (line_cut_yp == tmp && line_cut_type == HORZLINE)
- return 1;
- if(!(line_cut_limit & HORZLINE))
- return 1;
- line_cut_yp = tmp;
- line_cut_type = HORZLINE;
- plotLineCut();
- redraw_overlay();
- return 1;
- case 3:
- if(!alt(state))
- break; // Right-alt is vertical, but not right-unshifted.
- case 2:
- tmp = get_event_x();
- if (tmp > w-1)
- tmp = w-1;
- if (tmp < 0)
- tmp = 0;
- if (line_cut_xp == tmp && line_cut_type == VERTLINE) return 1;
- if(!(line_cut_limit & VERTLINE))
- return 1;
- line_cut_xp = tmp;
- line_cut_type = VERTLINE;
- plotLineCut();
- redraw_overlay();
- return 1;
- default:
- return Fl_Overlay_Window::handle(event);
- }
- else if (shift(state)) // zoom windows (this is a long one)
- switch(button)
- {
- case 1:
- switch(event)
- {
- case FL_PUSH:
- zwd_x1 = get_event_x();
- zwd_y1 = get_event_y();
- zwd_x2 = zwd_x1;
- zwd_y2 = zwd_y1;
- zoomWindowDragging = ZOOM_DRAG;
- break;
- case FL_RELEASE:
- zwd_x2 = get_event_x();
- zwd_y2 = get_event_y();
- makeZoomWindow();
- zoom_window->center_x = (zwd_x1+zwd_x2)/2;
- zoom_window->center_y = (zwd_y1+zwd_y2)/2;
- zoom_window->size((abs(zwd_x2-zwd_x1))*zoom_window->xscale, (abs(zwd_y2-zwd_y1))*zoom_window->yscale);
- showZoomWindow();
- zoom_window->zoomMoved();
- zoomWindowDragging = ZOOM_NO;
- break;
- case FL_DRAG:
- zwd_x2 = get_event_x();
- zwd_y2 = get_event_y();
- redraw_overlay();
- break;
- }
- break;
- case 2:
- if(zoom_window == NULL)
- return 1;
- switch(event)
- {
- case FL_PUSH:
- {
- int mx1 = get_event_x();
- int my1 = get_event_y();
- zoom_window->getSourceArea(zwd_x1,zwd_y1,zwd_x2,zwd_y2);
- zoomWindowDragging = ZOOM_RESIZE_NW;
- double distance = distance_squared(mx1,my1, zwd_x1,zwd_y1);
- tryZoomCorner(mx1,my1,zwd_x1,zwd_y2,ZOOM_RESIZE_SW,distance);
- tryZoomCorner(mx1,my1,zwd_x2,zwd_y1,ZOOM_RESIZE_NE,distance);
- tryZoomCorner(mx1,my1,zwd_x2,zwd_y2,ZOOM_RESIZE_SE,distance);
- } // Warning! Falling case!
- case FL_DRAG:
- {
- switch(zoomWindowDragging)
- {
- case ZOOM_RESIZE_NW: zwd_x1 = get_event_x(); zwd_y1 = get_event_y(); break;
- case ZOOM_RESIZE_SW: zwd_x1 = get_event_x(); zwd_y2 = get_event_y(); break;
- case ZOOM_RESIZE_NE: zwd_x2 = get_event_x(); zwd_y1 = get_event_y(); break;
- case ZOOM_RESIZE_SE: zwd_x2 = get_event_x(); zwd_y2 = get_event_y(); break;
- case ZOOM_NO: case ZOOM_DRAG: info("Unusual event; hard to get here.\n"); break;
- }
- redraw_overlay();
- return 1;
- }
- case FL_RELEASE:
- switch(zoomWindowDragging)
- {
- case ZOOM_RESIZE_NW: zwd_x1 = get_event_x(); zwd_y1 = get_event_y(); break;
- case ZOOM_RESIZE_SW: zwd_x1 = get_event_x(); zwd_y2 = get_event_y(); break;
- case ZOOM_RESIZE_NE: zwd_x2 = get_event_x(); zwd_y1 = get_event_y(); break;
- case ZOOM_RESIZE_SE: zwd_x2 = get_event_x(); zwd_y2 = get_event_y(); break;
- case ZOOM_NO: case ZOOM_DRAG: info("Unusual event; hard to get here.\n"); break;
- }
- zoom_window->center_x = (zwd_x1+zwd_x2)/2;
- zoom_window->center_y = (zwd_y1+zwd_y2)/2;
- zoom_window->size((abs(zwd_x2-zwd_x1))*zoom_window->xscale, (abs(zwd_y2-zwd_y1))*zoom_window->yscale);
- showZoomWindow();
- zoomWindowDragging = ZOOM_NO;
- zoom_window->zoomMoved();
- return 1;
- }
- break;
- case 3:
- showZoomWindow();
- zoom_window->center_x = get_event_x();
- zoom_window->center_y = get_event_y();
- zoom_window->zoomMoved();
- return 1;
- default:
- return Fl_Overlay_Window::handle(event);
- }
- else if (ctrl(state)) // arb LC
- switch (button)
- {
- case 1:
- if (event == FL_PUSH)
- {
- lcx1 = lcx2 = get_event_x();
- lcy1 = lcy2 = get_event_y();
- line_cut_type = OTHERLINE;
- redraw_overlay();
- return 1;
- }
- else //if (event == FL_DRAG) // Button 1 + control + drag (arb line cut)
- {
- lcx2 = get_event_x();
- lcy2 = get_event_y();
- if (lcx2 < 0) lcx2 = 0;
- if (lcy2 < 0) lcy2 = 0;
- if (lcx2 > w-1) lcx2 = w-1;
- if (lcy2 > h-1) lcy2 = h-1;
- plotLineCut();
- redraw_overlay();
- return 1;
- }
- case 2:
- static int pointnum = 0;
- int nx, ny;
- nx = get_event_x();
- ny = get_event_y();
- if (nx < 0) nx = 0;
- if (ny < 0) ny = 0;
- if (nx > w-1) nx = w-1;
- if (ny > h-1) ny = h-1;
- d1 = sqrt(static_cast<double>((nx-lcx1)*(nx-lcx1)+(ny-lcy1)*(ny-lcy1)));
- d2 = sqrt(static_cast<double>((nx-lcx2)*(nx-lcx2)+(ny-lcy2)*(ny-lcy2)));
- if (event == FL_PUSH)
- {
- if (d1 < d2)
- { lcx1 = nx; lcy1 = ny; pointnum = 1;}
- else
- { lcx2 = nx; lcy2 = ny; pointnum = 2;}
- }
- else if (event == FL_DRAG)
- {
- if (pointnum == 1)
- { lcx1 = nx; lcy1 = ny; }
- else if (pointnum == 2)
- { lcx2 = nx; lcy2 = ny; }
- }
- plotLineCut();
- redraw_overlay();
- return 1;
- case 3:
- static int x0, y0, x1, y1; // Mouse coord at push and then at drag
- static int lcx1i, lcy1i, lcx2i, lcy2i; // Initial line endpoint on the push
- int dx, dy; // displacments
- if (event == FL_PUSH) // Pushing button 3 + control (arb line cut)
- {
- if(!(line_cut_limit & OTHERLINE))
- return 1;
- x0 = get_event_x();
- y0 = get_event_y();
- lcx1i = lcx1;
- lcx2i = lcx2;
- lcy1i = lcy1;
- lcy2i = lcy2;
- line_cut_type = OTHERLINE;
- return 1;
- }
- else if (event == FL_DRAG) // Dragging button 3 + control (arb line cut)
- {
- x1 = get_event_x();
- y1 = get_event_y();
- dx = x1-x0;
- dy = y1-y0;
- if (lcx1i+dx < 0) dx = -lcx1i;
- if (lcx1i+dx > w-1) dx = w-1-lcx1i;
- if (lcx2i+dx < 0) dx = -lcx2i;
- if (lcx2i+dx > w-1) dx = w-1-lcx2i;
- if (lcy1i+dy < 0) dy = -lcy1i;
- if (lcy1i+dy > h-1) dy = h-1-lcy1i;
- if (lcy2i+dy < 0) dy = -lcy2i;
- if (lcy2i+dy > h-1) dy = h-1-lcy2i;
- if (dx == 0 && dy == 0 && line_cut_type == OTHERLINE) return 1;
- lcx1 = lcx1i + dx; lcx2 = lcx2i + dx;
- lcy1 = lcy1i + dy; lcy2 = lcy2i + dy;
- line_cut_type = OTHERLINE;
- plotLineCut();
- redraw_overlay();
- return 1;
- }
- default:
- return Fl_Overlay_Window::handle(event);
- }
- // no modifiers, or multiple modifiers...
- if (button == 3 && controls_window != NULL && event == FL_PUSH)
- {
- if (controls_window->visible())
- controls_window->hide();
- else
- controls_window->show();
- return 1;
- }
- break;
- }
- return 0;
-}
-
-double ImageWindow::dataval(int x, int y)
-{
- if (x>=0 && x<w && y>=0 && y<h)
- return id.raw(x,y) - ((plane) ? id.quant_to_raw(planeval(y,x)) : 0); // watchout: planeval is swapped i,j!
- else
- return 0;
-}
-
-
-static void swap_crossection(const char *xsection_fn, const char *xsection_tmp_fn)
-{
-#ifdef WIN32
- if(unlink(xsection_fn) != 0)
- {
- info("Error deleting temporary file \"%s\": %s\n", xsection_fn,strerror(errno));
- // Sometimes, win32 seems to have trouble delete files: probably due to stupid locking...
- // In this case, we will try again with a new filename
-// int n=0;
-// while (true)
-// {
-// make_tmpfiles();
-// info("Trying new temporary filename %s", xsection_fn);
-// if (fopen(xsection_fn, "w") != NULL)
-// return;
-// sleep(5);
-// n++;
-// if (n==10)
-// {
-// info("giving up on xsection file!");
-// return;
-// }
- }
-#endif
- if(rename(xsection_tmp_fn, xsection_fn) != 0)
- {
- info("Error renaming temporary \"%s\" to \"%s\": %s\n",
- xsection_tmp_fn, xsection_fn, strerror(errno));
- return;
- }
-}
-
-
-
-void ImageWindow::plotLineCut(bool nothrottle)
-{
- static OptThrottle<ImageWindow> throttle(this,&ImageWindow::plotLineCut);
- if(!(nothrottle || throttle.throttle()))
- return;
-
- FILE *fp;
- if (line_cut_type == NOLINE)
- {
- if (gplinecut.isopen())
- {
- // set term x11 close doesn't work if the terminal type is not wxt.
- // Newer versions of gnuplot default to wxt.
- // Safer to kill gnuplot; of course, this "forgets" where the window was.
- gplinecut.close();
- }
- return;
- }
-
- if (!gplinecut.isopen())
- {
- gplinecut.open();
- if(!gplinecut.open())
- {
- nognuplot();
- return;
- }
- gplinecut.cmd("set style data %s\n", gp_with_string.c_str());
- }
-
- if ((fp = fopen(xsection_fn, "w")) == NULL)
- {
- error("Error opening file \"%s\": %s\n", xsection_tmp_fn, strerror(errno));
-
- return;
- }
- unlink("xsection.dat");
-#ifdef HAVE_SYMLINK
-// just so that we always have a file in the current dir where we can easily access the data
- if(symlink(xsection_fn, "xsection.dat") != 0)
- fprintf(stderr,"Error creating xsection.dat symlink: %s\n",strerror(errno));
-#endif
-
- // OK, let's give this a real cleanup.
- // We will plot the real, unquantized raw data, with as little permutation as possible.
-
- double xstep;
- double ystep;
- string axname;
- int x1,x2,y1,y2;
- double ax1, ax2;
-
- int npeaks = 0;
- int nvalleys = 0;
- double peak, valley;
-
- if (line_cut_type == HORZLINE)
- {
- int j = line_cut_yp;
- for (int i=0; i < w; i++)
- {
- fprintf(fp, "%e %e ", id.getX(i), dataval(i,j));
- if (pf->peaks != NULL && pfc.plot_peaks->value() && pf->peaks[j*w+i] == 1)
- {
- npeaks++;
- fprintf(fp, "%e ", dataval(i,j));
- }
- else fprintf(fp, "none ");
- if (pf->peaks != NULL && pfc.plot_valleys->value() && pf->peaks[j*w+i] == -1)
- {
- nvalleys++;
- fprintf(fp, "%e\n", dataval(i,j));
- }
- else fprintf(fp, "none\n");
- }
- x1 = 0; x2 = w;
- y1 = y2 = line_cut_yp;
- axname = id.xname;
- ax1 = id.getX(x1);
- ax2 = id.getX(x2);
- }
- else if (line_cut_type == VERTLINE)
- {
- int i = line_cut_xp;
- for (int j=0; j < h; j++)
- {
- fprintf(fp, "%e %e ", id.getY(j), dataval(i,j));
- if (pf->peaks != NULL && pfc.plot_peaks->value() && pf->peaks[j*w+i] == 1)
- {
- npeaks++;
- fprintf(fp, "%e ", dataval(i,j));
- }
- else fprintf(fp, "none ");
- if (pf->peaks != NULL && pfc.plot_valleys->value() && pf->peaks[j*w+i] == -1)
- {
- nvalleys++;
- fprintf(fp, "%e\n", dataval(i,j));
- }
- else fprintf(fp, "none\n");
- }
- x1 = x2 = line_cut_xp;
- y1 = h; y2 = 0;
- axname= id.yname;
- ax1 = id.getY(y1);
- ax2 = id.getY(y2);
- }
- else // otherwise, we'll use bilinear interpolation
- {
- int num_steps, n;
- x1 = lcx1; x2 = lcx2;
- y1 = lcy1; y2 = lcy2;
-
- if (x1 == x2 && y1 == y2) return;
-
- double i,j;
- double i1,j1;
- double i2,j2;
- double d1,d2,d;
- double x;
- bool step_x;
-
- if (abs(x2-x1) > abs(y2-y1))
- {
- step_x = true;
- num_steps = abs(x2-x1);
- xstep = 1.0*(x2-x1)/num_steps;
- ystep = 1.0*(y2-y1)/num_steps;
- }
- else
- {
- step_x = false;
- num_steps = abs(y2-y1);
- ystep = 1.0*(y2-y1)/num_steps;
- xstep = 1.0*(x2-x1)/num_steps;
- }
-
- i = x1; j = y1;
- for (n=0; n<num_steps; n++)
- {
- i1 = floor(i);
- i2 = ceil(i);
- j1 = floor(j);
- j2 = ceil(j);
- if (i1 == i2 && j1 == j2)
- d = dataval(i1,j1);
- else if (step_x)
- {
- d1 = dataval(i1, j1);
- d2 = dataval(i1, j2);
- d = d1 + (d2-d1)*(j-j1);
- }
- else
- {
- d1 = dataval(i1, j1);
- d2 = dataval(i2, j1);
- d = d1 + (d2-d1)*(i-i1);
- }
- if (lc_axis == XAXIS) x = id.getX(i);
- else if (lc_axis == YAXIS) x = id.getY(j);
- else
- {
- d1 = id.getX(i)-id.getX(x1);
- d2 = id.getY(j)-id.getY(y1);
- x = sqrt(d1*d1+d2*d2);
- }
- if (n == 0) ax1 = x;
- if (n == num_steps-1) ax2 = x;
- fprintf(fp, "%e %e\n", (double) x, d);
- i+=xstep; j+=ystep;
- }
- if (lc_axis == XAXIS) axname = id.xname;
- else if (lc_axis == YAXIS) axname = id.yname;
- else axname = "Distance (" + id.xname + ")";
- }
-
- fprintf(fp,
- "#X axis: %s\n"
- "#Line cut: %s %e to %e, %s %e to %e';\n"
- "#Row %d %d Column %d %d'\n",
- axname.c_str(),
- id.xname.c_str(), id.getX(x1), id.getX(x2),
- id.yname.c_str(), id.getY(y1), id.getY(y2),
- x1, x2, y1, y2);
-
-
- fclose(fp);
- //swap_crossection(xsection_fn, xsection_tmp_fn);
-
- //warn( "%e %e\n", ax1, ax2);
-
- if (line_cut_xauto)
- gplinecut.cmd("set xrange [%e:%e]\n",ax1, ax2);
-
- for(modules_t::iterator i = modules.begin(); i != modules.end(); i++)
- (*i)->linecut_callback(true);
-
- char buf[1024];
- gplinecut.cmd("set xlabel '%s';\n"
- "set ylabel '%s';\n"
- "set title \"%s \\n Line cut: %s %g to %g, %s %g to %g\";\n"
- "plot '%s' u %s w %s t 'x %d %d y %d %d'",
- axname.c_str(),
- id.zname.c_str(),
- Gnuplot_Interface::escape(filename).c_str(),
- id.xname.c_str(), id.getX(x1), id.getX(x2),
- id.yname.c_str(), id.getY(y1), id.getY(y2),
- xsection_fn, gp_using_string, gp_with_string.c_str(),
- x1, x2, y1, y2);
- if (npeaks != 0)
- gplinecut.cmd(", '' u 1:3 w p pt 5 t 'Peaks'");
- if (nvalleys != 0)
- gplinecut.cmd(", '' u 1:4 w p pt 5 t 'Valleys'");
-
-
- for(modules_t::iterator i = modules.begin(); i != modules.end(); i++)
- (*i)->linecut_callback(false);
-
- gplinecut.cmd("\n");
-}
-
-void ImageWindow::plotCmap()
-{
- static Throttle<ImageWindow> throttle(this,&ImageWindow::plotCmap);
- if(!throttle.throttle())
- return;
- int i,j;
- if (plot_cmap)
- {
- if (!gpcmap.isopen())
- {
- if(!gpcmap.open())
- {
- nognuplot();
- return;
- }
- }
- FILE *fp = fopen(cmap_fn, "w");
- if (fp == NULL)
- {
- error("Error opening file \"%s\": %s\n", cmap_fn, strerror(errno));
- return;
- }
- unlink("cmap.dat");
-#ifdef HAVE_SYMLINK
- symlink(cmap_fn, "cmap.dat");
-#endif
- for (i = 0; i < colormap_length; i++)
- {
- j = gammatable[i];
- fprintf(fp, "%d %d %d %d\n", i ,colormap[3*j], colormap[3*j+1], colormap[3*j+2]);
- }
- fclose(fp);
- gpcmap.cmd("set xrange [0:%d]; set yrange [0:255];"
- "set data style linespoints; set nokey;\n", colormap_length);
- gpcmap.cmd("plot '%s' u 1:2, '' u 1:3, '' u 1:4\n",cmap_fn);
- }
- else if (gpcmap.isopen())
- gpcmap.close();
-}
-
-void ImageWindow::plotHist()
-{
- static Throttle<ImageWindow> throttle(this,&ImageWindow::plotHist);
- if(!throttle.throttle())
- return;
- int i, min, max, inc, bintotal;
- if (plot_hist)
- {
- if(!gphist.isopen())
- {
- if(!gphist.open())
- {
- nognuplot();
- return;
- }
- }
- FILE *fp = fopen(hist_fn, "w");
- if (fp == NULL)
- {
- error("Error opening file \"%s\": %s\n", hist_fn, strerror(errno));
- return;
- }
- unlink("hist.dat");
-#ifdef HAVE_SYMLINK
- symlink(hist_fn, "hist.dat");
-#endif
- min = (hmin < datamin) ? hmin : datamin;
- max = (hmax > datamax) ? hmax : datamax;
- inc = (datamax - datamin)/300;
- if (inc < 1) inc = 1;
- bintotal=0;
- for (i = min ; i < max+inc && i < 65535 ; i++)
- {
- bintotal += datahist[i];
- if ( (i%inc) == 0)
- {
- fprintf(fp, "%d %e %d %d\n",i, id.quant_to_raw(i), bintotal,
- ((hmax-inc>=i && hmax-inc<=(i+inc-1)) ? 1 : 0) +
- ((hmin+inc>=i && hmin+inc<=(i+inc-1)) ? 1 : 0));
- bintotal = 0;
- }
- }
- fclose(fp);
- gphist.cmd("set x2range [%d:%d]; set xrange [%e:%e]; "
- "set x2tics; set yrange [1e-1:*];"
- "set style data boxes; set style fill solid;\n"
- "set nokey; set title '%s';"
- "set xlabel '%s'; set x2label 'Gray Value'\n",
- min-3*inc, max+3*inc, id.quant_to_raw(min-3*inc), id.quant_to_raw(max+3*inc), hist_fn, id.zname.c_str());
- gphist.cmd("plot '%s' u 1:4 ax x2y2 lt 2, '' u 1:3 ax x2y1 lt 1\n", hist_fn);
- }
- else if (gphist.isopen())
- {
- gphist.close();
- }
-}
-
-void ImageWindow::setMin(int m)
-{
- if (m > LMAX) m = LMAX;
- if (m < 0) m = 0;
- hmin = m;
- if (hmax < hmin)
- hmin = hmax;
-}
-
-void ImageWindow::setMax(int m)
-{
- if (m > LMAX) m = LMAX;
- if (m < 0) m = 0;
- hmax = m;
- if (hmin > hmax)
- hmax = hmin;
-}
-
-void ImageWindow::allocateImage()
-{
- int newsize=(dozoom(w,xzoom))*(dozoom(h,yzoom))*3;
- zap(image);
- image = new uchar [newsize];
-}
-
-
-void ImageWindow::setXZoom(int xz)
-{
- if (xz == 0 || xz == -1)
- {
- if (xzoom > xz) xzoom = -2;
- else xzoom = 1;
- }
- else xzoom = xz;
-
- allocateImage();
- size(dozoom(w,xzoom), dozoom(h,yzoom));
-}
-
-void ImageWindow::setYZoom(int yz)
-{
- if (yz == 0 || yz == -1)
- {
- if (yzoom > yz) yzoom = -2;
- else yzoom = 1;
- }
- else yzoom = yz;
-
- allocateImage();
- size(dozoom(w,xzoom), dozoom(h,yzoom));
-}
-
-void ImageWindow::setColormap(uchar *cmap, int l)
-{
- zap(colormap);
- zap(gammatable);
- colormap = new uchar[3*l];
- gammatable = new int[l];
- colormap_length = l;
-
-
- int min_index = cmap_min * l;
- int max_index = cmap_max * l;
- //warn( "min %f max %f\n", cmap_min, cmap_max);
- //warn( "min index %d max index %d\n", min_index, max_index);
-
- int i,j;
- double r,g,b,h,s,v;
- for (j=0; j < l; j++)
- {
- if (j < min_index) i = min_index;
- else if (j > max_index) i = max_index;
- else i = j;
-
- r = cmap[3*i];
- g = cmap[3*i+1];
- b = cmap[3*i+2];
-
- // This was kindof fun, but not all that useful...
- if(fabs(colormap_rotation_angle) > 1e-3)
- {
- Fl_Color_Chooser::rgb2hsv(r,g,b,h,s,v);
- h = (h+(colormap_rotation_angle+0.001)/360.0*6.0); // avoid singularity at angles of 60 degrees (problem on win32)
- h = h - 6.0*floor(h/6.0);
- Fl_Color_Chooser::hsv2rgb(h,s,v,r,g,b);
- }
-
- // Let's move all of this crap into the colormap loading routine,
- // where it really belongs. This is really, really overdue.
- if (negate) i = (colormap_length-1) - j;
- else i = j;
-
- colormap[3*i] = (int) (invert) ? 255-r : r;
- colormap[3*i+1] = (int) (invert) ? 255-g : g;
- colormap[3*i+2] = (int) (invert) ? 255-b : b;
- }
-
- setGamma(gam, gcenter);
- adjustHistogram();
- plotCmap();
- colormap_window->update();
-}
-
-void ImageWindow::setGamma(double g, double gc)
-{
- // Build a lookup table that maps our data
- gam = g;
- gcenter = gc;
-
- // problem near 1.0... in the end, for some reason this didn't
- // always work (was still crashing in win32), so i configured the
- // spyview gui so that you cannot set gc greater that 0.999
- //if (gc > 0.999) gc = 0.999;
-
- // function:
- // f3(x,a,b) = b - (x<=b) * b * ((b-x)/b)**(a) + (x>=b) * (1-b) * ((x-b)/(1-b))**(a)
-
- double x,val;
- for (int i = 0; i<colormap_length; i++)
- {
- x = 1.0*i/(colormap_length-1)+1e-9;
- val = gc + ((x<=gc) ? (-gc) * pow(((gc-x)/gc), g) : (1-gc) * pow((x-gc)/(1-gc), g));
- if (val > 1.0) val = 1.0;
- if (val < 0.0) val = 0.0;
- int index = round((val * (colormap_length-1)));
- if (index < 0) index = 0;
- if (index >= colormap_length) index = colormap_length-1;
- gammatable[i] = index;
- //if (i==0 || i == colormap_length-1)
- //info( "%03d %.3f %07.3f %03d ", i,val, val*(colormap_length-1), gammatable[i]);
- }
- //info( "\n");
-
- calculateHistogram();
- adjustHistogram();
- redraw();
- colormap_window->update();
-}
-
-// Calculate the data's histogram
-void ImageWindow::calculateHistogram()
-{
- int d;
-
- // Zero the histogram table
- for (int i = 0; i <= LMAX; i++)
- datahist[i] = 0;
-
- //warn( "data[2] = %d\n",data[2]);
- for (int i=0; i<w*h; i++)
- {
- d = data[i] - planeval(i/w,i%w);
- if (d > LMAX)
- d = LMAX;
- if (d < 0)
- d = 0;
- ++datahist[d];
- }
- for (datamin = 0; datamin <= LMAX; datamin++)
- if (datahist[datamin]>0) break;
- for (datamax = LMAX; datamax >= 0; datamax--)
- if (datahist[datamax]>0) break;
-}
-
-// Adjust the lookup table for the image histogram mapping
-void ImageWindow::adjustHistogram()
-{
- int i;
- double s; // Scale factor that takes us from hmin-hmax to 0...1
- double w; // Width of output
- for (i = 0; i < hmin; i++)
- imagehist[i] = 0;
- for (i = hmax+1; i <= LMAX; i++)
- imagehist[i] = LMAX;
- if (hmin == hmax)
- {
- if (hmin == 0) hmax++;
- else hmin--;
- external_update();
- }
- s = 1.0/(hmax-hmin);
- w = LMAX;;
-
- // I forgot that the gamma mapping is actually applied here on the 16 bit data!!!
-
- for (i = hmin; i <= hmax; i++)
- {
- double d = (i-hmin)*s + 1e-9; // Put ourselves in the range 0...1
- //d = pow(d,gam); // Apply our gamma correction
- d = gcenter + ((d<=gcenter) ?
- (-gcenter) * pow(((gcenter-d)/gcenter), gam) :
- (1-gcenter) * pow((d-gcenter)/(1-gcenter), gam));
- imagehist[i] = static_cast<int>(round(d*w));
- }
-
- // Drawing the window when it wasn't shown resulted in a flaky window manager placement problem!
- if (shown())
- redraw();
-}
-
-void ImageWindow::normalize()
-{
- int new_hmax, new_hmin;
- int nwhite, nblack;
- nblack = nwhite = 0;
- calculateHistogram();
- for ( new_hmin = 0; new_hmin <= LMAX; new_hmin++)
- {
- nblack += datahist[new_hmin];
- if (nblack > bpercent*w*h/100) break;
- }
- for ( new_hmax = LMAX; new_hmax >= 0; new_hmax--)
- {
- nwhite += datahist[new_hmax];
- if (nwhite > wpercent*w*h/100) break;
- }
- //setGamma(1.0);
- setMin(new_hmin);
- setMax(new_hmax);
- adjustHistogram();
-}
-
-void ImageWindow::normalizeOnZoom()
-{
- if(!zoom_window)
- return;
- int new_hmax, new_hmin;
- int nwhite, nblack;
- int x1, y1, x2, y2;
- zoom_window->getSourceArea(x1,y1,x2,y2);
- int s = (x2-x1)*(y2-y1);
- nblack = nwhite = 0;
- zoom_window->calculateHistogram();
- for ( new_hmin = 0; new_hmin <= LMAX; new_hmin++)
- {
- nblack += zoom_window->histogram[new_hmin];
- if (nblack > bpercent*s/100) break;
- }
- for ( new_hmax = LMAX; new_hmax >= 0; new_hmax--)
- {
- nwhite += zoom_window->histogram[new_hmax];
- if (nwhite > wpercent*s/100) break;
- }
- //setGamma(1.0);
- setMin(new_hmin);
- setMax(new_hmax);
- adjustHistogram();
-}
-
-void ImageWindow::runQueue()
-{
- bool swap_zoom = 0;
-
- operations_string = "(";
-
- if (process_queue != NULL)
- {
- for (int i=1; i<=process_queue->size(); i++)
- {
- Image_Operation *op = (Image_Operation *) process_queue->data(i);
-
- assert(op);
-
- if(!op->enabled)
- continue;
-
- if (i!=1)
- operations_string += ";" ;
- operations_string += op->name;
-
- for (int n=0; n<op->num_parameters; n++)
- {
- operations_string += "-";
- ostringstream os;
- os << op->parameters[n].value;
- operations_string += os.str();
- }
-
- if (op->name == "sub fitplane")
- id.fitplane(op->parameters[0].value, op->parameters[1].value, op->parameters[3].value);
- else if (op->name == "shift data")
- id.shift_data(op->parameters[0].value, op->parameters[1].value);
- else if (op->name == "remove lines")
- id.remove_lines(op->parameters[0].value, op->parameters[1].value);
- else if (op->name == "sub linecut")
- id.sub_linecut(op->parameters[1].value, op->parameters[0].value);
- else if (op->name == "outlier")
- id.outlier_line(op->parameters[1].value, op->parameters[0].value);
- else if (op->name == "scale axes")
- id.scale_axes(op->parameters[0].value, op->parameters[1].value);
- else if (op->name == "offset axes")
- id.offset_axes(op->parameters[0].value, op->parameters[1].value);
- else if (op->name == "sub plane")
- id.plane(op->parameters[0].value, op->parameters[1].value);
- else if (op->name == "sub lbl")
- id.lbl(op->parameters[0].value, op->parameters[1].value, 0, 1, op->parameters[2].value, op->parameters[3].value);
- else if (op->name == "sub cbc")
- id.cbc(op->parameters[0].value, op->parameters[1].value, 0, 1, op->parameters[2].value, op->parameters[3].value);
- else if (op->name == "power")
- id.gamma(op->parameters[0].value,op->parameters[1].value);
- else if (op->name == "scale data")
- id.scale(op->parameters[0].value);
- else if (op->name == "even odd")
- id.even_odd(op->parameters[0].value, op->parameters[1].value);
- else if (op->name == "rm switch")
- id.switch_finder(op->parameters[0].value, op->parameters[1].value, false);
- else if (op->name == "offset")
- id.offset(op->parameters[0].value, op->parameters[1].value);
- else if (op->name == "norm lbl")
- id.norm_lbl();
- //else if (op->name == "square")
- //id.square();
- else if (op->name == "norm cbc")
- id.norm_cbc();
- else if (op->name == "log")
- id.log10(op->parameters[0].value, op->parameters[1].value);
- else if (op->name == "interp")
- id.interpolate(op->parameters[0].value, op->parameters[1].value);
- else if (op->name == "scale img")
- id.scale_image(op->parameters[0].value, op->parameters[1].value);
- else if (op->name == "abs")
- id.magnitude();
- else if (op->name == "neg")
- id.neg();
- else if (op->name == "hist2d")
- id.hist2d(op->parameters[0].value, op->parameters[1].value, op->parameters[2].value);
- else if (op->name == "xderiv")
- id.xderv();
- else if (op->name == "yderiv")
- id.yderv();
- else if (op->name == "ederiv")
- id.ederv(op->parameters[0].value,op->parameters[1].value);
- else if (op->name == "dderiv")
- id.dderv(op->parameters[0].value);
- else if (op->name == "gradmag")
- id.grad_mag(op->parameters[0].value);
- else if (op->name == "lowpass")
- id.lowpass(op->parameters[0].value, op->parameters[1].value,(ImageData::lowpass_kernel_t)op->parameters[2].value);
- else if (op->name == "highpass")
- id.highpass(op->parameters[0].value, op->parameters[1].value, op->parameters[2].value / 100.0, (ImageData::lowpass_kernel_t)op->parameters[3].value);
- else if (op->name == "notch")
- id.notch(op->parameters[0].value, op->parameters[1].value, op->parameters[2].value, op->parameters[3].value);
- else if (op->name == "crop")
- id.crop(op->parameters[0].value, op->parameters[1].value, op->parameters[3].value, op->parameters[2].value);
- else if(op->name == "despeckle")
- id.despeckle(op->parameters[0].value, op->parameters[1].value);
- else if(op->name == "flip")
- {
- if(op->parameters[0].value)
- id.xflip();
- if(op->parameters[1].value)
- id.yflip();
- }
- else if (op->name == "autoflip")
- {
- if (id.xmin > id.xmax)
- id.xflip();
- if (id.ymin > id.ymax)
- id.yflip();
- }
- else if (op->name == "pixel avg")
- id.pixel_average(op->parameters[0].value, op->parameters[1].value);
- else if(op->name == "rotate cw")
- {
- id.rotate_cw();
- swap_zoom = !swap_zoom;
- }
- else if(op->name == "rotate ccw")
- {
- id.rotate_ccw();
- swap_zoom = !swap_zoom;
- }
- else if (op->name == "equalize")
- id.equalize();
- else
- warn("Warning: unknown operation \"%s\"\n",process_queue->text(i));
- }
- }
-
- //info( "op string %s\n", operations_string.c_str());
- operations_string += ")";
- if (process_queue->size() == 0)
- operations_string = "";
-
- //info( "op string2 %s\n", operations_string.c_str());
- //warn( "swap_zoom %d zoom_is_swapped %d\n", swap_zoom, zoom_is_swapped);
-
- //info("op string2 %s\n", operations_string.c_str());
- //info("zname %s\n", id.zname.c_str());
-
- // We used to do id.zname = id.zname + operation_string, but this
- // didn't work for the MTX data derived from meta.txt files? I
- // coudn't figure it out, so we'll just use old-fashioned c
- // functions...
-
- char tmp[4096];
- snprintf(tmp, sizeof(tmp), "%s %s", id.zname.c_str(), operations_string.c_str());
- // info("sum test: %s\n", tmp);
- id.zname = tmp;
- //info( "zname %s\n", id.zname.c_str());
-
- if (swap_zoom != swap_zoom_state)
- {
- int tmp = xzoom;
- xzoom = yzoom;
- yzoom = tmp;
- }
- swap_zoom_state = swap_zoom;
-
- // We also need to recalculate the peaks. If they're not displayed, it's no
- // biggy, since it doesn't take too much time.
-
- // For some reason, this is reproducibly generating a segfault on
- // win32? with some specific input files (actually, in particular,
- // a really big input file of 600x3600)
-
- // However, I think the problem is deeper than this, since we were also
- // getting random segfaults in win32 before peakfinder.
-
- // Running in gdb, it is segfaulting when calling iw->dataval
-
- // Actually, I just realized that pf calls iw->dataval, which is no
- // good since if this function is called from loadData, we may not
- // have updated the iw width and height properly yet.
-
- pf->calculate();
-}
-
-// a little procedure
-void ImageWindow::adjust_window_size()
-{
- if (window_size_action == KEEPSIZE)
- {
- xzoom = 0; yzoom = 0;
- size(((Fl_Widget *) this)->w(), ((Fl_Widget *)this)->h());
- }
- else if (window_size_action == KEEPZOOM)
- setXZoom(xzoom); // call this to allocate the image array and set the window size.
- else // if (window_size_action == RESETZOOM)
- {
- xzoom = 1; yzoom = 1;
- setXZoom(xzoom);
- }
-}
-
-int ImageWindow::loadData(const char *name)
-{
- // This is now completely rewritten!
- filename = name;
- if (id.load_file(name) == -1) return -1;
- if (id.width == 0 || id.height == 0) return -1;
- if ((id.width>id.height) && (id.width%id.height == 0) && square)
- id.pixel_average(id.width/id.height, 1);
- original_dataname = id.zname;
- runQueue();
- id.quantize();
- data = id.quant_data;
-
- w = id.width;
- h = id.height;
-
- zap(databuf);
- databuf = new int [w*h];
-
- adjust_window_size();
-
- calculateHistogram();
- adjustHistogram();
- plotLineCut();
- plotHist();
-
- // Set a nice basename
- char *p;
- strncpy(output_basename, filename.c_str(), 256);
- if ((p = strstr(output_basename, ".pgm")) == 0)
- if ((p = strstr(output_basename, ".Stm")) == 0)
- if ((p = strstr(output_basename, ".mtx")) == 0)
- if ((p = strstr(output_basename, ".dat")) == 0)
- p = strchr(output_basename, 0);
- *p = 0;
-
- external_update();
- return 0;
-}
-
-void ImageWindow::loadData(int *newdata, int neww, int newh, const char *name, bool reset_units)
-{
- filename = "imagedata";
- // Keep these around: if the image doesn't change size, we won't bother reallocating the arrays.
- int oldw = w;
- int oldh = h;
-
- w = neww;
- h = newh;
-
- id.load_int(newdata, neww, newh);
- if ((id.width>id.height) && (id.width%id.height == 0) && square)
- id.pixel_average(w/h, 1);
- runQueue();
- id.quantize();
- data = id.quant_data;
-
- w = neww = id.width;
- h = newh = id.height;
-
- if ( oldw*oldh != neww*newh )
- {
- zap(databuf);
- databuf = new int [w*h];
- }
-
- adjust_window_size();
-
- calculateHistogram();
- adjustHistogram();
- plotLineCut();
- plotHist();
- sprintf(output_basename, name);
- external_update();
-}
-
-void ImageWindow::reRunQueue()
-{
- int oldw = w;
- int oldh = h;
-
- // This will copy the original data back into the raw data matrix
- id.reset();
- if ((id.width>id.height) && (id.width%id.height == 0) && square)
- id.pixel_average(id.width/id.height, 1);
- runQueue();
- id.quantize();
- data = id.quant_data;
-
- w = id.width;
- h = id.height;
-
- // since we will likely often be loading a dataset of the same dimesions
- if ( oldw*oldh != w*h )
- {
- zap(databuf);
- databuf = new int [w*h];
- }
-
- setXZoom(xzoom); // this will allocate the image array
-
- calculateHistogram();
- adjustHistogram();
- plotLineCut();
- plotHist();
-}
-
-void ImageWindow::load_mtx_cut(int index, mtxcut_t type)
-{
- int oldw = w;
- int oldh = h;
-
- type = type %3;
-
- if (!id.data3d)
- {
- info( "3D data not loaded!\n");
- return;
- }
-
- id.load_mtx_cut(index, type);
- original_dataname = id.zname;
- runQueue();
- id.quantize();
- data = id.quant_data;
-
- w = id.width;
- h = id.height;
-
- // since we will likely often be loading a dataset of the same dimesions
- if ( oldw*oldh != w*h )
- {
- zap(databuf);
- databuf = new int [w*h];
- }
-
- setXZoom(xzoom); // this will allocate the image array
-
- calculateHistogram();
- adjustHistogram();
- plotLineCut();
- plotHist();
- external_update();
-}
-
-
-void ImageWindow::saveFile()
-{
- char buf[256];
- snprintf(buf, 256, "%s.ppm", output_basename);
- FILE *fp = fopen(buf, "wb");
- if(fp == NULL)
- {
- warn("Unable to open file \"%s\": %s\n",
- buf, strerror(errno));
- return;
- }
- fprintf(fp,
- "P6\n%d %d\n"
- "#hmin %d %e %s\n"
- "#hmax %d %e %s\n"
- "#hwidth %d %e %s\n"
- "#plane_a %e\n"
- "#plane_b %e\n"
- "#gamma %e\n"
- "#Image processing: %s\n"
- "255\n", w, h,
- hmin, id.quant_to_raw(hmin), id.zname.c_str(),
- hmax, id.quant_to_raw(hmax), id.zname.c_str(),
- hmax-hmin, id.quant_to_raw(hmax-hmin), id.zname.c_str(),
- plane_a, plane_b, gam, operations_string.c_str());
-
- unsigned char r,g,b;
- for (int i = 0; i<w*h; i++)
- {
- makergb(data[i],r,g,b,i/w,i%w);
- fwrite(&r, 1, 1, fp);
- fwrite(&g, 1, 1, fp);
- fwrite(&b, 1, 1, fp);
- }
-
- fclose(fp);
-}
-
-void ImageWindow::fit_plane() //calculates plane_a, plane_b, and plane_c
-{
- // Formula for the plane: Z = a*X + b*Y + c
- double a,b,c;
- // calculate the moments
- int N = w*h;
- double Zavg = 0;
- double Xavg = 0;
- double Yavg = 0;
- double sXZ = 0;
- double sYZ = 0;
- double sXX = 0;
- double sYY = 0;
-
- for (int x=0; x < w; x++)
- {
- for (int y=0; y < h; y++)
- {
- Zavg += (double) data[y*w + x];
- Xavg += (double) (x-w/2);
- Yavg += (double) (y-h/2);
- sXZ += (double) data[y*w + x] * (x-w/2);
- sYZ += (double) data[y*w + x] * (y-h/2);
- sXX += (double) (x-w/2)*(x-w/2);
- sYY += (double) (y-h/2)*(y-h/2);
- }
- }
-
- Xavg /= N;
- Yavg /= N;
- Zavg /= N;
-
- a = (sXZ - N*Xavg*Zavg)/(sXX - N*Xavg*Xavg);
- b = (sYZ - N*Yavg*Zavg)/(sYY - N*Yavg*Yavg);
- c = Zavg - a*Xavg - b*Yavg - LMAX/2;
-
- //warn( "c = %f\n",c);
- //warn( " a %10.2f\n b %10.2f\n c %10.2f\n", a, b, c);
-
- plane_a = b;
- plane_b = a;
-
- plane_c = c;
-};
-
-int ImageWindow::planeval(int x,int y)
-{
- if (plane)
- return (int) (plane_a * (x-w/2) + plane_b*(y-h/2));
- else
- return 0;
-}
-
-double Image_Operation::getParameter(const char *str)
-{
- for(parameters_t::iterator i = parameters.begin(); i != parameters.end(); i++)
- if(i->name == str)
- return i->value;
- warn("Warning: unknown parameter \"%s\" on image operation \"%s\"\n", str, name.c_str());
- warn("Available parameters:\n");
- for(parameters_t::iterator i = parameters.begin(); i != parameters.end(); i++)
- warn("\t%s\n",i->name.c_str());
- return 0.0;
-}
-
-void ImageWindow::dumpColormap()
-{
- string fn = output_basename;
- fn += ".colormap.dat";
- info("dumping colormap to %s\n", fn.c_str());
- FILE *fp = fopen(fn.c_str(), "w");
- fprintf(fp, "# hmin %d hmax %d gamma %e\n", hmin, hmax, gam);
-
- unsigned char r,g,b;
- int cmap_index;
- for (int i=hmin; i<hmax; i++)
- {
- cmap_index = imagehist[i]*(colormap_length-1)/LMAX;
- makergb(i, r, g, b);
- fprintf(fp, "%d %d %e %d %d %d %d\n",
- cmap_index, i, id.quant_to_raw(i),
- imagehist[i],
- r, g, b);
- }
- fclose(fp);
-}
-
-
-
-void ImageWindow::exportLinecut()
-{
- // Ok, this is a real hack, but it's easy...
- char tmp[1024];
- char label[1024];
- char fn[1024];
-
- //sprintf is just so damn more convenient than c++ strings
- if (line_cut_type == HORZLINE)
- snprintf(label, 1024, "l.%d", line_cut_yp);
- else if (line_cut_type == VERTLINE)
- snprintf(label, 1024, "c.%d", line_cut_xp);
- else
- sprintf(label, "other");
- snprintf(fn, 1024, "%s.%s.linecut.dat", output_basename, label);
-
- info("exporting linecut to file %s\n", fn);
-
- strncpy(tmp, xsection_fn, 1024);
- strncpy(xsection_fn, fn, 1024);
- plotLineCut();
- strncpy(xsection_fn, tmp, 1024);
-}
-
-void ImageWindow::exportGnuplot()
-{
- FILE *fp;
- //char buf1[256],buf2[256];
- int i,j;
-
- string base = output_basename;
- // Output the data in pm3d format
-
- //snprintf(buf1, 256, "%s.pm3d", output_basename);
- if ((fp = fopenwarn((base+".gp").c_str(), "w")) == NULL)
- return;
-
- for (i=0; i<w; i++)
- {
- for (j=0; j<h; j++)
- fprintf(fp, "%e %e %e\n", id.getX(i), id.getY(j), dataval(i,j));
- fprintf(fp, "#\n\n");
- }
- fclose(fp);
-
- // Now output a gnuplot script file to plot the data with the right colormap range.
-
- //snprintf(buf2, 256, "%s.gnu", output_basename);
- if ((fp = fopenwarn((base+".gnu").c_str(), "w")) == NULL)
- return;
-
- fprintf(fp, "set palette defined (");
- for (int i=0; i<colormap_length-1; i+=1)
- fprintf(fp, "%f %f %f %f,", 1.0*i/(colormap_length-1), 1.0*colormap[3*i]/255.0, 1.0*colormap[3*i+1]/255.0, 1.0*colormap[3*i+2]/255.0);
- fprintf(fp, "%f %f %f %f)\n", 1.0, 1.0*colormap[3*colormap_length-3]/255.0, 1.0*colormap[3*colormap_length-2]/255.0, 1.0*colormap[3*colormap_length-1]/255.0);
-
- fprintf(fp,
- "set view map; set pm3d; set st d pm3d;\n"
- "unset grid; set pm3d corners2color c1;\n"
- "set cbrange [%e:%e];\n"
- "set xrange [%e:%e]; set yrange [%e:%e]\n"
- "set xlabel '%s'; set ylabel '%s'; set cblabel '%s'\n"
- "splot \"%s\"\n",
- id.quant_to_raw(hmin), id.quant_to_raw(hmax),
- id.getX(0), id.getX(w),
- id.getY(h), id.getY(0),
- id.xname.c_str(), id.yname.c_str(), id.zname.c_str(),
- (base+".pm3d").c_str());
- fclose(fp);
-
-}
-
-void ImageWindow::exportMAT()
-{
- string name = output_basename;
- name += ".export.dat";
- FILE *fp;
- if ((fp = fopenwarn(name.c_str(), "w")) == NULL)
- return;
-
- for (int i=0; i<w; i++)
- {
- for (int j=0; j<h; j++)
- fprintf(fp, "%e ", dataval(i,j));
- fprintf(fp, "\n");
- }
- fclose(fp);
-}
-
-void ImageWindow::setupPS()
-{
- imageprinter->updateSettings(&ipc);
- if (ipc.win->shown())
- ipc.win->hide();
- else
- ipc.win->show();
-}
-
-char *ImageWindow::exportPS()
-{
- //const char *extension = ipc.format->value() == Image_Printer::FORMAT_PDF ? "pdf" : "ps";
- struct stat s;
- FILE *fp;
- static char buf[1024];
- static char buf2[1024];
-
- if (ipc.auto_inc->value())
- {
- int number = 0;
- snprintf(buf, sizeof(buf), "%s.%d", output_basename, number++);
- while(stat(buf,&s) == 0) // Stat will return 0 if the file exists
- {
- snprintf(buf, sizeof(buf), "%s.%d", output_basename, number++);
- if(number > 1000)
- {
- warn("Unable to come up with a suitable file name\n");
- return NULL;
- }
- }
- if(errno != ENOENT)
- {
- warn("Problem stating output file name: %s\n",strerror(errno));
- return NULL;
- }
- ipc.incnum->value(number);
- }
- else if (ipc.do_number->value())
- {
- int n = ipc.incnum->value();
- snprintf(buf, sizeof(buf), "%s.%d", output_basename, n);
- if (ipc.increment->value())
- ipc.incnum->value(n+1);
- }
- else
- snprintf(buf, sizeof(buf), "%s", output_basename);
-
- snprintf(buf2, sizeof(buf2), "%s.ps", buf);
- info("outputting postscript file %s\n", buf2);
- fp = fopen(buf2, "w");
- imageprinter->print(fp);
- fflush(fp);
- fclose(fp);
-
- // This will call ghostscript to do the extra conversions
- imageprinter->do_extra_conversions(buf);
- return buf2;
-}
-
-void ImageWindow::exportMTX(bool save, bool zoom)
-{
- FILE *fp;
-
- string name = output_basename;
-
- if (save)
- name += ".mtx";
- else if (zoom)
- name += ".zoom.mtx";
- else
- name += ".export.mtx";
-
- info("save %d name %s\n", save, name.c_str());
-
- if ((fp = fopen(name.c_str(), "r")) != NULL && (save || zoom))
- {
- if (fl_ask("Overwrite file %s", name.c_str()) == 1)
- fclose(fp);
- else
- {
- fclose(fp);
- return;
- }
- }
-
- if ((fp = fopenwarn(name.c_str(), "wb")) == NULL)
- return;
-
- int x1, y1, x2, y2;
- double xmin, ymin, xmax, ymax;
-
- if (zoom)
- {
- zoom_window->getSourceArea(x1,y1,x2,y2);
- x2--;
- y2--;
- }
- else
- {
- x1 = 0; x2 = id.width-1;
- y1 = 0; y2 = id.height-1;
- }
-
- xmin = id.getX(x1);
- xmax = id.getX(x2);
- ymin = id.getY(y1);
- ymax = id.getY(y2);
-
- int wid = x2-x1+1;
- int hgt = y2-y1+1;
-
- string zname = search_replace(id.zname, ",", ";");
- string xname = search_replace(id.xname, ",", ";");
- string yname = search_replace(id.yname, ",", ";");
-
- fprintf(fp, "Units, %s,"
- "%s, %e, %e,"
- "%s, %e, %e,"
- "Nothing, 0, 1\n",
- zname.c_str(),
- xname.c_str(), xmin, xmax,
- yname.c_str(), ymin, ymax);
- fprintf(fp, "%d %d 1 8\n", wid, hgt);
-
- //info("x1 %d x2 %d width %d\n", x1, x2, wid);
- //info("y1 %d y2 %d height %d\n", y1, yq2, hgt);
-
- for (int i=x1; i<=x2; i++)
- for (int j=y1; j<=y2; j++)
- fwrite(&id.raw(i,j), sizeof(double), 1, fp);
-
- fclose(fp);
-}
-
-void ImageWindow::exportPGM()
-{
- FILE *fp;
- char buf[256];
- int i,j;
-
- snprintf(buf, 256, "%s.export.pgm", output_basename);
-
- if ((fp = fopenwarn(buf, "wb")) == NULL)
- return;
-
- fprintf(fp, "P5\n%d %d\n", w, h);
- fprintf(fp, "#zmin %e\n"
- "#zmax %e\n"
- "#xmin %e\n"
- "#xmax %e\n"
- "#ymin %e\n"
- "#ymax %e\n"
- "#xunit %s\n"
- "#yunit %s\n"
- "#zunig %s\n"
- "#Image Processing: %s\n"
- "65535\n", id.qmin, id.qmax, id.xmin, id.xmax, id.ymin, id.ymax,
- id.xname.c_str(), id.yname.c_str(), id.zname.c_str(),
- operations_string.c_str());
-
- char c;
- int val;
- for (j=0; j<h; j++)
- for (i=0; i<w; i++)
- {
- val = data[j*w+i]-planeval(j,i);
- c = val/256;
- fwrite(&c,1,1,fp);
- c = val%256;
- fwrite(&c,1,1,fp);
- }
- fclose(fp);
-}
-
-void ImageWindow::exportMatlab()
-{
- FILE *fp;
- char buf[256];
-
- string base = output_basename;
-
- // Matlab M-file names can contain only alphanumeric characters!
- // http://authors.ck12.org/wiki/index.php/Introduction_to_Programming_with_M-file_Scripts
- // How annoying...
-
- for (int pos = 0; pos < base.size(); pos++)
- if (!isalnum(base[pos]) &&
- base[pos] != '\\' && // we should not replace directory separators...
- base[pos] != ':' &&
- base[pos] != '/')
- base[pos] = '_';
-
- info("Outputting file %s\n", (base+".m").c_str());
-
- if ((fp = fopenwarn((base+".m").c_str(), "w")) == NULL)
- return;
-
- // Output the current colormap
- fprintf(fp, "cmap = [ ");
- for (int i=0; i<colormap_length; i+=1)
- {
- int tmp = gammatable[i];
- fprintf(fp, "%f %f %f ",
- 1.0*colormap[3*tmp]/255.0,
- 1.0*colormap[3*tmp+1]/255.0,
- 1.0*colormap[3*tmp+2]/255.0);
- if (i != colormap_length-1)
- fprintf(fp, ";\n");
- }
- fprintf(fp, "];\n");
-
- fprintf(fp, "data = [ ");
- for (int j=0; j<h; j++)
- {
- for (int i=0; i<w; i++)
- fprintf(fp, "%e ", dataval(i,j));
- if (j != h-1)
- fprintf(fp, ";\n");
- }
- fprintf(fp, "];\n");
-
- double min = id.quant_to_raw(hmin);
- double max = id.quant_to_raw(hmax);
-
-
- fprintf(fp,
- "figure(1)\n"
- "colormap(cmap)\n"
- "imagesc(data)\n"
- "caxis([%e %e])\n"
- "figure(2)\n"
- "colormap(cmap)\n"
- "surf(data)\n"
- "caxis([%e %e])\n"
- "shading flat\n"
- "lighting gouraud\n"
- "camlight\n",
- min, max, min, max);
- fclose(fp);
-}
-
-// Zoom window support
-
-void ZoomWindow::realloc_image()
-{
- if((image == NULL) || (image_size != static_cast<size_t>(w()*h())))
- {
- if(image != NULL)
- free(image);
- image_size = w()*h();
- image = (unsigned char *)malloc(sizeof(unsigned char) * image_size * 3);
- }
-}
-ZoomWindow::ZoomWindow(int w, int h, const char *title) : Fl_Double_Window(w,h,title), image(NULL), img(NULL), xscale(2),yscale(2), center_x(0), center_y(0)
-{
- autonormalize = false;
-}
-
-void ZoomWindow::calculateHistogram()
-{
- int x1,y1,x2,y2;
- getSourceArea(x1,y1,x2,y2);
- for(unsigned i = 0; i < hist_len; i++)
- histogram[i] = 0;
- for(int x = x1; x < x2; x++)
- for(int y = y1; y < y2; y++)
- {
- int d = img->id.quant(x,y);
- if(d >= 0 && d < static_cast<int>(hist_len))
- histogram[d]++;
- }
-}
-
-void ZoomWindow::draw()
-{
- if(!img)
- return;
- realloc_image();
- int src_x1, src_y1, src_x2, src_y2;
- getSourceArea(src_x1, src_y1, src_x2, src_y2);
- int my = h();
- int mx = w();
- unsigned char *p = image;
- for(int y = 0; y < my; y++)
- for(int x = 0; x < mx; x++)
- {
- int sx = src_x1 + x/xscale;
- int sy = src_y1 + y/yscale;
- if(sx >= src_x2 || sy >= src_y2)
- {
- *p++=0;
- *p++=0;
- *p++=0;
- continue;
- }
- else
- {
- unsigned char r,g,b;
- img->getrgb(sy,sx,r,g,b);
- *p++=r;
- *p++=g;
- *p++=b;
- }
- }
- fl_draw_image(image,0,0,mx,my,3,0);
- // This is sometimes getting out of sync: put in the redraw...
- snprintf(window_label, 256, "Zoom of %s: (%dx,%dx)", img->filename.c_str(), xscale, yscale);
- label(window_label);
-}
-
-int ZoomWindow::handle(int event)
-{
- switch (event)
- {
- case FL_PUSH:
- push_mouse_x = Fl::event_x();
- push_mouse_y = Fl::event_y();
- push_center_x = center_x;
- push_center_y = center_y;
- break;
- case FL_DRAG:
- case FL_RELEASE:
- center_x = push_center_x - (Fl::event_x()-push_mouse_x)/xscale;
- center_y = push_center_y - (Fl::event_y()-push_mouse_y)/yscale;
- zoomMoved();
- break;
- case FL_HIDE:
- if(img)
- img->redraw_overlay();
- break;
- case FL_SHOW:
- if(img)
- img->redraw_overlay();
- break;
- case FL_KEYDOWN:
- char c = Fl::event_key();
- //info("Key %c\n",c);
- switch(c)
- {
- case '=':
- case '+':
- case '.':
- case '>':
- {
- int oldw, oldh;
- oldw = w()/xscale;
- oldh = h()/yscale;
- if (Fl::event_state() & FL_SHIFT)
- xscale++;
- else if (Fl::event_state() & FL_CTRL)
- yscale++;
- else
- {xscale++; yscale++;}
- size(oldw*xscale, oldh*yscale);
- if(img)
- img->redraw_overlay();
- redraw();
- return 1;
- }
- case '-':
- case ',':
- case '<':
- {
- int oldw, oldh;
- oldw = w()/xscale;
- oldh = h()/yscale;
- if (Fl::event_state() & FL_SHIFT)
- xscale--;
- else if (Fl::event_state() & FL_CTRL)
- yscale--;
- else
- {xscale--; yscale--;}
- if(xscale < 1)
- xscale = 1;
- if(yscale < 1)
- yscale = 1;
- size(oldw*xscale, oldh*yscale);
- if(img)
- img->redraw_overlay();
- redraw();
- return 1;
- }
- case 'z':
- if (!(Fl::event_state() & FL_CTRL))
- {
- hide();
- return 1;
- }
- }
- break;
- }
- return 0;
-}
-
-void ZoomWindow::resize(int x, int y, int w, int h)
-{
- snprintf(window_label, 256, "Zoom of %s: (%dx,%dx)", img->filename.c_str(), xscale, yscale);
- label(window_label);
- Fl_Double_Window::resize(x,y,w,h);
- img->external_update();
- zoomMoved();
- size_range(1,1);
-}
-
-void ZoomWindow::getSourceArea(int &x1, int &y1, int &x2, int &y2)
-{
- int dx = w()/xscale;
- int dy = h()/yscale;
-
- //warn( "xscale %d yscale %d\n", xscale, yscale);
-
- x1 = center_x - dx/2; // Find the ideal top-left
- y1 = center_y - dy/2;
-
- if(x1 < 0) x1 = 0; // Clip to the window
- if(y1 < 0) y1 = 0;
-
- x2 = x1 + dx; // Find the bottom right, including top-left clipping
- y2 = y1 + dy;
-
- if(x2 >= img->w) // Clip the bottom right to the window
- {
- x2 = img->w;
- if(x2-dx < 0) // Be careful if the source window isn't as wide as dx!
- x1 = 0;
- else
- x1 = x2-dx;
- }
- if(y2 >= img->h)
- {
- y2 = img->h;
- if(y2-dy < 0)
- y1 = 0;
- else
- y1 = y2-dy;
- }
-}
-
-void ZoomWindow::zoomMoved()
-{
- if(autonormalize && img)
- img->normalizeOnZoom();
- redraw();
- if(img)
- img->redraw_overlay();
-}
-
-ColormapWindow::ColormapWindow(int wp, int hp, const char *title) : Fl_Window(wp,hp,title), image(NULL)
-{
- // You shouldn't call functions from a constructor!
- //resize(x(),y(),w(),h());
- //size_range(1,1,0,0);
-}
-
-void ColormapWindow::resize(int x, int y, int w, int h)
-{
- Fl_Window::resize(x,y,w,h);
-
- if(image)
- delete[] image;
- image = NULL;
-
- if(h < w)
- {
- vertical = false;
- xmult = w/wid;
- //warn( "xmult %d\n", xmult);
- if(xmult == 0)
- return;
- ih = h;
- iw = w - (w % wid);
- }
- else
- {
- vertical = true;
- xmult = h/wid;
- //warn( "xmult %d\n", xmult);
- if(xmult == 0)
- return;
- ih = w;
- iw = h - (h % wid);
- }
- if(iw <= 0 || ih <= 0)
- return;
- image = new uchar[3*iw*ih];
- assert(image);
- update();
- redraw();
-}
-
-ColormapWindow::~ColormapWindow()
-{
- delete[] image;
-}
-
-void ColormapWindow::update()
-{
- if(!img || !image)
- return;
-
- double foo = 1.0 * (img->colormap_length-1)/(iw-1);
- int tmp, tmp2;
- int i;
- for (int y = 0; y < ih; y++)
- for (int x = 0; x < iw; x++)
- {
- tmp2 = (int) round(x*foo);
- tmp = img->gammatable[tmp2];
- if (vertical)
- i = iw-1-x;
- else
- i = x;
-
-// if (x == iw/2 && y == 0)
-// {
-// warn( "iw %d cmapl %d foo %g x %d tmp2 %d tmp %d\n",
-// iw, img->colormap_length, foo, x, tmp2, tmp);
-// }
- if(tmp > img->colormap_length-1)
- tmp = img->colormap_length-1;
- if(tmp < 0)
- tmp = 0;
- image[3*(i+y*iw)] = img->colormap[3*tmp];
- image[3*(i+y*iw)+1] = img->colormap[3*tmp+1];
- image[3*(i+y*iw)+2] = img->colormap[3*tmp+2];
- }
- redraw();
-}
-void ColormapWindow::draw()
-{
- if(image)
- if(vertical)
- fl_draw_image(image,0,(h()-iw)/2,ih,iw,iw*3,3);
- else
- fl_draw_image(image,(w()-iw)/2,0,iw,ih,3,0);
-}
-
-void ColormapWindow::saveFile(const char *name)
-{
- static const int height=32;
- warn( "saving colormap to %s", name);
- FILE *fp = fopen(name, "wb");
- if(fp == NULL)
- {
- warn("Unable to open file \"%s\": %s\n",
- name, strerror(errno));
- return;
- }
- fprintf(fp,
- "P6\n%d %d\n"
- "#zmin %f\n"
- "#zmax %f\n"
- "255\n", wid, height,
- img->zunit(img->hmin),
- img->zunit(img->hmax));
-
- for(int j = 0; j < height; j++)
- for (int i = 0; i< wid; i++)
- {
- int tmp = img->gammatable[i];
- fwrite(&(img->colormap[3*tmp]),sizeof(char),3,fp);
- }
-
- fclose(fp);
-}
-
+++ /dev/null
-#ifndef __bisector_h__
-#define __bisector_h__
-#include <assert.h>
-#include <math.h>
-
-class bisector
-{
-public:
- static const double factor=0.5;
- double x1, x2, fx1, fx2;
- double acc;
- int iter;
- bisector(double x1p, double fx1p, double x2p, double fx2p, double acct=1e-6) : x1(x1p), x2(x2p), fx1(fx1p), fx2(fx2p), acc(acct*fabs(x1p-x2p))
- {
- iter =0;
- };
-
- bool x(double &xp) // Return next x coordinate to evaluate. Return true if we've converged.
- {
- if(fx1*fx2 > 0)
- {
- if(fabs(fx1) < fabs(fx2))
- {
- xp = x1;
- return true;
- }
- else
- {
- xp = x2;
- return true;
- }
- }
- if(fabs(x2-x1) < acc)
- {
- xp = (x1+x2)/2.0;
- return true;
- }
- if(iter++ > 100)
- {
- fprintf(stderr,"x1=%g, x2=%g, acc=%g; bailing\n",
- x1,x2,acc);
- xp=(x1+x2)/2.0;
- return true;
- }
- xp = x1+factor*(x2-x1);
- return false;
- };
-
- inline void o(double x, double fx) // Add an observation.
- {
- if(fx*fx1 <= 0.0)
- {
- x2 = x;
- fx2 = fx;
- }
- else
- {
- assert(fx*fx2 <= 0.0);
- x1 = x;
- fx1 = fx;
- }
- };
-};
-
-/* Newton step until we bracket, then bisect */
-class magic_bisector
-{
-public:
- static const double factor=0.5;
- bool bisection;
- double nx, nfx;
- double x1, fx1, x2, fx2, mest;
- double acc;
- int iter;
- magic_bisector(double x_start, double m_est_p, double acc_p=1e-6) : nx(x_start), mest(m_est_p), acc(acc_p)
- {
- x1 = NAN;
- x2 = NAN;
- nfx = 10*acc_p;
- bisection = false;
- iter = 0;
- };
- bool x(double &xp)
- {
- xp = nx;
- return (fabs(nfx) < acc) || (iter++ > 32);
- }
-
- void o(double xp, double fxp)
- {
- nfx = fxp;
- if(bisection)
- {
- if(fxp < 0)
- {
- x1 = xp;
- fx1 = fxp;
- }
- else
- {
- x2 = xp;
- fx2 = fxp;
- }
- }
- else
- {
- if(fxp < 0 && (isnan(x1) || (fxp > fx1)))
- {
- x1 = xp;
- fx1 = fxp;
- }
- else if(fxp > 0 && (isnan(x2) || (fxp < fx2)))
- {
- x2 = xp;
- fx2 = fxp;
- }
- }
- bisection = !(isnan(x1) || isnan(x2));
- if(bisection)
- {
- // printf("Bisection step: [%g,%g] {%g,%g}\n", x1,x2,fx1,fx2);
- nx = (x1+x2)/2.0;
- }
- else
- {
- nx -= nfx/mest;
- // printf("Newton step to %g (%g/%g)\n",nx,nfx,mest);
- }
- }
-};
-#endif
+++ /dev/null
-#include "spypal_import.H"
-#include <stdio.h>
-#include <math.h>
-
-double sqr(double x) { return x*x; };
-static int worst_point;
-static double worst_error;
-double spypal_worst_error() { return worst_error; };
-static double fidelity(unsigned char *c1, unsigned char *c2, unsigned l)
-{
- double e = 0;
- worst_error = 0;
- worst_point = -1;
- for(unsigned i = 0; i < l; i++)
- {
- double se = sqr(c2[3*i]-c1[3*i])+sqr(c2[3*i+1]-c1[3*i+1])+sqr(c2[3*i+2]-c1[3*i+2]);
- if(se > worst_error)
- {
- worst_point = i;
- worst_error = se;
- }
- e += se;
- }
- return e;
-}
-
-static void color_waypoints(std::vector<SpypalWaypoint> &wps, unsigned char *c1, unsigned l)
-{
- for(unsigned i = 0 ; i < wps.size(); i++)
- {
- double r,g,b;
- r = c1[3*wps[i].ind+0]/255.0;
- g = c1[3*wps[i].ind+1]/255.0;
- b = c1[3*wps[i].ind+2]/255.0;
- // printf("%d %g %g %g %d %d %d\n",wps[i].ind,r,g,b,c1[3*wps[i].ind+0],c1[3*wps[i].ind+1],c1[3*wps[i].ind+2]);
- cc_sRGB.set(wps[i].c,r,g,b);
- }
-}
-static double try_colormap(std::vector<SpypalWaypoint> &wps, const ccspace *cs, unsigned char *c1, unsigned l)
-{
- sort(wps.begin(),wps.end());
-
- generate_go(wps,OPTS_STRAIGHT,true,cs,cs,l);
- if(cmap.size() != l)
- return NAN;
- dump_colormap_memory();
- return fidelity(c1,spypal_colormap,l);
-}
-
-// Try to adjust the waypoints by starting from three waypoints, then building
-// up, adding the additional waypoint at the point where the error is largest
-// each time.
-double spypal_bisect_anneal(SpypalWaypoints_t &wps_out, const ccspace *cs, unsigned char *c1, unsigned l)
-{
- size_t size = wps_out.size();
- assert(size >= 2);
-
- if(size == 2)
- return spypal_anneal(wps_out,cs,c1,l);
-
- double err;
- SpypalWaypoints_t wps(3);
-
- // Initialize the guess.
- for(unsigned i = 0; i < wps.size(); i++)
- {
- wps[i].loc = ((double)i)/(wps.size()-1);
- wps[i].ind = wps[i].loc * (l-1);
- wps[i].locked = true;
- }
- color_waypoints(wps,c1,l);
- err = spypal_anneal(wps,cs,c1,l,false);
-
- // Add a waypoint at the worst point and anneal until we reach the right size
- while(wps.size() < size)
- {
- SpypalWaypoint w;
- if(worst_point >= 0)
- w.ind = worst_point;
- else
- w.ind = l/2;
- w.loc = ((double)w.ind) / (l-1);
- w.locked = true;
- wps.push_back(w);
- color_waypoints(wps,c1,l);
- err = spypal_anneal(wps,cs,c1,l,false);
- }
- wps_out = wps;
- return try_colormap(wps,cs,c1,l);
-}
-
-// Try to adjust the waypoints in waypoints to maximize the fidelity.
-// Return the fidelity.
-double spypal_anneal(SpypalWaypoints_t &wps, const ccspace *cs, unsigned char *c1, unsigned l, bool init)
-{
- double best;
- SpypalWaypoints_t wps_best;
-
- if(init)
- {
- // Initialize the guess.
- for(unsigned i = 0; i < wps.size(); i++)
- {
- wps[i].loc = ((double)i)/(wps.size()-1);
- wps[i].ind = wps[i].loc * (l-1);
- wps[i].locked = true;
- }
- color_waypoints(wps,c1,l);
- }
-
- // Get an initial fidelity
- best = try_colormap(wps,cs,c1,l);
- if(isnan(best))
- return best;
- wps_best = wps;
-
- // Anneal; try sliding each waypoint left then right.
- bool improved;
- int iter = 1000;
- int stepsize = l/(2.0*wps.size());
- if(stepsize < 1)
- stepsize = 1;
- do
- {
- improved = false;
- for(unsigned i = 1; i < wps.size()-1; i++)
- {
- if(wps[i].ind > stepsize)
- {
- SpypalWaypoints_t wpst = wps;
- wpst[i].ind -= stepsize;
- wpst[i].loc = wpst[i].ind / (l - 1.0);
- color_waypoints(wpst,c1,l);
- double f = try_colormap(wpst,cs,c1,l);
- if(f < best)
- {
- best = f;
- wps_best = wpst;
- improved = true;
- wps = wpst;
- break;
- }
- }
- if(((int)wps[i].ind) < (l-stepsize))
- {
- SpypalWaypoints_t wpst = wps;
- wpst[i].ind += stepsize;
- wpst[i].loc = wpst[i].ind / (l - 1.0);
- color_waypoints(wpst,c1,l);
- double f = try_colormap(wpst,cs,c1,l);
- if(f < best)
- {
- best = f;
- wps_best = wpst;
- improved = true;
- wps = wpst;
- break;
- }
- }
- }
- if(best == 0.0)
- break;
- if(!improved)
- {
- if(stepsize == 1)
- break;
- else
- stepsize /= 2.0;
- }
- // printf("%5d %3d %g\n",iter,stepsize,best);
- }
- while(iter--);
- wps = wps_best;
- // One extra calc cycle to get worst_error right.
- return best;
-}
+++ /dev/null
-#include <assert.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include "../config.h"
-#include <FLTK_Serialization.H>
-#include "spyview.H"
-#include "ImageWindow.H"
-#include "spyview_ui.h"
-#include "ImageWindow_LineDraw.H"
-#include "ImageWindow_Fitting.H"
-#include "ThresholdDisplay.H"
-#include "message.h"
-#include <Fl/fl_ask.H>
-#include <string.h>
-#include <Fl/Fl_File_Chooser.H>
-#include <Fl/filename.H>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <map>
-#include "Fiddle.H"
-#include "mypam.h"
-#include "misc.h"
-#include "spypal.h"
-#include "spypal_interface.H"
-#include "spypal_import.H"
-#include <libgen.h>
-
-using namespace std;
-
-//How's this for lazy...?
-char **arg_values;
-int arg_count;
-int opt_index;
-
-vector<string> filenames;
-vector<string> cmapfiles;
-string default_file;
-string current_filename;
-
-
-bool no_files_given;
-
-// Keep track of what directory we started in
-string original_dir("");
-
-// On unix, this will be $HOME/.spyview
-// On win32, default will be $APPDATA/spyview
-// If SPYVIEW_PREF_DIR exist, it will use $SPYVIEW_PREF_DIR/spyview
-string userdir("");
-
-// On unix, default to /usr/share
-// On windows, if called using file associations, we can find the full
-// path to the spyview.exe. If called from the command line, the user
-// should set the SPYVIEW_DIR environment variable.
-string sharedir("");
-
-int check_loaded()
-{
- return filenames.size();
-}
-
-void clear_files()
-{
- filech->clear();
- filenames.clear();
-}
-
-void spyview_exit()
-{
- // Will the iw destructor get called automatically on hide?
- // However, it is important not to delete it before hiding all of
- // the windows, as if the zoom window is open, then it will crash on
- // win32 when it tries to call the draw_overlay() of iw after it's
- // been deleted.
-
- //delete iw;
-
- // Just calling exit(0) will rely on the OS to clear all of the
- // memory. While this seems to work fine on UNIX, on win32, this
- // results in intermittent and unpredictable crashes. According to
- // this reference, http://www3.telus.net/public/robark/, it is
- // better to hide all of the windows, which will call Fl::run() to
- // return more safely (?)
-
- while( Fl::first_window() )
- Fl::first_window()->hide();
-}
-
-void close_window_callback(Fl_Widget*)
-{
- //if (fl_ask("Juriaan, do you really want to close spyview?")) // Who is Juriaan?
- spyview_exit();
-
- // I had never clicked on the "close" button of the image window
- // before, and so I had never noticed the bug that if you close the
- // ImageWindow, the program doesn't close, but then it is impossible
- // to get the window to appear again.
-
- // This bug was found by one of my earlier Windows-based spyview
- // adopters, Juriaan. My initial answer was "why would you ever
- // click on the close button of the window?", but I eventually caved
- // and added this exit handler, and the warning message...
-
-}
-
-// Find all the colormaps in a path, using "pretty_path" for the browser
-// hierarchy.
-void find_cmaps(std::string path, std::string pretty_path)
-{
- typedef vector<string> subdirs_t;
- subdirs_t subdirs;
- info("Checking \"%s\" for cmaps (%s)\n", path.c_str(),pretty_path.c_str());
- struct dirent **namelist;
- string fn;
- int n = fl_filename_list(path.c_str(), &namelist, fl_casealphasort);
- int count = 0;
- for (int i = 0; i<n ; i++)
- {
- if ((strstr(namelist[i]->d_name, ".ppm") != NULL) || (strstr(namelist[i]->d_name,".spp") != NULL))
- {
- fn = namelist[i]->d_name;
- std::string pretty_fn(fn);
- pretty_fn.erase(pretty_fn.find_last_of('.'));
- cmapfiles.push_back(path + fn);
- int ind = cmapch->add((pretty_path + pretty_fn).c_str(), 0, 0, reinterpret_cast<void *>(cmapfiles.size()-1));
- if(strstr(namelist[i]->d_name,".ppm") != NULL)
- cmapch->menu()[ind].labelfont(FL_HELVETICA_ITALIC);
- else
- cmapch->menu()[ind].labelfont(FL_HELVETICA);
- count++;
- }
- else if (fl_filename_isdir((path+namelist[i]->d_name).c_str()))
- subdirs.push_back(namelist[i]->d_name);
- if ((count != 0) && (count%30 == 0))
- pretty_path += "More/";
- }
- for(subdirs_t::iterator i = subdirs.begin(); i != subdirs.end(); i++)
- {
- if(*i == "./" || *i == "../" || *i == "")
- continue;
- find_cmaps(path+*i,pretty_path+*i);
- }
-}
-
-int add_file(const char *name)
-{
- // We store the actual filenames in a STL vector of strings
- // called "filenames"
-
- // In "filech", we put a "user friendly" filename in, and we
- // store the index location of the real filename in the
- // userdata.
-
- string menu_text;
- int fd;
- int n;
- if ( (fd = open(name, O_RDONLY)) != -1)
- {
- filenames.push_back(name);
- n=filech->add("foo", 0, filech_cb, reinterpret_cast<void *>(filenames.size()-1));
- filech->replace(n, name);
- close(fd);
- return n;
- }
- else
- {
- warn("Unable to open file \"%s\": %s\n", name, strerror(errno));
- return -1;
- }
-}
-
-
-// breaks apart a string into substrings separated by a character string
-// does not use a strtok() style list of separator characters
-// returns a vector of std::strings
-
-std::vector<std::string> Explode (const std::string &inString, const std::string &separator)
-{
- std::vector<std::string> returnVector;
- std::string::size_type start = 0;
- std::string::size_type end = 0;
-
- while ((end = inString.find (separator, start)) != std::string::npos)
- {
- returnVector.push_back (inString.substr (start, end-start));
- start = end + separator.size();
- }
-
- returnVector.push_back(inString.substr(start, inString.size()));
- return returnVector;
-}
-
-// A drag-n-drop handler
-void load_filech(const char *text)
-{
- info("test is:\n_%s_", text);
- vector <string> files = Explode(text, "\n");
- info("found %d files\n", files.size());
-
- int n;
- for (unsigned i=0; i<files.size(); i++)
- {
- info("adding file '%s'\n", files[i].c_str());
- n=add_file(files[i].c_str());
- if (n == -1)
- return;
- }
- filech->value(n);
- filech->do_callback();
-}
-
-int load_orig_files()
-{
- filenames.clear();
- filech->clear();
- for (int i=opt_index; i < arg_count; i++)
- add_file(arg_values[i]);
- no_files_given = false;
- if (filenames.size() == 0)
- {
- no_files_given = true;
- add_file(default_file.c_str());
- if (check_loaded() == 0)
- error("Could not find default image!");
- }
- return 0;
-}
-
-/* Callbacks for image operations */
-// Callbacks for crop
-void cb_crop_to_zoom(Fl_Widget *w, void *p)
-{
- int x1,y1,x2,y2;
- if(!iw->zoom_window)
- return;
- iw->zoom_window->getSourceArea(x1,y1,x2,y2);
- char buf[1024];
- snprintf(buf,sizeof(buf),"%d",x1);
- proc_parameters[0]->value(buf);
- snprintf(buf,sizeof(buf),"%d",x2);
- proc_parameters[1]->value(buf);
- snprintf(buf,sizeof(buf),"%d",y1);
- proc_parameters[2]->value(buf);
- snprintf(buf,sizeof(buf),"%d",y2);
- proc_parameters[3]->value(buf);
- proc_parameters[3]->do_callback();
-}
-
-void cb_reset_zoom(Fl_Widget *w, void *p)
-{
- proc_parameters[0]->value("0");
- proc_parameters[1]->value("0");
- proc_parameters[2]->value("0");
- proc_parameters[3]->value("0");
- proc_parameters[3]->do_callback();
-}
-
-// Callbacks for line subtraction
-void cb_sub_current_line(Fl_Widget *w, void *p)
-{
- int line;
- if(proc_bool_parameters[1]->value())
- line = iw->line_cut_yp;
- else
- line = iw->line_cut_xp;
- char buf[1024];
- snprintf(buf,sizeof(buf),"%d",line);
- proc_parameters[0]->value(buf);
- proc_parameters[0]->do_callback();
-}
-
-void cb_hist2d_autorange(Fl_Widget *w, void *p)
-{
- double tmp;
- char buf[1024];
-
- tmp = iw->id.quant_to_raw(iw->hmin);
- snprintf(buf,sizeof(buf),"%e",tmp);
- proc_parameters[0]->value(buf);
-
- tmp = iw->id.quant_to_raw(iw->hmax);
- snprintf(buf,sizeof(buf),"%e",tmp);
- proc_parameters[1]->value(buf);
-
- snprintf(buf,sizeof(buf),"%d",iw->id.height);
- proc_parameters[2]->value(buf);
-
- proc_parameters[0]->do_callback();
-}
-
-void usage()
-{
- printf("%s\n",Fl::help);
-}
-
-
-void Update_Status_Bar(int n, bool down);
-void embed_colormap();
-void showUsedFiles(bool leak); // For debugging
-int main(int argc, char **argv)
-{
- char c;
- Fl::visual(FL_RGB8|FL_DOUBLE);
- Fl::get_system_colors();
- info("Welcome to spyview\n");
- info("Build stamp: %s\n", BUILDSTAMP);
-
- char buf[1024];
- original_dir = getcwd(buf, sizeof(buf));
-
-#ifdef WIN32
-
- // This is tricky. Look first for an environment variable. If not
- // found, try to guess from program name, which if we've been
- // launched using file associations, will contain the full
- // executable path. This should make things work without having to
- // do and "install"
-
- if (getenv("SPYVIEW_DIR") != NULL) // otherwise get a windows crash?
- sharedir = getenv("SPYVIEW_DIR");
- else
- {
- // Under windows, argv[0] (seems) to get the full program path
- // (when launched by explorer.exe, but not when called from the
- // cmd.exe command line) So we try to split out the path to the
- // executable here.
- sharedir = argv[0];
- int c2 = sharedir.find_last_of("\\");
- if(c2 >= 0)
- sharedir.replace(c2,string::npos, "");
- info("SPYVIEW_DIR not found: guessing %s from argv[0]\n", sharedir.c_str());
- }
- if (sharedir.size() == 0)
- {
- warn("Could not find good sharedir: reverting to '.'\n");
- sharedir = ".";
- }
- info("sharedir is %s\n", sharedir.c_str());
-
- // For win32, we have a couple of options to get the user's
- // Application Data directory: APPDATA, USERPROFILE, or HOMEDRIVE +
- // HOMEPATH + "Application Data\". For local users, these are all
- // the same. For network users, they can be different: for example,
- //
- // HOMEPATH=\ HOMEDRIVE=H:
-
- // USERPROFILE=C:\Documents and Settings\gsteele
- // APPDATA=\\tudelft.net\staff-homes\S\gsteele\Application Data
- //
- // Ideally, we should store it on the network drive H:
- // (\\tudelft.net\staff-homes\S\gsteele\). However, if we just use
- // APPDATA, it will not work since mingw32 does not support DFS UNC
- // paths. (It does support regular UNC paths, such as
- // \\myserver\gsteele, although forward slashes are not interpreted
- // as directory separators, as they are for local dirctories on
- // WinXP).
- //
- // In the end, it seems to be safest to take HOMEDRIVE + HOMEPATH + "Application Data"
-
- // Update: 3 Dec 09
- //
- // Due to popular demand, I will now change the default behaviour so
- // that spyview uses the settings files that are in the SHAREDIR,
- // unless there is a SPYVIEW_PREF_DIR set. Note that from the
- // command line, you will need to set SPYVIEW_PREF_DIR.
-
- if(getenv("SPYVIEW_PREF_DIR") != NULL)
- userdir = getenv("SPYVIEW_PREF_DIR");
- //else if((getenv("HOMEDRIVE") != NULL) && (getenv("HOMEPATH") != NULL))
- //{
- // userdir = getenv("HOMEDRIVE");
- // userdir = userdir + getenv("HOMEPATH") + "\\Application Data";
- // userdir += "\\spyview";
- //}
- else
- userdir=sharedir;
- info("userdir is %s\n", userdir.c_str());
-
-#else
- if(getenv("HOME"))
- userdir = getenv("HOME");
- else
- userdir = ".";
- userdir += "/.spyview";
- sharedir = SPYVIEW_DATADIR;
-#endif
- default_file = sharedir + DIRECTORY_SEPARATOR + "default_image.pgm";
-
- info("def file is %s\n", default_file.c_str());
-
- string settings_file("");
-
- int firstarg;
- Fl::args(argc,argv,firstarg);
-
- init_spypal();
- colormap_callback = spypal_cb;
- spypal_sharedir = sharedir;
- while ((c = getopt(argc, argv, "s:")) != -1)
- {
- switch (c)
- {
- case 's':
- info("found settings file %s\n", optarg);
- settings_file = userdir + DIRECTORY_SEPARATOR + "settings" + DIRECTORY_SEPARATOR + optarg;
- break;
- }
- }
-
- //info("settings file %s\n", settings_file.c_str());
- //getchar();
-
- make_window();
-
- // Initialize the optional "modules"; these insert themselves into spyview callbacks to grab
- // keystrokes and draw things.
-
- LineDraw iwld(iw);
- Fitting iwf(iw);
- ThresholdDisplay iwtd(iw);
- Fiddle iwfiddle(iw);
-
- // Set the pointers to the controls window and the process_queue in the image window class
- iw->controls_window = control;
- iw->process_queue = pqueue;
- iw->external_update = update_widgets;
- iw->drag_n_drop = load_filech;
-
- embed_colormap();
-
- iw->setGamma(1.0,0.0);
- wpbox->value(iw->wpercent);
- bpbox->value(iw->bpercent);
-
- //add_image_operations(); // why doesn't this work? must be something funny with the macros...
-
- Define_Image_Operation(new Image_Operation("neg","Negate numerical data"));
- Define_Image_Operation(new Image_Operation("square","Average pixels to make a square image"));
- Define_Image_Operation(new Image_Operation("autoflip","Flip axes so that more neg end is on left/bottom"));
-
- Image_Operation sub_fitplane("sub fitplane","Subtract a fitted plane with outlier rejection");
- sub_fitplane.addParameter("Low ", 20.0);
- sub_fitplane.addParameter("High ", 20.0);
- sub_fitplane.addParameter("!Percentiles?", 1);
- Define_Image_Operation(&sub_fitplane);
-
- Image_Operation sub_plane("sub plane","Subtract a plane with a specified slope");
- sub_plane.addParameter("Vert %", 0.0);
- sub_plane.addParameter("Horiz %", 0.0);
- Define_Image_Operation(&sub_plane);
-
- Image_Operation scale_axes("scale axes","Scale the ranges of the X & Y axes");
- scale_axes.addParameter("X scale", 1.0);
- scale_axes.addParameter("Y scale", 1.0);
- Define_Image_Operation(&scale_axes);
-
- Image_Operation offset_axes("offset axes","Offset the ranges of the X & Y axes");
- offset_axes.addParameter("X offset", 0.0);
- offset_axes.addParameter("Y offset", 0.0);
- Define_Image_Operation(&offset_axes);
-
- Image_Operation interp("interp","Interpolate the data onto a new grid (bilinear)");
- interp.addParameter("New x size", 200);
- interp.addParameter("New y size", 200);
- Define_Image_Operation(&interp);
-
- Image_Operation scale_img("scale img","Scale the image data using bilinear interpolation");
- scale_img.addParameter("X scaling", 2.5);
- scale_img.addParameter("Y scaling", 2.5);
- Define_Image_Operation(&scale_img);
-
- Image_Operation sub_lbl("sub lbl", "Subtract the mean of each image line with outlier rejection");
- sub_lbl.addParameter("Low %", 2.0);
- sub_lbl.addParameter("High %", 90.0);
- sub_lbl.addParameter("Low limit", -1e99);
- sub_lbl.addParameter("High limit", 1e99);
- //sub_lbl.addParameter("!Whole image thr?", 0);
- //sub_lbl.addParameter("!Percentiles?", 1);
- Define_Image_Operation(&sub_lbl);
-
- Image_Operation sub_cbc("sub cbc","Subtract the mean of each image column with outlier rejection");
- sub_cbc.addParameter("Low ", 2.0);
- sub_cbc.addParameter("High ", 90.0);
- sub_cbc.addParameter("Low limit", -1e99);
- sub_cbc.addParameter("High limit", 1e99);
- //sub_cbc.addParameter("!Whole image thr?", 0);
- //sub_cbc.addParameter("!Percentiles?", 1);
- Define_Image_Operation(&sub_cbc);
-
- Image_Operation sub_line("sub linecut","Subtract a linecut from every line");
- sub_line.addParameter("Line Num",0);
- sub_line.addParameter("!Horizontal",1);
- sub_line.addParameter(".Current Line",0,cb_sub_current_line);
- Define_Image_Operation(&sub_line);
-
- Image_Operation outlier_line("outlier","Remove an outlier line from the data");
- outlier_line.addParameter("Line Num",0);
- outlier_line.addParameter("!Horizontal",1);
- outlier_line.addParameter(".Current Line",0,cb_sub_current_line);
- Define_Image_Operation(&outlier_line);
-
- Define_Image_Operation(new Image_Operation("xderiv","Take an x derivative of the image data"));
- Define_Image_Operation(new Image_Operation("yderiv","Take a y derivative of the image data"));
- Image_Operation ederiv("ederiv","Take an energy derivative of the image data");
- ederiv.addParameter("Negative Scale",1.0);
- ederiv.addParameter("Positive Scale",1.0);
- Define_Image_Operation(&ederiv);
-
- Image_Operation dderiv("dderiv", "Take a derivative along an arbitrary axis");
- dderiv.addParameter("Theta",0.0);
- Define_Image_Operation(&dderiv);
- Image_Operation gradmag("gradmag", "Take the magnitude of the gradient");
- gradmag.addParameter("Axis Bias [0-1.0]",0.5);
- Define_Image_Operation(&gradmag);
-
- Image_Operation gamma("power","y = x^p, p<0 & abs(x)<eps => truncate x, y<0 & p not int => set y=0"); // a better name
- gamma.addParameter("Power", 0.5);
- gamma.addParameter("Epsilon", 1e-20);
- Define_Image_Operation(&gamma);
-
- Define_Image_Operation(new Image_Operation("norm lbl","Stretch the contrast of each line to full scale"));
- Define_Image_Operation(new Image_Operation("norm cbc","Stretch the contrast of each column to full scale"));
-
- Image_Operation lp("lowpass","Low pass filter the image; 0 for no filtering");
- lp.addParameter("X Width",3.0);
- lp.addParameter("Y Width",3.0);
- lp.addParameter("?Type 0,Gaussian 1,Lorentzian 2,Exponential 3,Thermal",0.0);
- Define_Image_Operation(&lp);
-
- Image_Operation hp("highpass","High pass filter the image; 0 for no filtering");
- hp.addParameter("X Width",3.0);
- hp.addParameter("Y Width",3.0);
- hp.addParameter("Pass. %",0.0);
- hp.addParameter("?Type 0,Gaussian 1,Lorentzian 2,Exponential",0.0);
- Define_Image_Operation(&hp);
-
- Image_Operation notch("notch","Notch filter the image; 0 for no filtering");
- notch.addParameter("X Low",2.0);
- notch.addParameter("X High",2.0);
- notch.addParameter("Y Low",2.0);
- notch.addParameter("Y High",3.0);
- Define_Image_Operation(¬ch);
-
- Image_Operation despeckle("despeckle","Despeckle Image Using Median Filter");
- despeckle.addParameter("!X Despeckle",1);
- despeckle.addParameter("!Y Despeckle",0);
- Define_Image_Operation(&despeckle);
-
- Image_Operation flip("flip","Flip the Image");
- flip.addParameter("!Flip X Axis",0);
- flip.addParameter("!Flip Y Axis",0);
- Define_Image_Operation(&flip);
-
- Image_Operation crop("crop","Crop the Image (0 to keep current, negative possible for lower/right)");
- crop.addParameter("left col #", 0);
- crop.addParameter("right col #", 0);
- crop.addParameter("upper row #", 0);
- crop.addParameter("lower row #", 0);
- crop.addParameter(".Copy Zoom",-1,cb_crop_to_zoom);
- crop.addParameter(".Reset Zoom",-1,cb_reset_zoom);
- Define_Image_Operation(&crop);
-
- Image_Operation pixel_avg("pixel avg","Down sample image by averaging pixels");
- pixel_avg.addParameter("X pixels", 2);
- pixel_avg.addParameter("Y pixels", 2);
- Define_Image_Operation(&pixel_avg);
-
- Image_Operation scale("scale data","Scale and center the data (change dynamic range)");
- scale.addParameter("Factor",0.5);
- Define_Image_Operation(&scale);
-
- Image_Operation offset("offset","Add an offset to the data");
- offset.addParameter("Offset by",0);
- offset.addParameter("!Auto (sub min first)", 1);
- Define_Image_Operation(&offset);
-
- Image_Operation log("log","Take logarithm (base 10) of intensities");
- log.addParameter("!Auto subtract offset", 0);
- log.addParameter("New min",1e-4);
- Define_Image_Operation(&log);
-
- Image_Operation sw_find("rm switch", "Remove switches (1 pixel jumps) in the data");
- sw_find.addParameter("Threshold", 300);
- sw_find.addParameter("Avg win",10);
- Define_Image_Operation(&sw_find);
-
- Image_Operation even_odd("even odd","Extract even or odd rows, optionally flipping odd rows");
- even_odd.addParameter("!Even", 1);
- even_odd.addParameter("!Flip odd rows", 1);
- Define_Image_Operation(&even_odd);
-
- Image_Operation hist2d("hist2d", "Convert y-axis into a histogram of each column");
- hist2d.addParameter("ymax", -100);
- hist2d.addParameter("ymax", +100);
- hist2d.addParameter("Num bins", 100);
- hist2d.addParameter(".Autorange", -1, cb_hist2d_autorange);
- //hist2d.addParameter("!Flip odd rows", 1);
- Define_Image_Operation(&hist2d);
-
-
- Image_Operation shift_data("shift data","Horizontally shift data after a given row");
- shift_data.addParameter("After row", 0);
- shift_data.addParameter("Shift (pix)", 0);
- Define_Image_Operation(&shift_data);
-
- Image_Operation remove_lines("remove lines","Remove lines, shifting data vertically");
- remove_lines.addParameter("Start row", 0);
- remove_lines.addParameter("# lines", 0);
- Define_Image_Operation(&remove_lines);
-
- Define_Image_Operation(new Image_Operation("rotate cw","Rotate the image by 90 degrees clockwise"));
- Define_Image_Operation(new Image_Operation("rotate ccw","Rotate the image by 90 degrees counter clockwise"));
- Define_Image_Operation(new Image_Operation("abs","Take the absolute value of the intensities"));
- Define_Image_Operation(new Image_Operation("equalize","Perform a histogramic equalization on the image"));
-
- // Now sort image operations alphabetically
-
-
- // Works on unix, but segfaults on win32?
-
-// Fl_Browser *b = options;
-// for ( int t=1; t<=b->size(); t++ ) {
-// for ( int r=t+1; r<=b->size(); r++ ) {
-// if ( strcmp(b->text(t), b->text(r)) > 0 ) {
-// b->swap(t,r);
-// }
-// }
-// }
-
- Fl_Browser *b = options;
- for ( int t=1; t<=b->size(); t++ )
- {
- for ( int r=t+1; r<=b->size(); r++ )
- {
- if ( strcmp(b->text(t), b->text(r)) > 0 )
- {
- //b->swap(t,r);
- string tmp = b->text(t);
- void *ptr = b->data(t);
- b->text(t, b->text(r));
- b->data(t, b->data(r));
- b->text(r, tmp.c_str());
- b->data(r, ptr);
- }
- }
- }
-
-
-
- // Check if these swapped properly
-// Image_Operation *op = (Image_Operation *) b->data(1);
-// info("text %s\n", options->text(1));
-// info("name %s\n", op->name.c_str());
-
- // Now it works fine? I don't know why it wasn't working?
-
- arg_values = argv;
- arg_count = argc;
- opt_index = optind;
-
- load_orig_files();
-
- info("Found "_STF" files\n", filenames.size());
-
- // Construct a list of colormap files
- // First scan them from /usr/share/spyview/cmaps, then ~/cmaps/ under unix
- // Look in current directory, then location of .exe / cmaps under windows.
-
- string user_path = userdir + DIRECTORY_SEPARATOR + "cmaps" + DIRECTORY_SEPARATOR;
- string share_path = sharedir + DIRECTORY_SEPARATOR + "cmaps" + DIRECTORY_SEPARATOR;
- find_cmaps(share_path, "");
- info("Loaded "_STF" color maps from %s.\n",cmapfiles.size(),share_path.c_str());
-
- if(share_path != user_path)
- {
- find_cmaps(user_path, "~/");
- info("Loaded "_STF" color maps from %s.\n",cmapfiles.size(),user_path.c_str());
- }
-
- int ind = cmapch->add("Custom",0,0,-1);
- cmapch->menu()[ind].labelfont(FL_HELVETICA_BOLD); // Make spypal stand out as it's different.
-
- // Update some of the widgets with the default values from the ImageWindow class
- gpusing->value(iw->gp_using_string);
- gpwith->value(iw->gp_with_string.c_str());
- location_fmt->value("%.1f");
-
-#ifdef WIN32
- Gnuplot_Interface::gnuplot_cmd = "\"" + sharedir + "\\pgnuplot.exe\"";
-#endif
-
- // Load the first file
- filech->value(0);
-
- // Find the first valid cmap
- for(int n = 0; true; n++)
- {
- assert(n <= cmapch->size());
- cmapch->value(n);
- if (!cmapch->mvalue()->submenu() && cmapch->text(n) != NULL) // null entry at end of submenu
- break;
- }
-
- //filech->do_callback(filech, (void *)argv[1]);
- //normb->do_callback();
- Fl::add_handler(keyhandler);
- //control->show();
- iw->statusCallback = Update_Status_Bar;
- // load the colormap
- loadsettings(settings_file.c_str());
- // Both of these are now called by loadsettings so we don't load the file twice at startup
- //cmapch->do_callback();
- //filech->do_callback(); // load the file before we call show
- Fl_Text_Buffer *helpbuf = new Fl_Text_Buffer();
- help_text->buffer(helpbuf);
- string help_file = sharedir + DIRECTORY_SEPARATOR + "help.txt";
- info("loading help from file %s\n", help_file.c_str());
- helpbuf->loadfile(help_file.c_str());
- helpbuf->append("\nBuild stamp:\n\n");
- helpbuf->append(BUILDSTAMP);
- iw->callback(close_window_callback);
- iw->show(argc,argv);
-
- Fl::run();
-
- delete iw; // Make sure we clean up the gnuplot nicely.
-}
-
-int keyhandler(int event)
-{
- int key;
- int n;
-
- switch (event)
- {
- case FL_SHORTCUT:
- key = Fl::event_key();
- switch(key)
- {
- case 'd':
- if (Fl::event_state() & FL_SHIFT)
- loadImageProcessing();
- else if (Fl::event_state() & FL_CTRL)
- loadColors();
- else
- {
- loadImageProcessing();
- loadColors();
- }
- return 1;
- case 'e':
- filech->do_callback();
- return 1;
- case 'u':
- if (unitswin->shown())
- unitswin->hide();
- else
- unitswin->show();
- return 1;
- case 'c':
- if (Fl::event_state() & FL_CTRL)
- {
- if (location_window->shown())
- location_window->hide();
- else
- location_window->show();
- return 1;
- }
- // note falling case!!!
- case FL_Escape:
- //also for 'c' with no shift
- if(!(iw->line_cut_limit & NOLINE))
- return 1;
- iw->line_cut_type = NOLINE;
- iw->plotLineCut();
- iw->redraw();
- return 1;
- case FL_Right:
- case ' ':
- n = filech->value();
- while (true)
- {
- n++;
- if (n == filech->size() - 1)
- n=0;
- if (filech->text(n) != NULL && strcmp(filech->text(n), "More") != 0)
- break;
- }
- filech->value(n);
- filech->do_callback();
- return 1;
- case FL_Left:
- case FL_BackSpace:
- n = filech->value();
- while (true)
- {
- n--;
- if (n<0)
- n = filech->size()-1;
- if (filech->text(n) != NULL && strcmp(filech->text(n), "More") != 0)
- break;
- }
- filech->value(n);
- filech->do_callback();
- return 1;
- case FL_Down:
- case 'j':
- n = cmapch->value();
- while (true)
- {
- n++;
- if (n == cmapch->size()-1)
- n=0;
- cmapch->value(n);
- if (!cmapch->mvalue()->submenu() && cmapch->text(n) != NULL) // null entry at end of submenu
- break;
- }
- cmapch->do_callback();
- return 1;
- case FL_Up:
- case 'k':
- n = cmapch->value();
- while (true)
- {
- n--;
- if (n<0)
- n= cmapch->size()-1;
- cmapch->value(n);
- if (!cmapch->mvalue()->submenu() && cmapch->text(n) != NULL)
- break;
- }
- cmapch->do_callback();
- return 1;
- case 't':
- showUsedFiles(Fl::event_state() & FL_SHIFT);
- break;
- case 'n':
- if (Fl::event_state() & FL_SHIFT)
- {
- Add_Image_Operation(new Image_Operation("neg", "Negate numerical data"));
- reload_data();
- pqueue->select(pqueue->size());
- pqueue->do_callback();
- return 1;
- }
- else
- {
- normb->do_callback();
- return 1;
- }
- case 'q':
- spyview_exit();
- return 1; // note that this is required if we're exiting by hiding all the windows!!!!
- case 's':
- iw->exportMTX(true);
- return 1;
- case 'v':
- if (control->visible())
- control->hide();
- else
- control->show();
- return 1;
- case 'h':
- if (helpwin->visible())
- helpwin->hide();
- else
- helpwin->show();
- return 1;
- case 'o':
- if (normwin->visible())
- normwin->hide();
- else
- normwin->show();
- return 1;
- case 'x':
- xsecb->do_callback();
- return 1;
- case 'f':
- if (!(Fl::event_state() & FL_CTRL) &&
- !(Fl::event_state() & FL_SHIFT))
- {
- if (iw->pfc.win->visible())
- iw->pfc.win->hide();
- else
- iw->pfc.win->show();
- return 1;
- }
- case 'l':
- if (Fl::event_state() & FL_CTRL)
- {
- if (reload_window->shown())
- reload_window->hide();
- else
- reload_window->show();
- return 1;
- }
- case 'r':
- iw->setXZoom(1);
- iw->setYZoom(1);
- return 1;
- case 'p':
- if (Fl::event_state() & FL_CTRL)
- {
- iw->setupPS();
- return 1;
- }
- else if (Fl::event_state() & FL_ALT)
- {
- info("exporting postscript\n");
- iw->exportPS();
- return 1;
- }
- else if (Fl::event_state() & FL_SHIFT)
- {
- iw->imageprinter->ipc->preview_button->do_callback();
- return 1;
- }
- else
- {
- if (procwin->shown())
- procwin->hide();
- else
- procwin->show();
- }
- return 1;
- }
- }
- return 0;
-}
-
-void save_cmap_cb(Fl_Button *o, void*)
-{
- iw->colormap_window->saveFile();
-}
-
-// Called by spypal to indicate the colormap has changed.
-void spypal_cb()
-{
- int index = reinterpret_cast<int>(cmapch->mvalue()->user_data());
- if(index != -1)
- cmapch->value(cmapch->find_item("Custom"));
- iw->setColormap(spypal_colormap,spypal_colormap_size);
-}
-
-static bool cmap_is_ppm; // Is the current cmap a ppm file?
-void cmapedit_cb(Fl_Button *, void *)
-{
- assert(spypal); assert(spypal->win);
- if(cmap_is_ppm)
- {
- printf("CMap is a .ppm; launching import window\n");
- spypal->copy_cmap(iw->getColormap(), iw->getColormapLength());
- spypal->import_controls->show();
- spypal->import_update();
- cmap_is_ppm = false;
- }
- if(spypal->win->visible())
- spypal->win->hide();
- else
- spypal->win->show();
- colormap_callback();
-}
-
-void cmapch_cb(Fl_Widget *o, void*)
-{
- FILE *fp;
- int index;
-
- index = reinterpret_cast<int>(cmapch->mvalue()->user_data());
-
- static char label[1024];
- snprintf(label, 1024, "%s - %s", filech->text(), cmapch->text());
- iw->label(label);
- snprintf(label, 1024, "Colormap %s", cmapch->text());
- (iw->colormap_window)->label(label);
-
- if(index == -1) // spypal mode!
- { // Don't show the spypal win; that's what the edit button's for.
- // spypal->win->show();
- spypal_cb();
- cmap_is_ppm = false;
- return;
- }
-
- assert(index >= 0);
- assert((unsigned)index < cmapfiles.size());
-
- //info("userdata for %s is %d\n", cmapch->value(), index);
- const char *filename = cmapfiles[index].c_str();
- //info("loading file _%s_ from index %d, text _%s_\n", cmapfiles[index].c_str(), index, cmapch->text(cmapch->value()));
- spypal->import_controls->hide();
-
- // File is a spypal colormap
- if(strstr(filename,".spp") != NULL)
- {
- // Don't call spypal_cb; it'll reset the chooser. Hack.
- colormap_callback = NULL;
- spypal->load(filename);
-
- colormap_callback = spypal_cb;
-
- iw->setColormap(spypal_colormap,spypal_colormap_size);
- cmap_is_ppm = false;
- return;
- }
-
- cmap_is_ppm = true;
- spypal->win->hide();
- pixel **image;
- pixval maxval;
- int rows, cols;
-
- fp = fopen(filename, "rb");
- if (fp == NULL)
- {
- perror(filename);
- exit(-1);
- }
-
-#ifndef debug_read //debug a binary read problen in windows. implemented some nice ppm read/write code, will leave it in here.
- image = ppm_readppm(fp, &cols, &rows, &maxval);
- fclose(fp);
-
- uchar newcmap[3*rows];
-
- if (cols > 1)
- error("Invalid colormap %s: must contain only one column!\n", filename);
-
- if (maxval != 255)
- error("Invalid colormap %s: color depth must be 8 bit (255 maxval)\n", filename);
-
- for (int i=0; i<rows; i++)
- {
- newcmap[i*3] = image[0][i].r;
- newcmap[i*3+1] = image[0][i].g;
- newcmap[i*3+2] = image[0][i].b;
- }
-
- ppm_freearray(image, rows);
-#else
- char buf[256];
- int raw_file = 1;
-
- fgets(buf, 256, fp);
- info("_%s_\n", buf);
- if (strncmp(buf, "P3",2) == 0)
- raw_file = 0;
- else if (strncmp(buf, "P6",2) != 0)
- error("Unsupported magic number %s: %s", buf, filename);
- fgets(buf, 256, fp);
- while (buf[0] == '#')
- fgets(buf, 256, fp);
- if (sscanf(buf, "%d %d", &cols, &rows) != 2)
- error("Invalid row/cols in PPM file: %s", filename);
- if (cols > 1)
- error("PPM fils should be only 1 pixel wide: %s", filename);
- fgets(buf, 256, fp);
- if (sscanf(buf, "%d", &maxval) != 1)
- error("Invalid maxval in PPM file: %s", filename);
- if (maxval != 255)
- error("Only 8 bit (255 maxval) ppm files supported: %s", filename);
-
- info("reading file %d rows from file %s, raw file %d\n", rows, filename, raw_file);
- uchar newcmap[3*rows];
- int n;
-
- if (raw_file)
- {
- if ((n=fread(newcmap, 1, rows*3, fp)) != rows*3)
- {
- info("feof %d ferror %d\n", feof(fp), ferror(fp));
- error("Short read on PPM file (error after %d bytes of %d, offset %x)\n"
- "last read values %x %x %x %x: %s",
- n, rows*3, n,
- newcmap[n-4], newcmap[n-3], newcmap[n-2], newcmap[n-1],
- filename);
- }
- }
- else
- {
- for (int i=0; i<rows; i++)
- {
- int r,g,b;
- if (fgets(buf, 256, fp) == NULL)
- error("Short read on PPM file (%d of %d): %s", i, rows, filename);
- if (sscanf(buf, "%d %d %d", &r,&g,&b) != 3)
- error("Could not convert row %d (%s): %s", i, buf, filename);
- newcmap[i*3] = r;
- newcmap[i*3+1] = g;
- newcmap[i*3+2] = b;
- }
- }
-
-#endif
- iw->setColormap(newcmap, rows);
-}
-
-void filech_cb(Fl_Widget *, void *)
-{
- int index = reinterpret_cast<int>(filech->mvalue()->user_data());
- const char *filename = filenames[index].c_str();
- //info("loading file _%s_ from index %d, text _%s_\n", filename, index, filech->text(filech->value()));
- int old_w, old_h;
-
- // Fixme; this leaks memory.
- char *dir = strdup(filename);
- dir = dirname(dir);
- filename = basename(filename);
- current_filename = filename;
- if (strcmp(dir, ".") == 0)
- dir=strdup(original_dir.c_str());
- info("Changing Directory to: %s\n", dir);
- info("Filename: %s\n", filename);
- chdir(dir);
-
- //info("Qmin/max: %e %e\n", iw->id.qmin, iw->id.qmax);
-
- // This is a bit awkward due to my naming of the w and h variables
- // representing the data size, which conflict with the fltk w() and
- // h() functions returning the window size...
- old_w = ((Fl_Widget*) iw)->w();
- old_h = ((Fl_Widget*) iw)->h();
-
- // All file loading is now handled inside ImageWindow (including mtx).
- if (iw->loadData(filename) == -1)
- {
- warn("Error with file %s: reverting to default image\n", filename);
- iw->loadData(default_file.c_str());
- }
-
- update_widgets();
-
- // Normalize the data if we've been asked
- if (norm_on_load->value())
- iw->normalize();
-
- // Give us a nice label
- //string label = filename;
- //label = label + " - " + cmapch->text();
- //set_units();
- update_title();
-}
-
-void embed_colormap()
-{
- control->add(iw->colormap_window);
-
- iw->colormap_window->resize(colormap_placeholder->x() + Fl::box_dx(colormap_placeholder->box()),
- colormap_placeholder->y() + Fl::box_dy(colormap_placeholder->box()),
- colormap_placeholder->w() - Fl::box_dw(colormap_placeholder->box()),
- colormap_placeholder->h() - Fl::box_dh(colormap_placeholder->box()));
-
- if(control->visible())
- iw->show();
- else
- iw->colormap_window->set_visible();
-}
-
-void update_title()
-{
- char buf[256];
- if (iw->id.data3d)
- snprintf(buf, 256, "%s %.0f (%.3g to %.3g), (%.3g to %.3g)",
- current_filename.c_str(),
- indexbox->value(),
- xmin->value(), xmax->value(),
- ymin->value(), ymax->value());
- else
- snprintf(buf, 256, "%s (%.3g to %.3g), (%.3g to %.3g)",
- current_filename.c_str(),
- xmin->value(), xmax->value(),
- ymin->value(), ymax->value());
- iw->copy_label(buf);
-}
-
-void set_units()
-{
- // First update image data class
- iw->id.xmin = xmin->value();
- iw->id.xmax = xmax->value();
- iw->id.ymin = ymin->value();
- iw->id.ymax = ymax->value();
- iw->id.xname = xunitname->value();
- iw->id.yname = yunitname->value();
- iw->id.zname = zunitname->value();
-
- // Note: changing these doesn't make any sense!
- // These should now be manipulated through imageprocessing operations
- // that act on the image data matrix
- //iw->id.zmin = zmin->value();
- //iw->id.zmax = zmax->value();
-
- // Now update the mtx data class if we have data loaded
-
- int x,y;
- if (iw->id.data3d)
- {
- switch (dim->value())
- {
- case 0: // YZ
- x = 1;
- y = 2;
- break;
- case 1: // ZX
- x = 2;
- y = 0;
- break;
- case 2: // XY
- x = 0;
- y = 1;
- break;
- }
- iw->id.mtx.axismin[x] = xmin->value();
- iw->id.mtx.axismax[x] = xmax->value();
- iw->id.mtx.axismin[y] = ymin->value();
- iw->id.mtx.axismax[y] = ymax->value();
- iw->id.mtx.axisname[x] = xunitname->value();
- iw->id.mtx.axisname[y] = yunitname->value();
- iw->id.mtx.dataname = zunitname->value();
- }
-
- update_widgets();
- iw->plotLineCut();
- update_title();
-}
-
-void set_3d_units()
-{
- iw->id.mtx.axismin[0] = mtx_xmin->value();
- iw->id.mtx.axismin[1] = mtx_ymin->value();
- iw->id.mtx.axismin[2] = mtx_zmin->value();
- iw->id.mtx.axismax[0] = mtx_xmax->value();
- iw->id.mtx.axismax[1] = mtx_ymax->value();
- iw->id.mtx.axismax[2] = mtx_zmax->value();
- iw->id.mtx.axisname[0] = mtx_xname->value();
- iw->id.mtx.axisname[1] = mtx_yname->value();
- iw->id.mtx.axisname[2] = mtx_zname->value();
-
- // We also have to update the image window class
-
- int x,y;
- switch (dim->value())
- {
- case 0: // YZ
- x = 1;
- y = 2;
- break;
- case 1: // ZX
- x = 2;
- y = 0;
- break;
- case 2: // XY
- x = 0;
- y = 1;
- break;
- }
-
- iw->id.xmin = iw->id.mtx.axismin[x];
- iw->id.xmax = iw->id.mtx.axismax[x];
- iw->id.ymin = iw->id.mtx.axismin[y];
- iw->id.ymax = iw->id.mtx.axismax[y];
- iw->id.xname = iw->id.mtx.axisname[x];
- iw->id.yname = iw->id.mtx.axisname[y];
-
- update_widgets();
- iw->plotLineCut();
-}
-
-
-void saveb_cb(Fl_Widget *, void *)
-{
- iw->saveFile();
- //fl_message("File was saved to %s", savebox->value());
- fl_beep(FL_BEEP_MESSAGE);
-}
-
-void update_widgets()
-{
- int min, max, width, center;
- min = iw->hmin;
- max = iw->hmax;
- width = (max - min);
- center = (max + min)/2;
-
- minv->value(min);
- minslider->value(min);
- minroller->value(min);
- minv_units->value(iw->id.quant_to_raw(min));
-
- maxv->value(max);
- maxslider->value(max);
- maxroller->value(max);
- maxv_units->value(iw->id.quant_to_raw(max));
-
- centerv->value(center);
- centerslider->value(center);
- centerroller->value(center);
- centerv_units->value(iw->id.quant_to_raw(center));
-
- widthv->value(width);
- widthslider->value(width);
- widthroller->value(width);
- widthv_units->value(iw->id.quant_to_raw(width)-iw->id.quant_to_raw(0));
-
- gammav->value(iw->gam);
- gammaroller->value(log(iw->gam));
- gammaslider->value(log(iw->gam));
- gcenterv->value(iw->gcenter);
- gcenterroller->value(iw->gcenter);
- gcenterslider->value(iw->gcenter);
- iw->adjustHistogram();
- plothistb->do_callback();
- plotcmapb->do_callback();
-
- plotcmapb->value(iw->plot_cmap);
- plothistb->value(iw->plot_hist);
- invertb->value(iw->invert);
- negateb->value(iw->negate);
- savebox->value(iw->output_basename);
-
- plane_a->value(iw->plane_a*((double)iw->h/65535.0));
- plane_aroller->value(iw->plane_a*((double)iw->h/65535.0));
- plane_aslider->value(iw->plane_a*((double)iw->h/65535.0));
- plane_b->value(iw->plane_b*((double)iw->w/65535.0));
- plane_broller->value(iw->plane_b*(double)iw->w/65535.0);
- plane_bslider->value(iw->plane_b*((double)iw->w/65535.0));
-
- cmap_min->value(iw->cmap_min);
- cmap_max->value(iw->cmap_max);
-
- xzoom_value->value(iw->xzoom);
- yzoom_value->value(iw->yzoom);
-
- xsize->value(iw->w);
- ysize->value(iw->h);
-
- // Update the units window
-
- xunitname->value(iw->id.xname.c_str());
- yunitname->value(iw->id.yname.c_str());
- zunitname->value(iw->id.zname.c_str());
-
- //qinfo("zname update: %s\nq", iw->id.zname.c_str());
-
- xmin->value(iw->id.xmin);
- ymin->value(iw->id.ymin);
- zmin->value(iw->id.qmin);
-
- xmax->value(iw->id.xmax);
- ymax->value(iw->id.ymax);
- zmax->value(iw->id.qmax);
-
- gpusing->value(iw->gp_using_string);
- gpwith->value(iw->gp_with_string.c_str());
-
- axis_type->value(iw->lc_axis);
-
- // Update the load settings window
-
- gp_parse_txt->value(iw->id.mtx.parse_txt);
- gp_delft_raw->value(iw->id.mtx.delft_raw_units);
- gp_delft_set->value(iw->id.mtx.delft_settings);
- gp_col->value(iw->id.gp_column+1);
- a_quant_percent->value(iw->id.auto_quant_percent);
-
- qmin->value(iw->id.qmin);
- qmax->value(iw->id.qmax);
-
- if (iw->id.data3d)
- {
- controls3d->activate();
- units3d->activate();
- }
- else
- {
- controls3d->deactivate();
- units3d->deactivate();
- }
-
- if (iw->id.datfile_type == MATRIX)
- dat_type_mat->setonly();
- else if (iw->id.datfile_type == GNUPLOT)
- dat_type_gp->setonly();
- else if (iw->id.datfile_type == DELFT_LEGACY)
- dat_type_delft->setonly();
- else if (iw->id.datfile_type == DAT_META)
- dat_type_meta->setonly();
-
- //info("update: type is %d\n", iw->id.gpload_type);
- if (iw->id.gpload_type == COLUMNS)
- gp_type_col->setonly();
- else if (iw->id.gpload_type == INDEX)
- gp_type_index->setonly();
-
- if (iw->window_size_action == KEEPZOOM)
- keep_zoom->setonly();
- else if (iw->window_size_action == KEEPSIZE)
- keep_size->setonly();
- else // if (iw->window)_size_action == RESETZOOM)
- reset_zoom->setonly();
-
- if (iw->id.auto_quant)
- a_quant->setonly();
- else
- man_quant->setonly();
-
- // Update MTX dialog boxes
-
- indexbox->value(iw->id.mtx_index);
- indexslider->value(iw->id.mtx_index);
- indexroller->value(iw->id.mtx_index);
-
- indexbox->maximum(iw->id.mtx.size[iw->id.mtx_cut_type]-1);
- indexslider->maximum(iw->id.mtx.size[iw->id.mtx_cut_type]-1);
- indexroller->maximum(iw->id.mtx.size[iw->id.mtx_cut_type]-1);
-
- index_value->value(iw->id.mtx.get_coordinate(iw->id.mtx_cut_type,
- iw->id.mtx_index));
-
- dim->value((int)iw->id.mtx_cut_type);
- mtx_label->value(iw->id.do_mtx_cut_title);
-
- mtx_x->value(iw->id.mtx.size[0]);
- mtx_y->value(iw->id.mtx.size[1]);
- mtx_z->value(iw->id.mtx.size[2]);
-
- mtx_xmin->value(iw->id.mtx.axismin[0]);
- mtx_ymin->value(iw->id.mtx.axismin[1]);
- mtx_zmin->value(iw->id.mtx.axismin[2]);
-
- mtx_xmax->value(iw->id.mtx.axismax[0]);
- mtx_ymax->value(iw->id.mtx.axismax[1]);
- mtx_zmax->value(iw->id.mtx.axismax[2]);
-
- mtx_xname->value(iw->id.mtx.axisname[0].c_str());
- mtx_yname->value(iw->id.mtx.axisname[1].c_str());
- mtx_zname->value(iw->id.mtx.axisname[2].c_str());
-
- xrange->value(iw->line_cut_xauto);
-
-}
-
-void Fetch_ProcWindow_Settings(Image_Operation *op)
-{
- for(unsigned i = 0; i < op->parameters.size(); i++)
- {
- Image_Operation::Parameter *p = &(op->parameters[i]);
- if(i > proc_bool_parameters.size()) // All buttons must be at end.
- {
- assert(p->name.c_str()[0] == '.');
- break;
- }
-
- Fl_Check_Button *b = proc_bool_parameters[i];
- Fl_Input *in = proc_parameters[i];
- Fl_Choice *ch = proc_choice_parameters[i];
- switch(p->name.c_str()[0])
- {
- case '!':
- p->value = b->value();
- break;
- case '?':
- p->value = reinterpret_cast<int>(ch->mvalue()->user_data_);
- break;
- case '.':
- p->value = 0;
- break;
- default:
- p->value = atof(in->value());
- break;
- }
- }
- if(last_proc_side == pqueue)
- op->enabled = enable_filter->value();
-}
-
-void Set_ProcWindow_Settings(Image_Operation *op)
-{
- bool redraw_window = false;
- int bcount = 0; // Number of buttons so far.
- assert(proc_bool_parameters.size() == proc_parameters.size());
- assert(proc_choice_parameters.size() == proc_parameters.size());
-
- for(unsigned i = 0; i < proc_button_parameters.size(); i++)
- {
- Fl_Button *but = proc_button_parameters[i];
- but->hide();
- but->callback( (Fl_Callback *) NULL,NULL);
- }
- for(unsigned i = 0; i < op->parameters.size(); i++)
- {
- Image_Operation::Parameter *p = &(op->parameters[i]);
- if(p->name.c_str()[0] == '.') // Button
- {
- assert(bcount < proc_button_parameters.size());
- Fl_Button *but = proc_button_parameters[bcount++];
- but->label(p->name.c_str()+1);
- but->value(static_cast<int>(p->value));
- if(p->cb)
- but->callback(p->cb,NULL);
- but->show();
- continue;
- }
-
- assert(op->parameters.size() > i-bcount);
- Fl_Check_Button *b = proc_bool_parameters[i-bcount];
- Fl_Input *in = proc_parameters[i-bcount];
- Fl_Choice *ch = proc_choice_parameters[i-bcount];
- switch(p->name.c_str()[0])
- {
- case '.':
- assert(0);
- case '!': // Boolean
- {
- if(strcmp(p->name.c_str()+1,b->label()) != 0)
- redraw_window = true;
- b->label(p->name.c_str()+1);
- b->value(static_cast<int>(p->value));
- b->show();
- in->hide();
- ch->hide();
- break;
- }
- case '?': // Choice
- {
- redraw_window = true; // Lazy lazy lazy
- char *tmp = strdup(p->name.c_str());
- char *s1 = strchr(tmp,' ');
- assert(s1 != NULL);
- *s1++ = 0; // tmp+1 is now the choice name
- if(strcmp(tmp+1,ch->label()) != 0)
- redraw_window = true;
- ch->copy_label(tmp+1);
- ch->clear();
- while(isspace(*s1))
- s1++;
- while(1)
- {
- char *s2 = strchr(s1,' ');
- if(s2 != NULL)
- *s2 = 0;
- char buf[1024];
- int val;
- if(sscanf(s1," %d,%s ",&val,buf) != 2)
- {
- fprintf(stderr,"Error parsing format string \"%s\" from %s\n",s1,p->name.c_str());
- exit(1);
- }
- int idx = ch->add(buf,(const char *)NULL,NULL,(void *)val);
- if(val == p->value)
- ch->value(idx);
- if(s2 == NULL)
- break;
- else
- s1 = s2+1;
- }
- b->hide();
- in->hide();
- ch->show();
- free(tmp);
- break;
- }
- default:
- {
- if(p->name != in->label())
- redraw_window = true;
- in->label(p->name.c_str());
- char buf[1024];
- snprintf(buf,sizeof(buf),"%g",p->value);
- in->value(buf);
- in->show();
- b->hide();
- ch->hide();
- break;
- }
- }
- }
- for(unsigned i = op->parameters.size()-bcount; i < proc_parameters.size(); i++)
- {
- proc_parameters[i]->hide();
- proc_bool_parameters[i]->hide();
- proc_choice_parameters[i]->hide();
- }
- proc_description->value(op->description.c_str());
- if(last_proc_side == pqueue)
- {
- enable_filter->value(op->enabled);
- enable_filter->activate();
- }
- else
- enable_filter->deactivate();
- if(redraw_window) // Sometimes, if the labels get longer, we get dead characters in the background.
- procwin->redraw();
-}
-
-void Define_Image_Operation(Image_Operation *op)
-{
- options->add(op->name.c_str(), op);
-}
-
-void Add_Image_Operation(Image_Operation *op)
-{
- info("Adding operation: %s\n", op->name.c_str());
- Image_Operation *new_op = new Image_Operation(*op); // Copy so we don't share settings.
- pqueue->add(op->name.c_str(), new_op);
-}
-
-void Update_Status_Bar(int key, bool down)
-{
- static double ox, oy;
-
- int i = iw->dounzoom(Fl::event_x(),iw->xzoom);
- int j = iw->dounzoom(Fl::event_y(),iw->yzoom);
-
- double x = iw->id.getX(i);
- double y = iw->id.getY(j);
-
- if(ox != x || oy != y)
- {
- static char locbuf[1024];
- static char tmpbuf[1024];
- static char fmt_string[1024];
- static char fmt[1024];
-
- // Format is set in the Cursor Position window
- snprintf(fmt, sizeof(fmt), "%s", location_fmt->value());
-
- // Update the location bar at the bottom of the controls window
- sprintf(fmt_string, "%s,%s = %s %%s", fmt, fmt, fmt);
- snprintf(locbuf,sizeof(locbuf),fmt_string,
- x,y,iw->dataval(i,j), iw->id.zname.c_str());
- location_bar->label(locbuf);
-
- // Update the "Cursor Postion" window as well
- snprintf(tmpbuf, sizeof(tmpbuf), fmt, x);
- location_x->value(tmpbuf);
- location_x->label(xunitname->value());
- x_col->value(i);
-
- snprintf(tmpbuf, sizeof(tmpbuf), fmt, y);
- location_y->value(tmpbuf);
- location_y->label(yunitname->value());
- y_row->value(j);
-
- snprintf(tmpbuf, sizeof(tmpbuf), fmt, iw->dataval(i,j));
- location_data->value(tmpbuf);
- data_name->value(zunitname->value());
-
- // Update the zoom window information in the Cursor window
-
- if (iw->zoom_window)
- {
- zoom_group->activate();
- int x1,y1,x2,y2;
- iw->zoom_window->getSourceArea(x1,y1,x2,y2);
-
- zx1->value(x1);
- snprintf(tmpbuf, sizeof(tmpbuf), fmt, iw->id.getX(x1));
- zx1v->value(tmpbuf);
-
- zx2->value(x2);
- snprintf(tmpbuf, sizeof(tmpbuf), fmt, iw->id.getX(x2));
- zx2v->value(tmpbuf);
-
- zy1->value(y1);
- snprintf(tmpbuf, sizeof(tmpbuf), fmt, iw->id.getY(y1));
- zy1v->value(tmpbuf);
-
- zy2->value(y2);
- snprintf(tmpbuf, sizeof(tmpbuf), fmt, iw->id.getY(y2));
- zy2v->value(tmpbuf);
- }
- else
- zoom_group->deactivate();
-
- ox = x;
- oy = y;
-
- }
-
- static const int event_mask=FL_CTRL|FL_SHIFT;
- static std::map<int, string> h;
-// This is where the status bar help goes
-// Add entries as needed.
- if(h.size() == 0)
- {
- h[0] = "B1: X Linecut; B2: Y Linecut; B3: Control Win";
- h[FL_CTRL] = "B1: Arb Linecut; B2: Move Endpt; B3: Drag Linecut";
- h[FL_SHIFT] = "B1: Drag Zoom; B3: Move Zoom Window";
- }
- static int last_state = -1;
-
- int state = Fl::event_state() & event_mask;
- // Horrible hack to handle XWindows shift state bug
- if(key == FL_Shift_L || key == FL_Shift_R)
- {
- if(down)
- state = state | FL_SHIFT;
- else
- state = state & ~FL_SHIFT;
- }
- if(key == FL_Control_L || key == FL_Control_R)
- {
- if(down)
- state = state | FL_CTRL;
- else
- state = state & ~FL_CTRL;
- }
-
- if(last_state != state)
- {
- // This will automagically make an empty entry if event_state
- // is not in the help database
- const char *help = h[state].c_str();
- help_bar->value(help);
- last_state = state;
- }
-}
-
-void reload_cb(Fl_Widget *, void *)
-{
- dirent **dirlist;
- int n;
-
- n = fl_filename_list(".", &dirlist);
- if (replaceb->value()) clear_files();
-
- for (int i = 0; i<n; i++)
- if (fl_filename_match(dirlist[i]->d_name, reload_text->value()))
- add_file(dirlist[i]->d_name);
-
- if (filenames.size() == 0)
- {
- fl_alert("No files found!! Reverting to the list of files given on command line.");
- load_orig_files();
- }
-
- filech->value(0);
- filech->do_callback();
-
- for (int i = n; i > 0;)
- free((void*)(dirlist[--i]));
- free((void*)dirlist);
-
-}
-
-
-/*
- =============== Serialization Code ==========================
- boost stores class versions, not archive versions. In order to maintain backwards compatability
- for the "top level" objects (of which there are probably too many, because the FLTK widgets aren't
- encapsulated in a class), we introduce a helper class here. */
-const char * spyviewSettingsDir; // Ugly ugly ugly -- this belongs in the class, but spyview_ui.C wants it as well.
- // Maybe the class shouldn't be static...
-
-class Spyview_Serializer_t
-{
-public:
- typedef boost::archive::text_iarchive input_archive;
- typedef boost::archive::text_oarchive output_archive;
-
-// Directory setup functions.
- std::string settingsDir;
-
- void maybe_mkdir(const char *name)
- {
-#ifdef WIN32
- if(mkdir(name) == 0)
-#else
- if(mkdir(name,0777) == 0)
-#endif
- return;
-
- switch(errno)
- {
- case EEXIST:
- return;
- default:
- warn("Unable to create directory \"%s\": %s\n",name,strerror(errno));
- return;
- }
- }
-
- void initSettingsDir() // Use the system dependent userdir
- {
- string buf = userdir;
- maybe_mkdir(buf.c_str());
- buf = buf + DIRECTORY_SEPARATOR + "settings"; // note += won't work because the cast is wrong...
- settingsDir = buf;
- maybe_mkdir(buf.c_str());
- spyviewSettingsDir = settingsDir.c_str();
- }
-
-// Save/load functions
- void save(std::string &name)
- {
- initSettingsDir();
- if(name.empty())
- {
- name = settingsDir + DIRECTORY_SEPARATOR + "default.svs";
- }
- const char *fname = name.c_str();
- try
- {
- std::ofstream ofs(fname, std::ios::binary);
- if(!ofs.good())
- throw(1);
- output_archive oa(ofs); //doesn't work under win32?
- oa & (*this);
- }
- catch (boost::archive::archive_exception &e)
- {
- warn("Error saving spyview settings: %s\n",e.what());
- }
- catch (std::exception &e)
- {
- warn("Error saving settings file \"%s\": %s (%s)\n",fname,e.what(),strerror(errno));
- }
- catch (...)
- {
- error("Unknown error from settings file\n");
- }
- };
-
- void load(std::string &name)
- {
- initSettingsDir();
- if(name.empty())
- {
-
- name = settingsDir + DIRECTORY_SEPARATOR + "default.svs";
- }
-
- const char *fname = name.c_str();
- info("loading settings from %s\n", fname);
- try
- {
- std::ifstream ifs(fname, std::ios::binary);
- if(!ifs.good())
- {
- warn("IFS is not good!\n");
- throw(1);
- }
- input_archive ia(ifs);
- ia & (*this);
- }
- catch (boost::archive::archive_exception &e)
- {
- warn("Error loading settings %s\nTry overwriting the default settings file to get rid of this error.\n",e.what());
- }
- catch (std::exception &e)
- {
- warn("Spyview serialization error; did not load settings: %s (%s)\nTry overwriting the default settings file to get rid of this error.\n",e.what(),typeid(e).name());
- }
- catch (...)
- {
- warn("Unable to load settings file \"%s\": %s\nTry overwriting the default settings file to get rid of this error.\n",fname,strerror(errno));
- }
- };
-
- template<class Archive>
- void serialize(Archive & ar, const unsigned int version)
- {
- ar & (*iw);
-
- // Newer versions of spyview hide the extensions on the colormaps.
- // This causes the chooser serialization to ignore extensions so old
- // save files still work.
- push_chooser_equality(chooser_equality_noextension);
- ar & flcast(cmapch);
- pop_chooser_equality();
-
- ar & flcast(norm_on_load);
- ar & flcast(squareb);
- ar & flcast(dim);
-
- if (version >= 1)
- ar & flcast(gpwith);
- if (version >= 2)
- {
- ar & iw->id.datfile_type;
- ar & iw->id.gpload_type;
- ar & iw->id.gp_column;
- //ar & iw->id.mtx_cut_type; // This one is quite annoying, actually...
- }
- if (version >= 3)
- {
- ar & iw->id.mtx.parse_txt;
- Fl_Input tmp(0,0,0,0,""); // This used to be ipc.preview_cmd
- //ar & flcast(iw->ipc.preview_cmd);
- ar & flcast(&tmp);
- }
- if (version >= 4)
- {
- ar & iw->id.mtx.delft_raw_units;
- }
- if (version >= 5)
- {
- ar & iw->id.mtx.delft_settings;
- }
- if(version == 6)
- {
- warn("Version 6 archives were bad.. Spypal settings ignored\n");
- }
- if(version >= 7)
- {
- ar & (*spypal);
- }
- if(Archive::is_loading::value)
- {
- wpbox->value(iw->wpercent);
- bpbox->value(iw->bpercent);
- cmrot->value(iw->colormap_rotation_angle);
- cmrot_roller->value(iw->colormap_rotation_angle);
- if (version >= 1)
- iw->gp_with_string = gpwith->value();
- iw->setXZoom(iw->xzoom); // make sure to call this after updating class variables as it calls update_widgets()
- if(reinterpret_cast<int>(cmapch->mvalue()->user_data()) == -1) // Custom
- {
- cmap_is_ppm = false;
- spypal->recalculate(true);
- }
- }
- };
-};
-static Spyview_Serializer_t Spyview_Serializer;
-
-BOOST_CLASS_VERSION(Spyview_Serializer_t, 7); // Increment this if the archive format changes.
-
-void savesettings(std::string name)
-{
- Spyview_Serializer.save(name);
-}
-
-void loadsettings(std::string name)
-{
- Spyview_Serializer.load(name);
- cmapch->do_callback();
- filech->do_callback();
-}
-
-/* Motivation: open *always* returns the lowest numbered file descriptor. So by mapping which ones
- it returs, we can figure out which are in use. */
-void showUsedFiles(bool leak) // Simulate a file descriptor leak if leak is true
-{
- std::vector<int> desc;
- size_t ulen=80;
- int cnt = 0;
- int used[ulen];
-
- while(1)
- {
- int f = open(filenames[0].c_str(), O_RDONLY); // A file that should be available in both windows and unix.
- if(f < 0)
- {
- warn("Unable to check file descriptors! First .pgm file \"%s\": %s\n",
- filenames[0].c_str(), strerror(errno));
- goto cleanup;
- }
- if(f > ulen)
- {
- close(f);
- break;
- }
- else
- desc.push_back(f);
- }
-
- for(int i = 0; i < ulen; i++)
- used[i] = 1;
- for(int i = 0; i < desc.size(); i++)
- {
- if(desc[i] < ulen)
- used[desc[i]] = 0;
- }
- printf("Leak map: ");
- for(int i = 0; i < ulen; i++)
- {
- printf("%d", used[i]);
- if(used[i])
- cnt++;
- }
- printf("\n");
- printf("%d Total descriptors in use\n",cnt);
- cleanup:
- while(desc.size() > leak ? 1 : 0)
- {
- close(desc.back());
- desc.pop_back();
- }
-}
-//#endif
-
-void loadColors(char *fn)
-{
- // Automatically pick filename
- string filename;
- if (fn == NULL)
- {
- filename = iw->output_basename;
- filename += ".colors";
- }
- else
- filename = fn;
- info("loading colors to file %s\n", filename.c_str());
- std::ifstream ifs(filename.c_str());
- if (!ifs.good())
- {
- info("Error opening colors file: %s\n", filename.c_str());
- return;
- }
- boost::archive::text_iarchive ar(ifs);
-
- // Version 1: stuff to archive:
- //
- // hmin
- // hmax
- // gamma
- // gamma_center
- // quant_min
- // quant_max
- // colormap
- //
-
- int version;
- ar & version;
- ar & iw->hmin;
- ar & iw->hmax;
- ar & iw->gam;
- ar & iw->gcenter;
- ar & iw->id.qmin;
- ar & iw->id.qmax;
- ar & flcast(cmapch);
-
- // After loading, we will:
- //
- // - call update_widgets()
- // - turn off autonormalize (spyview gui widget)
- // - turn off autoquantize (in ImageData)
- // - requantize the data
- // - set the min and max
-
- norm_on_load->value(0);
- iw->id.auto_quant = false;
- iw->id.quantize();
- cmapch->do_callback();
- iw->adjustHistogram(); // this should remap and replot the data
- update_widgets();
-}
-
-
-void saveColors(char *fn)
-{
- // Automatically pick filename
- string filename;
- if (fn == NULL)
- {
- filename = iw->output_basename;
- filename += ".colors";
- }
- else
- filename = fn;
- info("saving colors to file %s\n", filename.c_str());
- std::ofstream ofs(filename.c_str());
- if (!ofs.good())
- {
- info("Error saving to colors file: %s\n", filename.c_str());
- return;
- }
- boost::archive::text_oarchive ar(ofs);
-
- // Note -- we need to set the version for the save direction,
- // otherwise it'll be random.
- int version = 1;
- ar & version;
- // All this stuff is in version 1
- ar & iw->hmin;
- ar & iw->hmax;
- ar & iw->gam;
- ar & iw->gcenter;
- ar & iw->id.qmin;
- ar & iw->id.qmax;
- ar & flcast(cmapch);
-}
-
-void saveImageProcessing(char *fn)
-{
- // Automatically pick filename
- string filename;
- if (fn == NULL)
- {
- filename = iw->output_basename;
- filename += ".img_proc";
- }
- else
- filename = fn;
- info("saving image processing to file %s\n", filename.c_str());
- std::ofstream ofs(filename.c_str());
- if (!ofs.good())
- {
- warn("Error saving to image processing file: %s\n", filename.c_str());
- return;
- }
- boost::archive::text_oarchive ar(ofs);
-
- int tmp = pqueue->size();
- ar & tmp;
- fprintf(stderr,"Saving %d process entries\n",tmp);
- for(int i = 1; i <= pqueue->size(); i++)
- {
- std::string tmp = pqueue->text(i);
- ar & tmp;
- Image_Operation * t = reinterpret_cast<Image_Operation *>(pqueue->data(i));
- ar & t;
- }
-}
-
-void loadImageProcessing(char *fn)
-{
- // Automatically pick filename
- string filename;
- if (fn == NULL)
- {
- filename = iw->output_basename;
- filename += ".img_proc";
- }
- else
- filename = fn;
- info("loading image_processing from file %s\n", filename.c_str());
- std::ifstream ifs(filename.c_str());
- if (!ifs.good())
- {
- info("Error opening image processing file: %s\n", filename.c_str());
- return;
- }
- boost::archive::text_iarchive ar(ifs);
-
- for(int i = 1 ; i <= pqueue->size(); i++)
- delete reinterpret_cast<Image_Operation *>(pqueue->data(i));
- int len;
- pqueue->clear();
- ar & len; // This has the size of the expected queue
- fprintf(stderr,"Loading %d process entries\n",len);
- for(int i = 1; i <= len; i++)
- {
- std::string tmp;
- ar & tmp;
- Image_Operation *op;
- ar & op;
- pqueue->add(tmp.c_str(),op);
- }
- reload_data();
-}
-
+++ /dev/null
-otool -L
-
-list the libraries a program is linked against
+++ /dev/null
-set -x
-exe="spybrowse.exe dat2mtx.exe spyview.exe spyview_console.exe spybrowse_console.exe mtxdiff.exe huettel2mtx.exe toeno2mtx.exe *.bat help.txt"
-scp $exe kavli:public_html/spyview/windows_exe
+++ /dev/null
-set -x
-# remote=qt.tn.tudelft.nl
-# exe="spybrowse.exe dat2mtx.exe spyview.exe spyview_console.exe spybrowse_console.exe mtxdiff.exe huettel2mtx.exe toeno2mtx.exe *.bat pgnuplot.exe wgnuplot.exe gilles2mtx.exe help.txt updates_page.url ns2pgm.exe"
-# cp $exe spyview_windows
-# scp $exe $remote:public_html/spyview/windows_exe
-# rm spyview_windows.zip
-# zip -r spyview_windows.zip spyview_windows
-# #(cd spyview_windows; zip -r ../spyview_windows.zip .)
-# scp spyview_windows.zip $remote:public_html/spyview/
-# scp spyview_console.exe help.txt $remote:public_html/spyview/
-
-# Now we're building on the local machine
-exe="spybrowse.exe dat2mtx.exe spyview.exe spyview_console.exe spybrowse_console.exe mtxdiff.exe huettel2mtx.exe toeno2mtx.exe *.bat pgnuplot.exe wgnuplot.exe gilles2mtx.exe help.txt updates_page.url ns2pgm.exe"
-cp $exe spyview_windows
-cp ~/public_html/spyview/windows_exe
-rm spyview_windows.zip
-zip -r spyview_windows.zip spyview_windows
-#(cd spyview_windows; zip -r ../spyview_windows.zip .)
-cp spyview_windows.zip ~/public_html/spyview/
-cp spyview_console.exe help.txt ~/public_html/spyview/
-date > ~/public_html/spyview/update.html