render_hkl.c 19.3 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*
 * render_hkl.c
 *
 * Draw pretty renderings of reflection lists
 *
 * (c) 2006-2010 Thomas White <taw@physics.org>
 *
 * Part of CrystFEL - crystallography with a FEL
 *
 */


#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>
23
#ifdef HAVE_CAIRO
Thomas White's avatar
Thomas White committed
24
25
#include <cairo.h>
#include <cairo-pdf.h>
26
#endif
27
28

#include "utils.h"
29
#include "povray.h"
30
#include "symmetry.h"
31
#include "render.h"
32
#include "render_hkl.h"
Thomas White's avatar
Thomas White committed
33
34
#include "reflist.h"
#include "reflist-utils.h"
35
36


37
38
39
#define KEY_FILENAME "key.pdf"


40
41
42
43
static void show_help(const char *s)
{
	printf("Syntax: %s [options] <file.hkl>\n\n", s);
	printf(
44
"Render intensity lists in various ways.\n"
45
"\n"
46
"      --povray            Render a 3D animation using POV-ray.\n"
47
#ifdef HAVE_CAIRO
48
"      --zone-axis         Render a 2D zone axis pattern.\n"
49
#endif
50
"\n"
51
"  -d, --down=<h>,<k>,<l>  Indices for the axis in the downward direction.\n"
52
"                           Default: 1,0,0.\n"
53
"  -r, --right=<h>,<k>,<l> Indices for the axis in the 'right' (roughly)\n"
54
"                           direction.  Default: 0,1,0.\n"
55
"  -o, --output=<filename> Output filename (not for POV-ray).  Default: za.pdf\n"
56
57
58
"      --boost=<val>       Squash colour scale by <val>.\n"
"  -p, --pdb=<file>        PDB file from which to get the unit cell.\n"
"  -y, --symmetry=<sym>    Expand reflections according to point group <sym>.\n"
59
60
61
62
"\n"
"  -c, --colscale=<scale>  Use the given colour scale.  Choose from:\n"
"                           mono    : Greyscale, black is zero.\n"
"                           invmono : Greyscale, white is zero.\n"
Thomas White's avatar
Thomas White committed
63
"                           colour  : Colour scale:\n"
64
65
"                                     black-blue-pink-red-orange-yellow-white\n"
"\n"
66
67
"  -w  --weighting=<wght>  Colour/shade the reciprocal lattice points\n"
"                           according to:\n"
68
69
"                            I      : the intensity of the reflection.\n"
"                            sqrtI  : the square root of the intensity.\n"
Thomas White's avatar
Thomas White committed
70
"                            count  : the number of measurements for the reflection.\n"
71
"                                     (after correcting for 'epsilon')\n"
Thomas White's avatar
Thomas White committed
72
"                            rawcts : the raw number of measurements for the\n"
73
"                                     reflection (no 'epsilon' correction).\n"
74
75
76
77
"\n"
"      --colour-key        Draw (only) the key for the current colour scale.\n"
"  -j <n>                  Run <n> instances of POV-ray in parallel.\n"
"  -h, --help              Display this help message.\n"
78
);
79
80
81
}


82
#ifdef HAVE_CAIRO
83
84


85
86
87
static void draw_circles(signed int xh, signed int xk, signed int xl,
                         signed int yh, signed int yk, signed int yl,
                         signed int zh, signed int zk, signed int zl,
Thomas White's avatar
Thomas White committed
88
                         RefList *list, const char *sym,
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
                         cairo_t *dctx, int wght, double boost, int colscale,
                         UnitCell *cell, double radius, double theta,
                         double as, double bs, double cx, double cy,
                         double scale,
                         signed int *max_ux, signed int *max_uy,
                         double *max_val, double *max_u, double *max_v,
                         double *max_res)
{
	signed int xi, yi;

	if ( dctx == NULL ) {
		*max_u = 0.0;  *max_v = 0.0;  *max_val = 0.0;
		*max_res = 0.0;  *max_ux = 0;  *max_uy = 0;
	}

Thomas White's avatar
Thomas White committed
104
	/* Iterate over possible reflections in this zone */
105
106
107
108
109
	for ( xi=-INDMAX; xi<INDMAX; xi++ ) {
	for ( yi=-INDMAX; yi<INDMAX; yi++ ) {

		double u, v, val, res;
		signed int h, k, l;
Thomas White's avatar
Thomas White committed
110
		signed int he, ke, le;
Thomas White's avatar
Thomas White committed
111
		Reflection *refl;
Thomas White's avatar
Thomas White committed
112
		int r;
113
114
115
116
117
118

		h = xi*xh + yi*yh;
		k = xi*xk + yi*yk;
		l = xi*xl + yi*yl;

		/* Got this reflection? */
Thomas White's avatar
Thomas White committed
119
120
121
		r = find_equiv_in_list(list, h, k, l, sym, &he, &ke, &le);
		if ( !r ) continue;
		refl = find_refl(list, he, ke, le);
122
123
124

		switch ( wght ) {
		case WGHT_I :
Thomas White's avatar
Thomas White committed
125
			val = get_intensity(refl);
126
127
			break;
		case WGHT_SQRTI :
Thomas White's avatar
Thomas White committed
128
			val = get_intensity(refl);
129
130
131
			val = (val>0.0) ? sqrt(val) : 0.0;
			break;
		case WGHT_COUNTS :
Thomas White's avatar
Thomas White committed
132
133
			val = get_redundancy(refl);
			val /= (float)num_equivs(h, k, l, sym);
134
135
			break;
		case WGHT_RAWCOUNTS :
Thomas White's avatar
Thomas White committed
136
			val = get_redundancy(refl);
137
138
139
140
141
142
			break;
		default :
			ERROR("Invalid weighting.\n");
			abort();
		}

143
		/* Absolute location in image based on 2D basis */
Thomas White's avatar
Thomas White committed
144
145
		u = (double)xi*as*sin(theta);
		v = (double)xi*as*cos(theta) + (double)yi*bs;
146

147
		if ( dctx != NULL ) {
148

149
			double r, g, b;
150

151
152
153
			cairo_arc(dctx, ((double)cx)+u*scale,
			                ((double)cy)+v*scale,
			                radius, 0, 2*M_PI);
154

155
156
157
158
			render_scale(val, *max_val/boost, colscale,
			             &r, &g, &b);
			cairo_set_source_rgb(dctx, r, g, b);
			cairo_fill(dctx);
159

160
		} else {
161

162
163
164
			/* Find max vectors in plane for scaling */
			if ( fabs(u) > fabs(*max_u) ) *max_u = fabs(u);
			if ( fabs(v) > fabs(*max_v) ) *max_v = fabs(v);
165

166
			/* Find max value for colour scale */
Thomas White's avatar
Thomas White committed
167
168
169
			if ( !isnan(val) && !isinf(val)
			  && (fabs(val) > fabs(*max_val)) )
			{
170
				*max_val = fabs(val);
171
172
			}

173
			/* Find max indices */
Thomas White's avatar
Thomas White committed
174
175
176
177
			if ( (yi==0) && (fabs(xi) > *max_ux) )
				*max_ux = fabs(xi);
			if ( (xi==0) && (fabs(yi) > *max_uy) )
				*max_uy = fabs(yi);
178
179

			/* Find max resolution */
Thomas White's avatar
Thomas White committed
180
			res = resolution(cell, h, k, l);
181
			if ( res > *max_res ) *max_res = res;
Thomas White's avatar
Thomas White committed
182

183
184
185
186
187
188
189
		}

	}
	}
}


190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
static void render_overlined_indices(cairo_t *dctx,
                                     signed int h, signed int k, signed int l)
{
	char tmp[256];
	cairo_text_extents_t size;
	double x, y;
	const double sh = 39.0;

	cairo_get_current_point(dctx, &x, &y);
	cairo_set_line_width(dctx, 4.0);

	/* Draw 'h' */
	snprintf(tmp, 255, "%i", abs(h));
	cairo_text_extents(dctx, tmp, &size);
	cairo_show_text(dctx, tmp);
	cairo_fill(dctx);
	if ( h < 0 ) {
		cairo_move_to(dctx, x+size.x_bearing, y-sh);
		cairo_rel_line_to(dctx, size.width, 0.0);
		cairo_stroke(dctx);
	}
	x += size.x_advance;

	/* Draw 'k' */
	cairo_move_to(dctx, x, y);
	snprintf(tmp, 255, "%i", abs(k));
	cairo_text_extents(dctx, tmp, &size);
	cairo_show_text(dctx, tmp);
	cairo_fill(dctx);
	if ( k < 0 ) {
		cairo_move_to(dctx, x+size.x_bearing, y-sh);
		cairo_rel_line_to(dctx, size.width, 0.0);
		cairo_stroke(dctx);
	}
	x += size.x_advance;

	/* Draw 'l' */
	cairo_move_to(dctx, x, y);
	snprintf(tmp, 255, "%i", abs(l));
	cairo_text_extents(dctx, tmp, &size);
	cairo_show_text(dctx, tmp);
	cairo_fill(dctx);
	if ( l < 0 ) {
		cairo_move_to(dctx, x+size.x_bearing, y-sh);
		cairo_rel_line_to(dctx, size.width, 0.0);
		cairo_stroke(dctx);
	}
}


Thomas White's avatar
Thomas White committed
240
static void render_za(UnitCell *cell, RefList *list,
241
242
                      double boost, const char *sym, int wght, int colscale,
                      signed int xh, signed int xk, signed int xl,
243
                      signed int yh, signed int yk, signed int yl,
244
                      const char *outfile, double scale_top)
245
{
Thomas White's avatar
Thomas White committed
246
247
	cairo_surface_t *surface;
	cairo_t *dctx;
248
	double max_u, max_v, max_res, max_val;
249
	double scale_u, scale_v, scale;
Thomas White's avatar
Thomas White committed
250
	double sep_u, sep_v, max_r;
251
	double u, v;
252
	signed int max_ux, max_uy;
Thomas White's avatar
Thomas White committed
253
	double as, bs, theta;
254
255
256
	double asx, asy, asz;
	double bsx, bsy, bsz;
	double csx, csy, csz;
Thomas White's avatar
Thomas White committed
257
	float wh, ht;
258
259
260
261
262
263
264
	signed int zh, zk, zl;
	double xx, xy, xz;
	double yx, yy, yz;
	char tmp[256];
	cairo_text_extents_t size;
	double cx, cy;
	const double border = 200.0;
265
	int png;
266

267
	/* Vector product to determine the zone axis. */
268
269
270
271
	zh = xk*yl - xl*yk;
	zk = - xh*yl + xl*yh;
	zl = xh*yk - xk*yh;
	STATUS("Zone axis is %i %i %i\n", zh, zk, zl);
272

273
	/* Size of output and centre definition */
Thomas White's avatar
Thomas White committed
274
275
	wh = 1024;
	ht = 1024;
276

Thomas White's avatar
Thomas White committed
277
	/* Work out reciprocal lattice spacings and angles for this cut */
278
	if ( cell_get_reciprocal(cell, &asx, &asy, &asz,
Thomas White's avatar
Thomas White committed
279
	                          &bsx, &bsy, &bsz,
280
281
282
283
	                          &csx, &csy, &csz) ) {
		ERROR("Couldn't get reciprocal parameters\n");
		return;
	}
284
285
286
287
288
289
290
291
292
293
	xx = xh*asx + xk*bsx + xl*csx;
	xy = xh*asy + xk*bsy + xl*csy;
	xz = xh*asz + xk*bsz + xl*csz;
	yx = yh*asx + yk*bsx + yl*csx;
	yy = yh*asy + yk*bsy + yl*csy;
	yz = yh*asz + yk*bsz + yl*csz;
	theta = angle_between(xx, xy, xz, yx, yy, yz);
	as = modulus(xx, xy, xz) / 1e9;
	bs = modulus(yx, yy, yz) / 1e9;

294
	scale = 1.0;
295
	draw_circles(xh, xk, xl, yh, yk, yl, zh, zk, zl,
Thomas White's avatar
Thomas White committed
296
	             list, sym, NULL, wght, boost, colscale, cell,
Thomas White's avatar
Thomas White committed
297
	             0.0, theta, as, bs, 0.0, 0.0, scale,
298
	             &max_ux, &max_uy, &max_val, &max_u, &max_v, &max_res);
299

Thomas White's avatar
Thomas White committed
300
	max_res /= 1e9;
301
302
	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));
Thomas White's avatar
Thomas White committed
303

304
	if ( max_val <= 0.0 ) {
305
		STATUS("Couldn't find max value.\n");
Thomas White's avatar
Thomas White committed
306
		return;
307
308
	}

309
310
311
312
313
	/* Use manual scale top if specified */
	if ( scale_top > 0.0 ) {
		max_val = scale_top;
	}

Thomas White's avatar
Thomas White committed
314
	/* Choose whichever scaling factor gives the smallest value */
315
316
	scale_u = ((double)wh-border) / (2.0*max_u);
	scale_v = ((double)ht-border) / (2.0*max_v);
317
	scale = (scale_u < scale_v) ? scale_u : scale_v;
318

319
320
	sep_u = scale*as;
	sep_v = scale*bs;
321
	/* We are interested in the smaller of the two separations */
322
	max_r = (sep_u < sep_v) ? sep_u : sep_v;
323
	max_r /= 2.0;  /* Max radius is half the separation */
324
	max_r -= 1.0;  /* Add a tiny separation between circles */
325
326
327
	if ( max_r < 1.0 ) {
		ERROR("Circle radius is probably too small (%f).\n", max_r);
	}
Thomas White's avatar
Thomas White committed
328

329
	if ( outfile == NULL ) outfile = "za.pdf";
330
331
332
333
334
335
336
337
338

	if ( strcmp(outfile+strlen(outfile)-4, ".png") == 0 ) {
		png = 1;
		surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
		                                     wh, ht);
	} else {
		png = 0;
		surface = cairo_pdf_surface_create(outfile, wh, ht);
	}
339
340

	if ( cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS ) {
Thomas White's avatar
Thomas White committed
341
		ERROR("Couldn't create Cairo surface\n");
342
343
344
345
346
		cairo_surface_destroy(surface);
		return;
	}

	dctx = cairo_create(surface);
Thomas White's avatar
Thomas White committed
347
348
349
350
351
	if ( cairo_status(dctx) != CAIRO_STATUS_SUCCESS ) {
		ERROR("Couldn't create Cairo context\n");
		cairo_surface_destroy(surface);
		return;
	}
352
353
354
355
356
357
358
359
360
361
362
363
364
365

	/* 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);

	/* Test size of text that goes to the right(ish) */
	cairo_set_font_size(dctx, 40.0);
	snprintf(tmp, 255, "%i%i%i", abs(xh), abs(xk), abs(xl));
	cairo_text_extents(dctx, tmp, &size);

	cx = 532.0 - size.width;
	cy = 512.0 - 20.0;

366
	draw_circles(xh, xk, xl, yh, yk, yl, zh, zk, zl,
Thomas White's avatar
Thomas White committed
367
	             list, sym, dctx, wght, boost, colscale, cell,
368
369
	             max_r, theta, as, bs, cx, cy, scale,
	             NULL, NULL, &max_val, NULL, NULL, NULL);
370

Thomas White's avatar
Thomas White committed
371
	/* Centre marker */
372
373
	cairo_arc(dctx, (double)cx,
			(double)cy, max_r, 0, 2*M_PI);
Thomas White's avatar
Thomas White committed
374
375
376
	cairo_set_source_rgb(dctx, 1.0, 0.0, 0.0);
	cairo_fill(dctx);

377
	/* Draw indexing lines */
378
	cairo_set_line_cap(dctx, CAIRO_LINE_CAP_ROUND);
379
	cairo_set_line_width(dctx, 4.0);
380
	cairo_move_to(dctx, (double)cx, (double)cy);
381
382
	u = (2.0+max_ux)*as*sin(theta);
	v = (2.0+max_ux)*as*cos(theta);
383
	cairo_line_to(dctx, cx+u*scale, cy+v*scale);
384
385
386
	cairo_set_source_rgb(dctx, 0.0, 1.0, 0.0);
	cairo_stroke(dctx);

387
	cairo_set_font_size(dctx, 40.0);
388
	snprintf(tmp, 255, "%i%i%i", abs(xh), abs(xk), abs(xl));
389
390
391
	cairo_text_extents(dctx, tmp, &size);

	cairo_move_to(dctx, cx+u*scale + 20.0, cy+v*scale + size.height/2.0);
392
	render_overlined_indices(dctx, xh, xk, xl);
393
394
	cairo_fill(dctx);

395
	snprintf(tmp, 255, "%i%i%i", abs(yh), abs(yk), abs(yl));
396
397
398
	cairo_text_extents(dctx, tmp, &size);

	cairo_move_to(dctx, (double)cx, (double)cy);
399
	u = 0.0;
400
	v = (2.0+max_uy)*bs;
401
	cairo_line_to(dctx, cx+u*scale, cy+v*scale);
402
403
404
	cairo_set_source_rgb(dctx, 0.0, 1.0, 0.0);
	cairo_stroke(dctx);

405
406
	cairo_move_to(dctx, cx+u*scale - size.width/2.0,
	                    cy+v*scale + size.height + 20.0);
407
	render_overlined_indices(dctx, yh, yk, yl);
408
409
	cairo_fill(dctx);

410
411
412
413
414
415
416
	if ( png ) {
		int r = cairo_surface_write_to_png(surface, outfile);
		if ( r != CAIRO_STATUS_SUCCESS ) {
			ERROR("Failed to write PNG to '%s'\n", outfile);
		}
	}

Thomas White's avatar
Thomas White committed
417
418
419
	cairo_surface_finish(surface);
	cairo_destroy(dctx);
}
420

421

422
static int render_key(int colscale, double scale_top)
423
424
425
{
	cairo_surface_t *surface;
	cairo_t *dctx;
426
427
	double top, wh, ht, y;
	double slice;
428

429
430
431
432
433
434
435
436
437
	wh = 128.0;
	ht = 1024.0;
	slice = 1.0;

	if ( scale_top > 0.0 ) {
		top = scale_top;
	} else {
		top = 1.0;
	}
438

439
	surface = cairo_pdf_surface_create(KEY_FILENAME, wh, ht);
440
441
442
443
444
445
446
447
448

	if ( cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS ) {
		fprintf(stderr, "Couldn't create Cairo surface\n");
		cairo_surface_destroy(surface);
		return 1;
	}

	dctx = cairo_create(surface);

449
	for ( y=0.0; y<ht; y+=slice ) {
450

451
452
453
		double r, g, b;
		double val;
		double v = y;
454

455
456
457
458
459
460
461
462
463
464
465
		cairo_rectangle(dctx, 0.0, ht-y, wh/2.0, slice);

		if ( colscale == SCALE_RATIO ) {
			if ( v < ht/2.0 ) {
				val = v/(ht/2.0);
			} else {
				val = (((v-ht/2.0)/(ht/2.0))*(top-1.0))+1.0;
			}
		} else {
			val = v/ht;
		}
466

467
		render_scale(val, top, colscale, &r, &g, &b);
468
469
		cairo_set_source_rgb(dctx, r, g, b);

470
		cairo_stroke_preserve(dctx);
471
472
473
474
		cairo_fill(dctx);

	}

475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
	if ( colscale == SCALE_RATIO ) {

		cairo_text_extents_t size;
		char tmp[32];

		cairo_rectangle(dctx, 0.0, ht/2.0-2.0, wh/2.0, 4.0);
		cairo_set_source_rgb(dctx, 0.0, 0.0, 0.0);
		cairo_stroke_preserve(dctx);
		cairo_fill(dctx);

		cairo_set_font_size(dctx, 20.0);
		cairo_text_extents(dctx, "1.0", &size);
		cairo_move_to(dctx, wh/2.0+5.0, ht/2.0+size.height/2.0);
		cairo_show_text(dctx, "1.0");

		cairo_set_font_size(dctx, 20.0);
		cairo_text_extents(dctx, "0.0", &size);
		cairo_move_to(dctx, wh/2.0+5.0, ht-5.0);
		cairo_show_text(dctx, "0.0");

		cairo_set_font_size(dctx, 20.0);
		snprintf(tmp, 31, "%.1f", top);
		cairo_text_extents(dctx, tmp, &size);
		cairo_move_to(dctx, wh/2.0+5.0, size.height+5.0);
		cairo_show_text(dctx, tmp);

	}


504
505
506
	cairo_surface_finish(surface);
	cairo_destroy(dctx);

507
508
	STATUS("Colour key written to "KEY_FILENAME"\n");

509
510
	return 0;
}
511
512
513
514
515


#else  /* HAVE_CAIRO */


516
static int render_key(int colscale, double scale_top)
517
518
519
520
521
522
523
524
{
	ERROR("This version of CrystFEL was compiled without Cairo");
	ERROR(" support, which is required to draw the colour");
	ERROR(" scale.  Sorry!\n");
	return 1;
}


525
static void render_za(UnitCell *cell, RefList *list,
526
527
528
                      double boost, const char *sym, int wght, int colscale,
                      signed int xh, signed int xk, signed int xl,
                      signed int yh, signed int yk, signed int yl,
529
                      const char *outfile, double scale_top)
530
531
532
533
534
535
536
537
{
	ERROR("This version of CrystFEL was compiled without Cairo");
	ERROR(" support, which is required to plot a zone axis");
	ERROR(" pattern.  Sorry!\n");
}


#endif /* HAVE_CAIRO */
Thomas White's avatar
Thomas White committed
538
539
540
541
542
543


int main(int argc, char *argv[])
{
	int c;
	UnitCell *cell;
Thomas White's avatar
Thomas White committed
544
	RefList *list;
Thomas White's avatar
Thomas White committed
545
546
547
	char *infile;
	int config_povray = 0;
	int config_zoneaxis = 0;
Thomas White's avatar
Thomas White committed
548
	int config_sqrt = 0;
549
	int config_colkey = 0;
Thomas White's avatar
Thomas White committed
550
	unsigned int nproc = 1;
551
	char *pdb = NULL;
552
	int r = 0;
553
	double boost = 1.0;
554
	char *sym = NULL;
555
556
	char *weighting = NULL;
	int wght;
557
558
	int colscale;
	char *cscale = NULL;
559
560
561
562
	signed int dh=1, dk=0, dl=0;
	signed int rh=0, rk=1, rl=0;
	char *down = NULL;
	char *right = NULL;
563
	char *outfile = NULL;
564
565
	double scale_top = -1.0;
	char *endptr;
Thomas White's avatar
Thomas White committed
566
567
568
569
570
571

	/* Long options */
	const struct option longopts[] = {
		{"help",               0, NULL,               'h'},
		{"povray",             0, &config_povray,      1},
		{"zone-axis",          0, &config_zoneaxis,    1},
572
		{"output",             1, NULL,               'o'},
573
		{"pdb",                1, NULL,               'p'},
574
		{"boost",              1, NULL,               'b'},
575
		{"symmetry",           1, NULL,               'y'},
576
		{"weighting",          1, NULL,               'w'},
577
		{"colscale",           1, NULL,               'c'},
578
579
		{"down",               1, NULL,               'd'},
		{"right",              1, NULL,               'r'},
580
		{"counts",             0, &config_sqrt,        1},
581
		{"colour-key",         0, &config_colkey,      1},
582
		{"scale-top",          1, NULL,                2},
Thomas White's avatar
Thomas White committed
583
584
585
586
		{0, 0, NULL, 0}
	};

	/* Short options */
587
	while ((c = getopt_long(argc, argv, "hj:p:w:c:y:d:r:o:",
588
	                        longopts, NULL)) != -1) {
Thomas White's avatar
Thomas White committed
589
590

		switch (c) {
Thomas White's avatar
Thomas White committed
591
		case 'h' :
Thomas White's avatar
Thomas White committed
592
593
594
			show_help(argv[0]);
			return 0;

Thomas White's avatar
Thomas White committed
595
		case 'j' :
Thomas White's avatar
Thomas White committed
596
597
598
			nproc = atoi(optarg);
			break;

599
600
601
602
		case 'p' :
			pdb = strdup(optarg);
			break;

603
604
605
606
		case 'b' :
			boost = atof(optarg);
			break;

607
608
609
610
		case 'y' :
			sym = strdup(optarg);
			break;

611
612
613
614
		case 'w' :
			weighting = strdup(optarg);
			break;

615
616
617
618
		case 'c' :
			cscale = strdup(optarg);
			break;

619
620
621
622
623
624
625
626
		case 'd' :
			down = strdup(optarg);
			break;

		case 'r' :
			right = strdup(optarg);
			break;

627
628
629
630
		case 'o' :
			outfile = strdup(optarg);
			break;

631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
		case 2 :
			errno = 0;
			scale_top = strtod(optarg, &endptr);
			if ( !( (optarg[0] != '\0') && (endptr[0] == '\0') )
			   || (errno != 0) )
			{
				ERROR("Invalid scale top('%s')\n", optarg);
				return 1;
			}
			if ( scale_top < 0.0 ) {
				ERROR("Scale top must be positive.\n");
				return 1;
			}
			break;

Thomas White's avatar
Thomas White committed
646
		case 0 :
Thomas White's avatar
Thomas White committed
647
648
			break;

Thomas White's avatar
Thomas White committed
649
		default :
Thomas White's avatar
Thomas White committed
650
651
652
653
654
			return 1;
		}

	}

655
656
657
	if ( (pdb == NULL) && !config_colkey ) {
		ERROR("You must specify the PDB containing the unit cell.\n");
		return 1;
658
659
	}

660
661
662
663
	if ( sym == NULL ) {
		sym = strdup("1");
	}

664
665
666
667
668
669
670
671
672
673
	if ( weighting == NULL ) {
		weighting = strdup("I");
	}

	if ( strcmp(weighting, "I") == 0 ) {
		wght = WGHT_I;
	} else if ( strcmp(weighting, "sqrtI") == 0 ) {
		wght = WGHT_SQRTI;
	} else if ( strcmp(weighting, "count") == 0 ) {
		wght = WGHT_COUNTS;
674
675
	} else if ( strcmp(weighting, "counts") == 0 ) {
		wght = WGHT_COUNTS;
676
677
	} else if ( strcmp(weighting, "rawcts") == 0 ) {
		wght = WGHT_RAWCOUNTS;
678
679
680
681
	} else if ( strcmp(weighting, "rawcount") == 0 ) {
		wght = WGHT_RAWCOUNTS;
	} else if ( strcmp(weighting, "rawcounts") == 0 ) {
		wght = WGHT_RAWCOUNTS;
682
683
684
685
	} else {
		ERROR("Unrecognised weighting '%s'\n", weighting);
		return 1;
	}
686
687
688
689
690
691
692
693
694
695
696
697
698
699
	free(weighting);

	if ( cscale == NULL ) {
		cscale = strdup("mono");
	}

	if ( strcmp(cscale, "mono") == 0 ) {
		colscale = SCALE_MONO;
	} else if ( strcmp(cscale, "invmono") == 0 ) {
		colscale = SCALE_INVMONO;
	} else if ( strcmp(cscale, "colour") == 0 ) {
		colscale = SCALE_COLOUR;
	} else if ( strcmp(cscale, "color") == 0 ) {
		colscale = SCALE_COLOUR;
700
701
	} else if ( strcmp(cscale, "ratio") == 0 ) {
		colscale = SCALE_RATIO;
702
703
704
705
706
	} else {
		ERROR("Unrecognised colour scale '%s'\n", cscale);
		return 1;
	}
	free(cscale);
707

708
	if ( config_colkey ) {
709
		return render_key(colscale, scale_top);
710
711
	}

712
713
714
	if ( config_zoneaxis ) {
		if ( (( down == NULL ) && ( right != NULL ))
		  || (( down != NULL ) && ( right == NULL )) ) {
Thomas White's avatar
Thomas White committed
715
716
			ERROR("Either specify both 'down' and 'right',"
			      " or neither.\n");
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
			return 1;
		}
		if ( down != NULL ) {
			int r;
			r = sscanf(down, "%i,%i,%i", &dh, &dk, &dl);
			if ( r != 3 ) {
				ERROR("Invalid format for 'down'\n");
				return 1;
			}
		}
		if ( right != NULL ) {
			int r;
			r = sscanf(right, "%i,%i,%i", &rh, &rk, &rl);
			if ( r != 3 ) {
				ERROR("Invalid format for 'right'\n");
				return 1;
			}
		}
	}

Thomas White's avatar
Thomas White committed
737
738
	infile = argv[optind];

739
	cell = load_cell_from_pdb(pdb);
740
741
742
743
	if ( cell == NULL ) {
		ERROR("Couldn't load unit cell from %s\n", pdb);
		return 1;
	}
Thomas White's avatar
Thomas White committed
744
745
746
	list = read_reflections(infile);
	if ( list == NULL ) {
		ERROR("Couldn't read file '%s'\n", infile);
Thomas White's avatar
Thomas White committed
747
748
		return 1;
	}
Thomas White's avatar
Thomas White committed
749
	if ( check_list_symmetry(list, sym) ) {
Thomas White's avatar
Thomas White committed
750
751
752
753
		ERROR("The input reflection list does not appear to"
		      " have symmetry %s\n", sym);
		return 1;
	}
Thomas White's avatar
Thomas White committed
754
755

	if ( config_povray ) {
Thomas White's avatar
Thomas White committed
756
		r = povray_render_animation(cell, list,
757
		                            nproc, sym, wght, boost, scale_top);
Thomas White's avatar
Thomas White committed
758
	} else if ( config_zoneaxis ) {
Thomas White's avatar
Thomas White committed
759
		render_za(cell, list, boost, sym, wght, colscale,
760
		          rh, rk, rl, dh, dk, dl, outfile, scale_top);
Thomas White's avatar
Thomas White committed
761
762
763
764
	} else {
		ERROR("Try again with either --povray or --zone-axis.\n");
	}

765
	free(pdb);
766
	free(sym);
Thomas White's avatar
Thomas White committed
767
	reflist_free(list);
768
	if ( outfile != NULL ) free(outfile);
769

770
	return r;
771
}