render_hkl.c 16.4 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
29

#include "utils.h"
#include "reflections.h"
30
#include "povray.h"
31
#include "symmetry.h"
32
#include "render.h"
33
#include "render_hkl.h"
34
35


36
37
38
39
static void show_help(const char *s)
{
	printf("Syntax: %s [options] <file.hkl>\n\n", s);
	printf(
40
"Render intensity lists in various ways.\n"
41
"\n"
42
"      --povray            Render a 3D animation using POV-ray.\n"
43
#ifdef HAVE_CAIRO
44
"      --zone-axis         Render a 2D zone axis pattern.\n"
45
#endif
46
"\n"
47
"  -d, --down=<h>,<k>,<l>  Indices for the axis in the downward direction.\n"
48
"                           Default: 1,0,0.\n"
49
"  -r, --right=<h>,<k>,<l> Indices for the axis in the 'right' (roughly)\n"
50
51
"                           direction.  Default: 0,1,0.\n"
"  -o, --output=<filename> Output filename (not for POV-ray).\n"
52
53
54
"      --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"
55
56
57
58
59
60
61
"\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"
62
63
"  -w  --weighting=<wght>  Colour/shade the reciprocal lattice points\n"
"                           according to:\n"
64
65
66
67
68
69
"                            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"
70
71
72
73
"\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"
74
);
75
76
77
}


78
#ifdef HAVE_CAIRO
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
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;

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

	/* 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
105
		signed int he, ke, le;
106
107
108
109
110
111

		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
112
113
		if ( find_unique_equiv(items, h, k, l, sym,
		                       &he, &ke, &le) == 0 ) continue;
114
115
116

		switch ( wght ) {
		case WGHT_I :
Thomas White's avatar
Thomas White committed
117
			val = lookup_intensity(ref, he, ke, le);
118
119
			break;
		case WGHT_SQRTI :
Thomas White's avatar
Thomas White committed
120
			val = lookup_intensity(ref, he, ke, le);
121
122
123
			val = (val>0.0) ? sqrt(val) : 0.0;
			break;
		case WGHT_COUNTS :
Thomas White's avatar
Thomas White committed
124
125
			val = lookup_count(counts, he, ke, le);
			val /= (float)num_equivs(he, ke, le, sym);
126
127
			break;
		case WGHT_RAWCOUNTS :
Thomas White's avatar
Thomas White committed
128
			val = lookup_count(counts, he, ke, le);
129
130
131
132
133
134
			break;
		default :
			ERROR("Invalid weighting.\n");
			abort();
		}

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

139
		if ( dctx != NULL ) {
140

141
			float r, g, b;
142

143
144
145
			cairo_arc(dctx, ((double)cx)+u*scale,
			                ((double)cy)+v*scale,
			                radius, 0, 2*M_PI);
146

147
148
149
150
			render_scale(val, *max_val/boost, colscale,
			             &r, &g, &b);
			cairo_set_source_rgb(dctx, r, g, b);
			cairo_fill(dctx);
151

152
		} else {
153

154
155
156
			/* 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);
157

158
159
160
			/* Find max value for colour scale */
			if ( fabs(val) > fabs(*max_val) ) {
				*max_val = fabs(val);
161
162
			}

163
			/* Find max indices */
Thomas White's avatar
Thomas White committed
164
165
166
167
			if ( (yi==0) && (fabs(xi) > *max_ux) )
				*max_ux = fabs(xi);
			if ( (xi==0) && (fabs(yi) > *max_uy) )
				*max_uy = fabs(yi);
168
169

			/* Find max resolution */
Thomas White's avatar
Thomas White committed
170
			res = resolution(cell, h, k, l);
171
			if ( res > *max_res ) *max_res = res;
172
173
174
175
176
177
178
		}

	}
	}
}


179
180
181
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
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);
	}
}


229
static void render_za(UnitCell *cell, ReflItemList *items,
230
                      double *ref, unsigned int *counts,
231
232
                      double boost, const char *sym, int wght, int colscale,
                      signed int xh, signed int xk, signed int xl,
233
234
                      signed int yh, signed int yk, signed int yl,
                      const char *outfile)
235
{
Thomas White's avatar
Thomas White committed
236
237
	cairo_surface_t *surface;
	cairo_t *dctx;
238
	double max_u, max_v, max_res, max_val;
239
	double scale_u, scale_v, scale;
Thomas White's avatar
Thomas White committed
240
	double sep_u, sep_v, max_r;
241
	double u, v;
242
	signed int max_ux, max_uy;
Thomas White's avatar
Thomas White committed
243
	double as, bs, theta;
244
245
246
	double asx, asy, asz;
	double bsx, bsy, bsz;
	double csx, csy, csz;
Thomas White's avatar
Thomas White committed
247
	float wh, ht;
248
249
250
251
252
253
254
255
	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;

256
	/* Vector product to determine the zone axis. */
257
258
259
260
	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);
261

262
	/* Size of output and centre definition */
Thomas White's avatar
Thomas White committed
263
264
	wh = 1024;
	ht = 1024;
265

Thomas White's avatar
Thomas White committed
266
	/* Work out reciprocal lattice spacings and angles for this cut */
267
	if ( cell_get_reciprocal(cell, &asx, &asy, &asz,
Thomas White's avatar
Thomas White committed
268
	                          &bsx, &bsy, &bsz,
269
270
271
272
	                          &csx, &csy, &csz) ) {
		ERROR("Couldn't get reciprocal parameters\n");
		return;
	}
273
274
275
276
277
278
279
280
281
282
	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;

283
	scale = 1.0;
284
285
	draw_circles(xh, xk, xl, yh, yk, yl, zh, zk, zl,
	             ref, counts, items, sym, NULL, wght, boost, colscale, cell,
Thomas White's avatar
Thomas White committed
286
	             0.0, theta, as, bs, 0.0, 0.0, scale,
287
	             &max_ux, &max_uy, &max_val, &max_u, &max_v, &max_res);
288

Thomas White's avatar
Thomas White committed
289
	max_res /= 1e9;
290
291
	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
292

293
	if ( max_val <= 0.0 ) {
294
		STATUS("Couldn't find max value.\n");
Thomas White's avatar
Thomas White committed
295
		return;
296
297
	}

Thomas White's avatar
Thomas White committed
298
	/* Choose whichever scaling factor gives the smallest value */
299
300
	scale_u = ((double)wh-border) / (2.0*max_u);
	scale_v = ((double)ht-border) / (2.0*max_v);
301
	scale = (scale_u < scale_v) ? scale_u : scale_v;
302

303
304
	sep_u = scale*as;
	sep_v = scale*bs;
305
	/* We are interested in the smaller of the two separations */
306
	max_r = (sep_u < sep_v) ? sep_u : sep_v;
307
	max_r /= 2.0;  /* Max radius is half the separation */
308
	max_r -= 1.0;  /* Add a tiny separation between circles */
309
310
311
	if ( max_r < 1.0 ) {
		ERROR("Circle radius is probably too small (%f).\n", max_r);
	}
Thomas White's avatar
Thomas White committed
312

313
314
	if ( outfile == NULL ) outfile = "za.pdf";
	surface = cairo_pdf_surface_create(outfile, wh, ht);
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336

	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;

337
338
339
340
	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);
341

Thomas White's avatar
Thomas White committed
342
	/* Centre marker */
343
344
	cairo_arc(dctx, (double)cx,
			(double)cy, max_r, 0, 2*M_PI);
Thomas White's avatar
Thomas White committed
345
346
347
	cairo_set_source_rgb(dctx, 1.0, 0.0, 0.0);
	cairo_fill(dctx);

348
	/* Draw indexing lines */
349
	cairo_set_line_cap(dctx, CAIRO_LINE_CAP_ROUND);
350
	cairo_set_line_width(dctx, 4.0);
351
	cairo_move_to(dctx, (double)cx, (double)cy);
352
353
	u = (2.0+max_ux)*as*sin(theta);
	v = (2.0+max_ux)*as*cos(theta);
354
	cairo_line_to(dctx, cx+u*scale, cy+v*scale);
355
356
357
	cairo_set_source_rgb(dctx, 0.0, 1.0, 0.0);
	cairo_stroke(dctx);

358
	cairo_set_font_size(dctx, 40.0);
359
	snprintf(tmp, 255, "%i%i%i", abs(xh), abs(xk), abs(xl));
360
361
362
	cairo_text_extents(dctx, tmp, &size);

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

366
	snprintf(tmp, 255, "%i%i%i", abs(yh), abs(yk), abs(yl));
367
368
369
	cairo_text_extents(dctx, tmp, &size);

	cairo_move_to(dctx, (double)cx, (double)cy);
370
	u = 0.0;
371
	v = (2.0+max_uy)*bs;
372
	cairo_line_to(dctx, cx+u*scale, cy+v*scale);
373
374
375
	cairo_set_source_rgb(dctx, 0.0, 1.0, 0.0);
	cairo_stroke(dctx);

376
377
	cairo_move_to(dctx, cx+u*scale - size.width/2.0,
	                    cy+v*scale + size.height + 20.0);
378
	render_overlined_indices(dctx, yh, yk, yl);
379
380
	cairo_fill(dctx);

Thomas White's avatar
Thomas White committed
381
382
383
	cairo_surface_finish(surface);
	cairo_destroy(dctx);
}
384

385

386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
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;
}
424
#endif
Thomas White's avatar
Thomas White committed
425
426
427
428
429
430
431
432
433
434


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
435
	int config_sqrt = 0;
436
	int config_colkey = 0;
Thomas White's avatar
Thomas White committed
437
	unsigned int nproc = 1;
438
	char *pdb = NULL;
439
	int r = 0;
440
	double boost = 1.0;
441
	char *sym = NULL;
442
443
	char *weighting = NULL;
	int wght;
444
445
	int colscale;
	char *cscale = NULL;
Thomas White's avatar
Thomas White committed
446
	unsigned int *cts;
447
448
449
450
	signed int dh=1, dk=0, dl=0;
	signed int rh=0, rk=1, rl=0;
	char *down = NULL;
	char *right = NULL;
451
	char *outfile = NULL;
Thomas White's avatar
Thomas White committed
452
453
454
455
456
457

	/* Long options */
	const struct option longopts[] = {
		{"help",               0, NULL,               'h'},
		{"povray",             0, &config_povray,      1},
		{"zone-axis",          0, &config_zoneaxis,    1},
458
		{"output",             1, NULL,               'o'},
459
		{"pdb",                1, NULL,               'p'},
460
		{"boost",              1, NULL,               'b'},
461
		{"symmetry",           1, NULL,               'y'},
462
		{"weighting",          1, NULL,               'w'},
463
		{"colscale",           1, NULL,               'c'},
464
465
		{"down",               1, NULL,               'd'},
		{"right",              1, NULL,               'r'},
466
		{"counts",             0, &config_sqrt,        1},
467
		{"colour-key",         0, &config_colkey,      1},
Thomas White's avatar
Thomas White committed
468
469
470
471
		{0, 0, NULL, 0}
	};

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

		switch (c) {
Thomas White's avatar
Thomas White committed
476
		case 'h' :
Thomas White's avatar
Thomas White committed
477
478
479
			show_help(argv[0]);
			return 0;

Thomas White's avatar
Thomas White committed
480
		case 'j' :
Thomas White's avatar
Thomas White committed
481
482
483
			nproc = atoi(optarg);
			break;

484
485
486
487
		case 'p' :
			pdb = strdup(optarg);
			break;

488
489
490
491
		case 'b' :
			boost = atof(optarg);
			break;

492
493
494
495
		case 'y' :
			sym = strdup(optarg);
			break;

496
497
498
499
		case 'w' :
			weighting = strdup(optarg);
			break;

500
501
502
503
		case 'c' :
			cscale = strdup(optarg);
			break;

504
505
506
507
508
509
510
511
		case 'd' :
			down = strdup(optarg);
			break;

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

512
513
514
515
		case 'o' :
			outfile = strdup(optarg);
			break;

Thomas White's avatar
Thomas White committed
516
		case 0 :
Thomas White's avatar
Thomas White committed
517
518
			break;

Thomas White's avatar
Thomas White committed
519
		default :
Thomas White's avatar
Thomas White committed
520
521
522
523
524
			return 1;
		}

	}

525
526
527
528
	if ( pdb == NULL ) {
		pdb = strdup("molecule.pdb");
	}

529
530
531
532
	if ( sym == NULL ) {
		sym = strdup("1");
	}

533
534
535
536
537
538
539
540
541
542
	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;
543
544
	} else if ( strcmp(weighting, "counts") == 0 ) {
		wght = WGHT_COUNTS;
545
546
	} else if ( strcmp(weighting, "rawcts") == 0 ) {
		wght = WGHT_RAWCOUNTS;
547
548
549
550
	} else if ( strcmp(weighting, "rawcount") == 0 ) {
		wght = WGHT_RAWCOUNTS;
	} else if ( strcmp(weighting, "rawcounts") == 0 ) {
		wght = WGHT_RAWCOUNTS;
551
552
553
554
	} else {
		ERROR("Unrecognised weighting '%s'\n", weighting);
		return 1;
	}
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
	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);
574

575
576
577
578
	if ( config_colkey ) {
		return render_key(colscale);
	}

579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
	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
603
604
	infile = argv[optind];

605
	cell = load_cell_from_pdb(pdb);
606
607
608
609
	if ( cell == NULL ) {
		ERROR("Couldn't load unit cell from %s\n", pdb);
		return 1;
	}
Thomas White's avatar
Thomas White committed
610
	ref = new_list_intensity();
Thomas White's avatar
Thomas White committed
611
	cts = new_list_count();
612
	ReflItemList *items = read_reflections(infile, ref, NULL, cts, NULL);
Thomas White's avatar
Thomas White committed
613
614
615
616
617
618
	if ( ref == NULL ) {
		ERROR("Couldn't open file '%s'\n", infile);
		return 1;
	}

	if ( config_povray ) {
619
620
		r = povray_render_animation(cell, ref, cts, items,
		                            nproc, sym, wght, boost);
Thomas White's avatar
Thomas White committed
621
	} else if ( config_zoneaxis ) {
622
#ifdef HAVE_CAIRO
623
		render_za(cell, items, ref, cts, boost, sym, wght, colscale,
624
		          rh, rk, rl, dh, dk, dl, outfile);
625
626
627
628
629
#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
630
631
632
633
	} else {
		ERROR("Try again with either --povray or --zone-axis.\n");
	}

634
	free(pdb);
635
	free(sym);
636
	delete_items(items);
637
	if ( outfile != NULL ) free(outfile);
638

639
	return r;
640
}