aboutsummaryrefslogtreecommitdiff
path: root/src/contourise.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/contourise.c')
-rw-r--r--src/contourise.c441
1 files changed, 441 insertions, 0 deletions
diff --git a/src/contourise.c b/src/contourise.c
new file mode 100644
index 0000000..56e10b8
--- /dev/null
+++ b/src/contourise.c
@@ -0,0 +1,441 @@
+/*
+ * contourise.c
+ *
+ * Draw contour maps
+ *
+ * (c) 2006-2009 Thomas White <taw27@cam.ac.uk>
+ *
+ * synth2d - Two-Dimensional Crystallographic Fourier Synthesis
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <fftw3.h>
+#include <math.h>
+
+#include "displaywindow.h"
+#include "model.h"
+#include "data.h"
+#include "renderer.h"
+
+typedef struct {
+ GtkWidget *rad_mod;
+ GtkWidget *rad_mod_sign;
+ GtkWidget *rad_real;
+ GtkWidget *rad_imag;
+ GtkWidget *n_contours;
+ int nx;
+ int ny;
+} ContourDialog;
+
+typedef enum {
+ VALUES_NONE,
+ VALUES_MODULUS,
+ VALUES_MODULUS_SIGN,
+ VALUES_REAL,
+ VALUES_IMAGINARY
+} ContourValues;
+
+static GtkWidget *contourise_dialog = NULL;
+
+static void griwrite(FILE *gri, const char *string)
+{
+ fwrite(string, strlen(string), 1, gri);
+}
+
+static void contourise_map(fftw_complex *out, unsigned int width,
+ unsigned int height, ContourValues vals,
+ int nx, int ny, int ncont)
+{
+ FILE *gri;
+ char tmp[1024];
+ double maxval;
+ int model_marks;
+ int xn, yn;
+ pid_t pid;
+ int status;
+ size_t width_n, height_n;
+ double gamma;
+ double aspect;
+ int landscape; /* 1=landscape, 0=portrait */
+ int fit_x; /* 1=fit the x-axis to the page, 0=fit the y-axis */
+ ComplexArray cxar;
+ double xsize, ysize, scale;
+
+ gamma = data_gamma();
+
+ if ( ( displaywindow_mode() == DWV_MODEL )
+ || ( displaywindow_mode() == DWV_DIFFERENCE )
+ || ( displaywindow_mode() == DWV_EXITWAVE )
+ || ( displaywindow_mode() == DWV_REFSYN ) ) {
+ model_marks = 1;
+ } else {
+ model_marks = 0;
+ }
+
+ width_n = renderer_width(width, height, gamma, nx, ny);
+ height_n = renderer_height(width, height, gamma, nx, ny);
+
+ maxval = displaywindow_max();
+
+ gri = popen("gri -b -no_startup_message", "w");
+ if ( !gri ) {
+ fprintf(stderr, "Couldn't invoke gri. Please check your PATH.");
+ return;
+ }
+
+ /* Initialise */
+ griwrite(gri, "set postscript filename synth2d.ps\n");
+ griwrite(gri, "set page size A4\n");
+ snprintf(tmp, 1023, "set x grid 0 1 /%i\n", width_n);
+ griwrite(gri, tmp);
+ snprintf(tmp, 1023, "set y grid 0 1 /%i\n", height_n);
+ griwrite(gri, tmp);
+
+ /* Figure out the size */
+ aspect = (double)height_n/width_n;
+ if ( width_n > height_n ) {
+ landscape = 1;
+ if ( aspect < (19.0/27.7) ) {
+ fit_x = 1;
+ } else {
+ fit_x = 0;
+ }
+ } else {
+ landscape = 0;
+ if ( aspect < (27.7/19.0) ) {
+ fit_x = 1;
+ } else {
+ fit_x = 0;
+ }
+ }
+ if ( landscape ) {
+ if ( fit_x ) {
+ xsize = 27.7;
+ ysize = 27.7*aspect;
+ scale = 27.7/width_n;
+ } else {
+ xsize = 19.0/aspect;
+ ysize = 19.0;
+ scale = 19.0/height_n;
+ }
+ } else {
+ if ( fit_x ) {
+ xsize = 19.0;
+ ysize = 19.0*aspect;
+ scale = 19.0/width_n;
+ } else {
+ xsize = 27.7/aspect;
+ ysize = 27.7;
+ scale = 27.7/height_n;
+ }
+ }
+ printf("CO: aspect=%f => selected ", aspect);
+ if ( landscape ) {
+ printf("landscape, ");
+ griwrite(gri, "set page landscape\n");
+ } else {
+ printf("portrait, ");
+ griwrite(gri, "set page portrait\n");
+ }
+ if ( fit_x ) {
+ printf("fitting x, ");
+ } else {
+ printf("fitting y, ");
+ }
+ snprintf(tmp, 1023, "set x size %f\n", xsize);
+ griwrite(gri, tmp);
+ snprintf(tmp, 1023, "set y size %f\n", ysize);
+ griwrite(gri, tmp);
+ printf("width=%f height=%f\n", xsize, ysize);
+
+ griwrite(gri, "set x margin 1\n"); /* cm */
+ griwrite(gri, "set y margin 1\n"); /* cm */
+ griwrite(gri, "set axes style none\n");
+ griwrite(gri, "set line width 3.0\n");
+ if ( landscape ) {
+ if ( fit_x ) {
+ snprintf(tmp, 1023, "draw box 1 1 %f %f cm\n",
+ 1.0+27.7, 1.0+27.7*aspect);
+ griwrite(gri, tmp);
+ } else {
+ snprintf(tmp, 1023, "draw box 1 1 %f %f cm\n",
+ 1.0+19.0/aspect, 1.0+19.0);
+ griwrite(gri, tmp);
+ }
+ } else {
+ if ( fit_x ) {
+ snprintf(tmp, 1023, "draw box 1 1 %f %f cm\n",
+ 1.0+19.0, 1.0+19.0*aspect);
+ griwrite(gri, tmp);
+ } else {
+ snprintf(tmp, 1023, "draw box 1 1 %f %f cm\n",
+ 1.0+27.7/aspect, 1.0+27.7);
+ griwrite(gri, tmp);
+ }
+ }
+
+ /* Read the data and plot contours */
+ griwrite(gri, "read grid data\n");
+
+ /* Give it the data to read... */
+ cxar = renderer_draw(out, width, height, gamma, nx, ny);
+ for ( yn=height_n-1; yn>=0; yn-- ) {
+
+ int first = 1;
+
+ for ( xn=0; xn<width_n; xn++ ) {
+
+ double re, im;
+
+ if ( !first ) griwrite(gri, " "); else first = 0;
+
+ re = cxar.re[xn+width_n*yn];
+ im = cxar.im[xn+width_n*yn];
+
+ if ( (vals == VALUES_MODULUS)
+ || (vals == VALUES_MODULUS_SIGN) ) {
+ double val = sqrt(re*re + im*im);
+ if ( (vals == VALUES_MODULUS_SIGN)
+ && (re < 0) ) {
+ snprintf(tmp, 1023, "-%f", val);
+ } else {
+ snprintf(tmp, 1023, "%f", val);
+ }
+ } else if ( vals == VALUES_REAL ) {
+ double val = re;
+ snprintf(tmp, 1023, "%f", val);
+ } else if ( vals == VALUES_IMAGINARY ) {
+ double val = im;
+ snprintf(tmp, 1023, "%f", val);
+ }
+ griwrite(gri, tmp);
+
+ }
+ griwrite(gri, "\n");
+
+ }
+
+ griwrite(gri, "set line width 1.5\n");
+ snprintf(tmp, 1023, "draw contour 0 %f %f unlabelled\n",
+ maxval, maxval/ncont);
+ griwrite(gri, tmp);
+ griwrite(gri, "set line width 1.0\n");
+ griwrite(gri, "set color blue\n");
+ griwrite(gri, "set dash 7\n");
+ snprintf(tmp, 1023, "draw contour %f %f %f unlabelled\n",
+ -maxval, -maxval/ncont, maxval/ncont);
+ griwrite(gri, tmp);
+
+ /* Mark the atomic coordinates if appropriate */
+ if ( model_marks ) {
+
+ AtomicModel *model;
+ int i;
+
+ griwrite(gri, "set color red\n");
+ griwrite(gri, "set dash 0\n");
+ griwrite(gri, "set symbol size 0.5\n");
+ griwrite(gri, "set line width symbol 0.8\n");
+
+ model = model_get_current();
+
+ for ( i=0; i<model->n_atoms; i++ ) {
+
+ double p, q;
+ int xc, yc;
+
+ p = model->atoms[i].x;
+ q = model->atoms[i].y;
+
+ for ( xc=0; xc<nx; xc++ ) {
+ for ( yc=0; yc<ny; yc++ ) {
+ double x, y;
+ x = renderer_map_x((p+xc)*(double)width,
+ (q+yc)*(double)height,
+ width, height, gamma, nx, ny);
+ x *= scale;
+ y = renderer_map_y((p+xc)*(double)width,
+ (q+yc)*(double)height,
+ width, height, gamma, nx, ny);
+ y *= scale;
+ snprintf(tmp, 1023,
+ "draw symbol 1 at %f %f cm\n",
+ 1.0+x, 1.0+y);
+ griwrite(gri, tmp);
+ }
+ }
+
+ }
+
+ }
+
+ if ( pclose(gri) == -1 ) {
+ fprintf(stderr, "gri returned an error code.");
+ return;
+ }
+
+ pid = fork();
+ if ( (pid != 0) && (pid != -1) ) {
+ printf("CO: Invoking ps2pdf...\n");
+ } else {
+ if ( pid == -1 ) {
+ fprintf(stderr, "fork() failed.\n");
+ return;
+ } else {
+ /* Forked successfully, child process */
+ system("ps2pdf -sPAPERSIZE=a4 synth2d.ps");
+ _exit(0);
+ }
+ }
+
+ waitpid(pid, &status, 0);
+
+ pid = fork();
+ if ( (pid != 0) && (pid != -1) ) {
+ printf("CO: Invoking evince...\n");
+ } else {
+ if ( pid == -1 ) {
+ fprintf(stderr, "fork() failed.\n");
+ return;
+ } else {
+ /* Forked successfully, child process */
+ system("evince synth2d.pdf");
+ _exit(0);
+ }
+ }
+
+ free(cxar.re);
+ free(cxar.im);
+}
+
+static gint contourise_dialog_close(GtkWidget *window, gint response,
+ ContourDialog *cd)
+{
+ int error = 0;
+
+ if ( response == GTK_RESPONSE_OK ) {
+
+ ContourValues vals;
+ int ncont = 0;
+ const char *ncont_s;
+
+ vals = VALUES_NONE;
+ if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
+ cd->rad_mod)) )
+ vals = VALUES_MODULUS;
+ if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
+ cd->rad_mod_sign)) )
+ vals = VALUES_MODULUS_SIGN;
+ if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
+ cd->rad_real)) )
+ vals = VALUES_REAL;
+ if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
+ cd->rad_imag)) )
+ vals = VALUES_IMAGINARY;
+ if ( vals == VALUES_NONE ) error = 1;
+
+ ncont_s = gtk_entry_get_text(GTK_ENTRY(cd->n_contours));
+ if ( sscanf(ncont_s, "%i", &ncont) != 1 ) {
+ error_report("Invalid number of contours");
+ error = 1;
+ } else {
+ if ( ncont < 1 ) {
+ error_report("Invalid number of contours");
+ error = 1;
+ }
+ }
+
+ if ( error == 0 ) {
+ contourise_map(displaywindow_outarray(),
+ data_width(), data_height(),
+ vals,
+ cd->nx, cd->ny, ncont);
+ }
+
+ }
+
+ if ( error == 0 ) {
+ gtk_widget_destroy(window);
+ contourise_dialog = NULL;
+ free(cd);
+ }
+
+ return 0;
+}
+
+void contourise_dialog_open(int nx, int ny)
+{
+ ContourDialog *cd;
+ GtkWidget *vbox;
+ GtkWidget *hbox;
+ GtkWidget *text;
+ GtkWidget *ncont_hbox;
+
+ if ( contourise_dialog ) {
+ return;
+ }
+
+ contourise_dialog = gtk_dialog_new_with_buttons("Contour Map",
+ GTK_WINDOW(displaywindow_gtkwindow()),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
+ cd = malloc(sizeof(ContourDialog));
+ if ( !cd ) return;
+ cd->nx = nx; /* Number of unit cells */
+ cd->ny = ny; /* Store these for later */
+
+ /* Structure */
+ vbox = gtk_vbox_new(FALSE, 0);
+ hbox = gtk_hbox_new(TRUE, 0);
+ gtk_box_pack_start(GTK_BOX(GTK_DIALOG(contourise_dialog)->vbox),
+ GTK_WIDGET(hbox), TRUE, TRUE, 7);
+ gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 5);
+
+ text = gtk_label_new("");
+ gtk_label_set_markup(GTK_LABEL(text),
+ "<span style=\"italic\" weight=\"light\">"
+ "What do you want to plot?</span>");
+ gtk_label_set_line_wrap(GTK_LABEL(text), TRUE);
+ gtk_box_pack_start(GTK_BOX(vbox), text, FALSE, FALSE, 5);
+
+ cd->rad_mod_sign = gtk_radio_button_new_with_label(NULL,
+ "Modulus with sign: √[Re(V)² + Im(V)²] × sign[Re(V)]");
+ gtk_box_pack_start(GTK_BOX(vbox), cd->rad_mod_sign, FALSE, FALSE, 2);
+ cd->rad_mod = gtk_radio_button_new_with_label_from_widget(
+ GTK_RADIO_BUTTON(cd->rad_mod_sign),
+ "Modulus alone: √[Re(V)² + Im(V)²]");
+ gtk_box_pack_start(GTK_BOX(vbox), cd->rad_mod, FALSE, FALSE, 2);
+ cd->rad_real = gtk_radio_button_new_with_label_from_widget(
+ GTK_RADIO_BUTTON(cd->rad_mod_sign),
+ "Real part: Re(V)");
+ gtk_box_pack_start(GTK_BOX(vbox), cd->rad_real, FALSE, FALSE, 2);
+ cd->rad_imag = gtk_radio_button_new_with_label_from_widget(
+ GTK_RADIO_BUTTON(cd->rad_mod_sign),
+ "Imaginary part: Im(V)");
+ gtk_box_pack_start(GTK_BOX(vbox), cd->rad_imag, FALSE, FALSE, 2);
+
+ text = gtk_label_new("Number of contours:");
+ gtk_misc_set_alignment(GTK_MISC(text), 1.0, 0.5);
+ ncont_hbox = gtk_hbox_new(FALSE, 2);
+ gtk_box_pack_start(GTK_BOX(ncont_hbox), text, FALSE, TRUE, 2);
+ gtk_box_pack_end(GTK_BOX(vbox), ncont_hbox, FALSE, FALSE, 2);
+ cd->n_contours = gtk_entry_new();
+ gtk_entry_set_width_chars(GTK_ENTRY(cd->n_contours), 4);
+ gtk_box_pack_start(GTK_BOX(ncont_hbox), cd->n_contours, FALSE, TRUE, 2);
+ gtk_entry_set_text(GTK_ENTRY(cd->n_contours), "20");
+
+ g_signal_connect(G_OBJECT(contourise_dialog), "response",
+ G_CALLBACK(contourise_dialog_close), cd);
+ gtk_widget_show_all(contourise_dialog);
+}