/* * render_hkl.c * * Draw pretty renderings of reflection lists * * (c) 2006-2010 Thomas White * * Part of CrystFEL - crystallography with a FEL * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #ifdef HAVE_CAIRO #include #include #endif #include "utils.h" #include "reflections.h" #include "povray.h" #include "symmetry.h" enum { WGHT_I, WGHT_SQRTI, WGHT_COUNTS, WGHT_RAWCOUNTS, }; static void show_help(const char *s) { printf("Syntax: %s [options] \n\n", s); printf( "Render intensity lists in various ways.\n" "\n" " -h, --help Display this help message.\n" " --povray Render a 3D animation using POV-ray.\n" #ifdef HAVE_CAIRO " --zone-axis Render a 2D zone axis pattern.\n" #endif " --boost= Squash colour scale by .\n" " -j Run instances of POV-ray in parallel.\n" " -p, --pdb= PDB file from which to get the unit cell.\n" " -y, --symmetry= Expand reflections according to point group .\n" " -w --weighting= Colour/shade the reciprocal lattice points\n" " according to:\n" " I : the intensity of the reflection.\n" " sqrtI : the square root of the intensity.\n" " count : the number of hits for the reflection.\n" " (after correcting for 'epsilon')\n" " rawcts : the raw number of hits for the\n" " reflection (no 'epsilon' correction).\n" ); } #ifdef HAVE_CAIRO static void render_za(UnitCell *cell, double *ref, unsigned int *c, double boost, const char *sym, int wght) { cairo_surface_t *surface; cairo_t *dctx; double max_u, max_v, max_res, max_val; double scale_u, scale_v, scale; double sep_u, sep_v, max_r; double u, v; signed int max_h, max_k; double as, bs, theta; double asx, asy, asz; double bsx, bsy, bsz; double csx, csy, csz; signed int h, k; float wh, ht; wh = 1024; ht = 1024; surface = cairo_pdf_surface_create("za.pdf", wh, ht); if ( cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS ) { fprintf(stderr, "Couldn't create Cairo surface\n"); cairo_surface_destroy(surface); return; } dctx = cairo_create(surface); /* Black background */ cairo_rectangle(dctx, 0.0, 0.0, wh, ht); cairo_set_source_rgb(dctx, 0.0, 0.0, 0.0); cairo_fill(dctx); max_u = 0.0; max_v = 0.0; max_val = 0.0; max_res = 0.0; max_h = 0; max_k = 0; /* Work out reciprocal lattice spacings and angles for this cut */ if ( cell_get_reciprocal(cell, &asx, &asy, &asz, &bsx, &bsy, &bsz, &csx, &csy, &csz) ) { ERROR("Couldn't get reciprocal parameters\n"); return; } theta = angle_between(asx, asy, asz, bsx, bsy, bsz); as = modulus(asx, asy, asz) / 1e9; bs = modulus(bsx, bsy, bsz) / 1e9; STATUS("theta=%f\n", rad2deg(theta)); for ( h=-INDMAX; h0.0) ? sqrt(val) : 0.0; break; case WGHT_COUNTS : val = (float)ct; val /= (float)num_equivs(h, k, 0, sym); break; case WGHT_RAWCOUNTS : val = (float)ct; break; default : ERROR("Invalid weighting.\n"); abort(); } nequiv = num_equivs(h, k, 0, sym); for ( p=0; p fabs(max_u) ) max_u = fabs(u); if ( fabs(v) > fabs(max_v) ) max_v = fabs(v); if ( fabs(val) > fabs(max_val) ) { max_val = fabs(val); } if ( fabs(he) > max_h ) max_h = fabs(he); if ( fabs(ke) > max_k ) max_k = fabs(ke); res = resolution(cell, he, ke, 0); if ( res > max_res ) max_res = res; } } } max_res /= 1e9; printf("Maximum resolution is 1/d = %5.3f nm^-1, d = %5.3f nm\n", max_res*2.0, 1.0/(max_res*2.0)); if ( max_val <= 0.0 ) { max_r = 4.0; goto out; } /* Choose whichever scaling factor gives the smallest value */ scale_u = ((double)(wh/2.0)-50.0) / max_u; scale_v = ((double)(ht/2.0)-50.0) / max_v; scale = (scale_u < scale_v) ? scale_u : scale_v; sep_u = as * scale * cos(theta); sep_v = bs * scale; max_r = (sep_u < sep_v) ? sep_u : sep_v; max_r -= 1.0; /* Add a tiny separation between circles */ for ( h=-INDMAX; h0.0) ? sqrt(val) : 0.0; break; case WGHT_COUNTS : val = (float)ct; val /= (float)num_equivs(h, k, 0, sym); break; case WGHT_RAWCOUNTS : val = (float)ct; break; default : ERROR("Invalid weighting.\n"); abort(); } val = boost*val/max_val; nequiv = num_equivs(h, k, 0, sym); for ( p=0; p