render_hkl.c 18 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
27
28
29
/* GSL is only used if Cairo is present */
#include <gsl/gsl_matrix.h>
#include <gsl/gsl_blas.h>
#include <gsl/gsl_linalg.h>
30
#endif
31
32
33

#include "utils.h"
#include "reflections.h"
34
#include "povray.h"
35
#include "symmetry.h"
36
#include "render.h"
37

38
39
40
41
enum {
	WGHT_I,
	WGHT_SQRTI,
	WGHT_COUNTS,
42
	WGHT_RAWCOUNTS,
43
};
44

45
46
47
48
static void show_help(const char *s)
{
	printf("Syntax: %s [options] <file.hkl>\n\n", s);
	printf(
49
"Render intensity lists in various ways.\n"
50
"\n"
51
"      --povray            Render a 3D animation using POV-ray.\n"
52
#ifdef HAVE_CAIRO
53
"      --zone-axis         Render a 2D zone axis pattern.\n"
54
#endif
55
"\n"
56
57
58
"  -d, --down=<h>,<k>,<l>  Indices for the axis in the downward direction.\n"
"  -r, --right=<h>,<k>,<l> Indices for the axis in the 'right' (roughly)\n"
"                           direction.\n"
59
60
61
"      --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"
62
63
64
65
66
67
68
"\n"
"  -c, --colscale=<scale>  Use the given colour scale.  Choose from:\n"
"                           mono    : Greyscale, black is zero.\n"
"                           invmono : Greyscale, white is zero.\n"
"                           colour  : Colours scale:\n"
"                                     black-blue-pink-red-orange-yellow-white\n"
"\n"
69
70
"  -w  --weighting=<wght>  Colour/shade the reciprocal lattice points\n"
"                           according to:\n"
71
72
73
74
75
76
"                            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"
77
78
79
80
"\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"
81
);
82
83
84
}


85
#ifdef HAVE_CAIRO
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
static int get_basis_change_coefficients(double *in, double *out)
{
	int s;
	gsl_matrix *m;
	gsl_matrix *inv;
	gsl_permutation *perm;

	m = gsl_matrix_alloc(3, 3);
	if ( m == NULL ) {
		ERROR("Couldn't allocate memory for matrix\n");
		return 1;
	}
	gsl_matrix_set(m, 0, 0, in[0]);
	gsl_matrix_set(m, 0, 1, in[1]);
	gsl_matrix_set(m, 0, 2, in[2]);
	gsl_matrix_set(m, 1, 0, in[3]);
	gsl_matrix_set(m, 1, 1, in[4]);
	gsl_matrix_set(m, 1, 2, in[5]);
	gsl_matrix_set(m, 2, 0, in[6]);
	gsl_matrix_set(m, 2, 1, in[7]);
	gsl_matrix_set(m, 2, 2, in[8]);

	/* Invert */
	perm = gsl_permutation_alloc(m->size1);
	if ( perm == NULL ) {
		ERROR("Couldn't allocate permutation\n");
		gsl_matrix_free(m);
		return 1;
	}
	inv = gsl_matrix_alloc(3, 3);
	if ( inv == NULL ) {
		ERROR("Couldn't allocate inverse\n");
		gsl_matrix_free(m);
		gsl_permutation_free(perm);
		return 1;
	}
	if ( gsl_linalg_LU_decomp(m, perm, &s) ) {
		ERROR("Couldn't decompose matrix\n");
		gsl_matrix_free(m);
		gsl_permutation_free(perm);
		return 1;
	}
	if ( gsl_linalg_LU_invert(m, perm, inv)  ) {
		ERROR("Couldn't invert matrix\n");
		gsl_matrix_free(m);
		gsl_permutation_free(perm);
		return 1;
	}
	gsl_permutation_free(perm);
	gsl_matrix_free(m);

	/* Transpose */
	gsl_matrix_transpose(inv);

	out[0] = gsl_matrix_get(inv, 0, 0);
	out[1] = gsl_matrix_get(inv, 0, 1);
	out[2] = gsl_matrix_get(inv, 0, 2);
	out[3] = gsl_matrix_get(inv, 1, 0);
	out[4] = gsl_matrix_get(inv, 1, 1);
	out[5] = gsl_matrix_get(inv, 1, 2);
	out[6] = gsl_matrix_get(inv, 2, 0);
	out[7] = gsl_matrix_get(inv, 2, 1);
	out[8] = gsl_matrix_get(inv, 2, 2);

	gsl_matrix_free(inv);

	return 0;

}


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,
                         double *ref, unsigned int *counts, ReflItemList *items,
                         const char *sym,
                         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;
	double in[9];
	double bc[9];

	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;
	}

	in[0] = xh;  in[1] = xk;  in[2] = xl;
	in[3] = yh;  in[4] = yk;  in[5] = yl;
	in[6] = zh;  in[7] = zk;  in[8] = zl;
	if ( get_basis_change_coefficients(in, bc) ) {
		ERROR("Couldn't change basis.\n");
		return;
	}

	/* Loop across the two basis directions */
	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
193
		signed int he, ke, le;
194
195
196
197
198
199

		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
200
201
		if ( find_unique_equiv(items, h, k, l, sym,
		                       &he, &ke, &le) == 0 ) continue;
202
203
204

		switch ( wght ) {
		case WGHT_I :
Thomas White's avatar
Thomas White committed
205
			val = lookup_intensity(ref, he, ke, le);
206
207
			break;
		case WGHT_SQRTI :
Thomas White's avatar
Thomas White committed
208
			val = lookup_intensity(ref, he, ke, le);
209
210
211
			val = (val>0.0) ? sqrt(val) : 0.0;
			break;
		case WGHT_COUNTS :
Thomas White's avatar
Thomas White committed
212
213
			val = lookup_count(counts, he, ke, le);
			val /= (float)num_equivs(he, ke, le, sym);
214
215
			break;
		case WGHT_RAWCOUNTS :
Thomas White's avatar
Thomas White committed
216
			val = lookup_count(counts, he, ke, le);
217
218
219
220
221
222
			break;
		default :
			ERROR("Invalid weighting.\n");
			abort();
		}

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

227
		if ( dctx != NULL ) {
228

229
			float r, g, b;
230

231
232
233
			cairo_arc(dctx, ((double)cx)+u*scale,
			                ((double)cy)+v*scale,
			                radius, 0, 2*M_PI);
234

235
236
237
238
			render_scale(val, *max_val/boost, colscale,
			             &r, &g, &b);
			cairo_set_source_rgb(dctx, r, g, b);
			cairo_fill(dctx);
239

240
		} else {
241

242
243
244
			/* 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);
245

246
247
248
			/* Find max value for colour scale */
			if ( fabs(val) > fabs(*max_val) ) {
				*max_val = fabs(val);
249
250
			}

251
			/* Find max indices */
Thomas White's avatar
Thomas White committed
252
253
254
255
			if ( (yi==0) && (fabs(xi) > *max_ux) )
				*max_ux = fabs(xi);
			if ( (xi==0) && (fabs(yi) > *max_uy) )
				*max_uy = fabs(yi);
256
257

			/* Find max resolution */
Thomas White's avatar
Thomas White committed
258
			res = resolution(cell, h, k, l);
259
			if ( res > *max_res ) *max_res = res;
260
261
262
263
264
265
266
		}

	}
	}
}


267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
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);
	}
}


317
static void render_za(UnitCell *cell, ReflItemList *items,
318
                      double *ref, unsigned int *counts,
319
320
321
                      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)
322
{
Thomas White's avatar
Thomas White committed
323
324
	cairo_surface_t *surface;
	cairo_t *dctx;
325
	double max_u, max_v, max_res, max_val;
326
	double scale_u, scale_v, scale;
Thomas White's avatar
Thomas White committed
327
	double sep_u, sep_v, max_r;
328
	double u, v;
329
	signed int max_ux, max_uy;
Thomas White's avatar
Thomas White committed
330
	double as, bs, theta;
331
332
333
	double asx, asy, asz;
	double bsx, bsy, bsz;
	double csx, csy, csz;
Thomas White's avatar
Thomas White committed
334
	float wh, ht;
335
336
337
338
339
340
341
342
	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;

343
	/* Vector product to determine the zone axis. */
344
345
346
347
	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);
348

349
	/* Size of output and centre definition */
Thomas White's avatar
Thomas White committed
350
351
	wh = 1024;
	ht = 1024;
352

Thomas White's avatar
Thomas White committed
353
	/* Work out reciprocal lattice spacings and angles for this cut */
354
	if ( cell_get_reciprocal(cell, &asx, &asy, &asz,
Thomas White's avatar
Thomas White committed
355
	                          &bsx, &bsy, &bsz,
356
357
358
359
	                          &csx, &csy, &csz) ) {
		ERROR("Couldn't get reciprocal parameters\n");
		return;
	}
360
361
362
363
364
365
366
367
368
369
	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;

370
	scale = 1.0;
371
372
373
374
	draw_circles(xh, xk, xl, yh, yk, yl, zh, zk, zl,
	             ref, counts, items, sym, NULL, wght, boost, colscale, cell,
	             0.0, theta, as, bs, cx, cy, scale,
	             &max_ux, &max_uy, &max_val, &max_u, &max_v, &max_res);
375

Thomas White's avatar
Thomas White committed
376
	max_res /= 1e9;
377
378
	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
379

380
	if ( max_val <= 0.0 ) {
Thomas White's avatar
Thomas White committed
381
		max_r = 4.0;
382
		STATUS("Couldn't find max value.\n");
Thomas White's avatar
Thomas White committed
383
		goto out;
384
385
	}

Thomas White's avatar
Thomas White committed
386
	/* Choose whichever scaling factor gives the smallest value */
387
388
	scale_u = ((double)wh-border) / (2.0*max_u);
	scale_v = ((double)ht-border) / (2.0*max_v);
389
	scale = (scale_u < scale_v) ? scale_u : scale_v;
390

391
392
	sep_u = scale*as;
	sep_v = scale*bs;
393
	/* We are interested in the smaller of the two separations */
394
	max_r = (sep_u < sep_v) ? sep_u : sep_v;
395
	max_r /= 2.0;  /* Max radius is half the separation */
396
	max_r -= 1.0;  /* Add a tiny separation between circles */
397
398
399
	if ( max_r < 1.0 ) {
		ERROR("Circle radius is probably too small (%f).\n", max_r);
	}
Thomas White's avatar
Thomas White committed
400

401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
	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);

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

424
425
426
427
	draw_circles(xh, xk, xl, yh, yk, yl, zh, zk, zl,
	             ref, counts, items, sym, dctx, wght, boost, colscale, cell,
	             max_r, theta, as, bs, cx, cy, scale,
	             NULL, NULL, &max_val, NULL, NULL, NULL);
428

Thomas White's avatar
Thomas White committed
429
430
out:
	/* Centre marker */
431
432
	cairo_arc(dctx, (double)cx,
			(double)cy, max_r, 0, 2*M_PI);
Thomas White's avatar
Thomas White committed
433
434
435
	cairo_set_source_rgb(dctx, 1.0, 0.0, 0.0);
	cairo_fill(dctx);

436
	/* Draw indexing lines */
437
	cairo_set_line_cap(dctx, CAIRO_LINE_CAP_ROUND);
438
	cairo_set_line_width(dctx, 4.0);
439
	cairo_move_to(dctx, (double)cx, (double)cy);
440
441
	u = (2.0+max_ux)*as*sin(theta);
	v = (2.0+max_ux)*as*cos(theta);
442
	cairo_line_to(dctx, cx+u*scale, cy+v*scale);
443
444
445
	cairo_set_source_rgb(dctx, 0.0, 1.0, 0.0);
	cairo_stroke(dctx);

446
	cairo_set_font_size(dctx, 40.0);
447
	snprintf(tmp, 255, "%i%i%i", abs(xh), abs(xk), abs(xl));
448
449
450
	cairo_text_extents(dctx, tmp, &size);

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

454
	snprintf(tmp, 255, "%i%i%i", abs(yh), abs(yk), abs(yl));
455
456
457
	cairo_text_extents(dctx, tmp, &size);

	cairo_move_to(dctx, (double)cx, (double)cy);
458
	u = 0.0;
459
	v = (2.0+max_uy)*bs;
460
	cairo_line_to(dctx, cx+u*scale, cy+v*scale);
461
462
463
	cairo_set_source_rgb(dctx, 0.0, 1.0, 0.0);
	cairo_stroke(dctx);

464
465
	cairo_move_to(dctx, cx+u*scale - size.width/2.0,
	                    cy+v*scale + size.height + 20.0);
466
	render_overlined_indices(dctx, yh, yk, yl);
467
468
	cairo_fill(dctx);

Thomas White's avatar
Thomas White committed
469
470
471
	cairo_surface_finish(surface);
	cairo_destroy(dctx);
}
472

473

474
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
504
505
506
507
508
509
510
511
static int render_key(int colscale)
{
	cairo_surface_t *surface;
	cairo_t *dctx;
	float wh, ht;
	float y;

	wh = 128;
	ht = 1024;

	surface = cairo_pdf_surface_create("key.pdf", wh, ht);

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

	for ( y=0; y<ht; y++ ) {

		float r, g, b;

		cairo_rectangle(dctx, 0.0, y, wh, y+1.0);

		render_scale(ht-y, ht, colscale, &r, &g, &b);
		cairo_set_source_rgb(dctx, r, g, b);

		cairo_fill(dctx);

	}

	cairo_surface_finish(surface);
	cairo_destroy(dctx);

	return 0;
}
512
#endif
Thomas White's avatar
Thomas White committed
513
514
515
516
517
518
519
520
521
522


int main(int argc, char *argv[])
{
	int c;
	UnitCell *cell;
	char *infile;
	double *ref;
	int config_povray = 0;
	int config_zoneaxis = 0;
Thomas White's avatar
Thomas White committed
523
	int config_sqrt = 0;
524
	int config_colkey = 0;
Thomas White's avatar
Thomas White committed
525
	unsigned int nproc = 1;
526
	char *pdb = NULL;
527
	int r = 0;
528
	double boost = 1.0;
529
	char *sym = NULL;
530
531
	char *weighting = NULL;
	int wght;
532
533
	int colscale;
	char *cscale = NULL;
Thomas White's avatar
Thomas White committed
534
	unsigned int *cts;
535
536
537
538
	signed int dh=1, dk=0, dl=0;
	signed int rh=0, rk=1, rl=0;
	char *down = NULL;
	char *right = NULL;
Thomas White's avatar
Thomas White committed
539
540
541
542
543
544

	/* Long options */
	const struct option longopts[] = {
		{"help",               0, NULL,               'h'},
		{"povray",             0, &config_povray,      1},
		{"zone-axis",          0, &config_zoneaxis,    1},
545
		{"pdb",                1, NULL,               'p'},
546
		{"boost",              1, NULL,               'b'},
547
		{"symmetry",           1, NULL,               'y'},
548
		{"weighting",          1, NULL,               'w'},
549
		{"colscale",           1, NULL,               'c'},
550
551
		{"down",               1, NULL,               'd'},
		{"right",              1, NULL,               'r'},
552
		{"counts",             0, &config_sqrt,        1},
553
		{"colour-key",         0, &config_colkey,      1},
Thomas White's avatar
Thomas White committed
554
555
556
557
		{0, 0, NULL, 0}
	};

	/* Short options */
558
	while ((c = getopt_long(argc, argv, "hj:p:w:c:y:d:r:",
559
	                        longopts, NULL)) != -1) {
Thomas White's avatar
Thomas White committed
560
561

		switch (c) {
Thomas White's avatar
Thomas White committed
562
		case 'h' :
Thomas White's avatar
Thomas White committed
563
564
565
			show_help(argv[0]);
			return 0;

Thomas White's avatar
Thomas White committed
566
		case 'j' :
Thomas White's avatar
Thomas White committed
567
568
569
			nproc = atoi(optarg);
			break;

570
571
572
573
		case 'p' :
			pdb = strdup(optarg);
			break;

574
575
576
577
		case 'b' :
			boost = atof(optarg);
			break;

578
579
580
581
		case 'y' :
			sym = strdup(optarg);
			break;

582
583
584
585
		case 'w' :
			weighting = strdup(optarg);
			break;

586
587
588
589
		case 'c' :
			cscale = strdup(optarg);
			break;

590
591
592
593
594
595
596
597
		case 'd' :
			down = strdup(optarg);
			break;

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

Thomas White's avatar
Thomas White committed
598
		case 0 :
Thomas White's avatar
Thomas White committed
599
600
			break;

Thomas White's avatar
Thomas White committed
601
		default :
Thomas White's avatar
Thomas White committed
602
603
604
605
606
			return 1;
		}

	}

607
608
609
610
	if ( pdb == NULL ) {
		pdb = strdup("molecule.pdb");
	}

611
612
613
614
	if ( sym == NULL ) {
		sym = strdup("1");
	}

615
616
617
618
619
620
621
622
623
624
	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;
625
626
	} else if ( strcmp(weighting, "counts") == 0 ) {
		wght = WGHT_COUNTS;
627
628
	} else if ( strcmp(weighting, "rawcts") == 0 ) {
		wght = WGHT_RAWCOUNTS;
629
630
631
632
	} else if ( strcmp(weighting, "rawcount") == 0 ) {
		wght = WGHT_RAWCOUNTS;
	} else if ( strcmp(weighting, "rawcounts") == 0 ) {
		wght = WGHT_RAWCOUNTS;
633
634
635
636
	} else {
		ERROR("Unrecognised weighting '%s'\n", weighting);
		return 1;
	}
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
	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;
	} else {
		ERROR("Unrecognised colour scale '%s'\n", cscale);
		return 1;
	}
	free(cscale);
656

657
658
659
660
	if ( config_colkey ) {
		return render_key(colscale);
	}

661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
	if ( config_zoneaxis ) {
		if ( (( down == NULL ) && ( right != NULL ))
		  || (( down != NULL ) && ( right == NULL )) ) {
			ERROR("Either specify both 'down' and 'right', or neither.\n");
			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
685
686
	infile = argv[optind];

687
	cell = load_cell_from_pdb(pdb);
688
689
690
691
	if ( cell == NULL ) {
		ERROR("Couldn't load unit cell from %s\n", pdb);
		return 1;
	}
Thomas White's avatar
Thomas White committed
692
	ref = new_list_intensity();
Thomas White's avatar
Thomas White committed
693
	cts = new_list_count();
Thomas White's avatar
Thomas White committed
694
	ReflItemList *items = read_reflections(infile, ref, NULL, cts);
Thomas White's avatar
Thomas White committed
695
696
697
698
699
700
	if ( ref == NULL ) {
		ERROR("Couldn't open file '%s'\n", infile);
		return 1;
	}

	if ( config_povray ) {
701
		r = povray_render_animation(cell, ref, cts, nproc);
Thomas White's avatar
Thomas White committed
702
	} else if ( config_zoneaxis ) {
703
#ifdef HAVE_CAIRO
704
705
		render_za(cell, items, ref, cts, boost, sym, wght, colscale,
		          rh, rk, rl, dh, dk, dl);
706
707
708
709
710
#else
		ERROR("This version of CrystFEL was compiled without Cairo");
		ERROR(" support, which is required to plot a zone axis");
		ERROR(" pattern.  Sorry!\n");
#endif
Thomas White's avatar
Thomas White committed
711
712
713
714
	} else {
		ERROR("Try again with either --povray or --zone-axis.\n");
	}

715
	free(pdb);
716
	free(sym);
717
	delete_items(items);
718

719
	return r;
720
}