diff options
author | Thomas White <taw@physics.org> | 2020-08-01 15:13:49 +0200 |
---|---|---|
committer | Thomas White <taw@physics.org> | 2020-08-01 15:19:26 +0200 |
commit | 189da15810deabd739d7c11c6e95fea55739fe60 (patch) | |
tree | e86e43fcbbf8278b792a74daf684cde3bd6e2bbf /src/contourise.c |
Initial import from archive
Diffstat (limited to 'src/contourise.c')
-rw-r--r-- | src/contourise.c | 441 |
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); +} |