render_hkl.c 17.1 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
"\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
59
"                           colour  : Colour scale:\n"
60
61
"                                     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
"                            I      : the intensity of the reflection.\n"
"                            sqrtI  : the square root of the intensity.\n"
Thomas White's avatar
Thomas White committed
66
"                            count  : the number of measurements for the reflection.\n"
67
"                                     (after correcting for 'epsilon')\n"
Thomas White's avatar
Thomas White committed
68
"                            rawcts : the raw number of measurements for the\n"
69
"                                     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
105
106
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
107
		signed int he, ke, le;
108
109
110
111
112
113

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

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

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

141
		if ( dctx != NULL ) {
142

143
			float r, g, b;
144

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

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

154
		} else {
155

156
157
158
			/* 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);
159

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

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

			/* Find max resolution */
Thomas White's avatar
Thomas White committed
172
			res = resolution(cell, h, k, l);
173
			if ( res > *max_res ) *max_res = res;
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
229
230
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);
	}
}


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

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

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

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

285
	scale = 1.0;
286
287
	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
288
	             0.0, theta, as, bs, 0.0, 0.0, scale,
289
	             &max_ux, &max_uy, &max_val, &max_u, &max_v, &max_res);
290

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

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

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

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

315
316
	if ( outfile == NULL ) outfile = "za.pdf";
	surface = cairo_pdf_surface_create(outfile, wh, ht);
317
318

	if ( cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS ) {
Thomas White's avatar
Thomas White committed
319
		ERROR("Couldn't create Cairo surface\n");
320
321
322
323
324
		cairo_surface_destroy(surface);
		return;
	}

	dctx = cairo_create(surface);
Thomas White's avatar
Thomas White committed
325
326
327
328
329
	if ( cairo_status(dctx) != CAIRO_STATUS_SUCCESS ) {
		ERROR("Couldn't create Cairo context\n");
		cairo_surface_destroy(surface);
		return;
	}
330
331
332
333
334
335
336
337
338
339
340
341
342
343

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

344
345
346
347
	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);
348

Thomas White's avatar
Thomas White committed
349
	/* Centre marker */
350
351
	cairo_arc(dctx, (double)cx,
			(double)cy, max_r, 0, 2*M_PI);
Thomas White's avatar
Thomas White committed
352
353
354
	cairo_set_source_rgb(dctx, 1.0, 0.0, 0.0);
	cairo_fill(dctx);

355
	/* Draw indexing lines */
356
	cairo_set_line_cap(dctx, CAIRO_LINE_CAP_ROUND);
357
	cairo_set_line_width(dctx, 4.0);
358
	cairo_move_to(dctx, (double)cx, (double)cy);
359
360
	u = (2.0+max_ux)*as*sin(theta);
	v = (2.0+max_ux)*as*cos(theta);
361
	cairo_line_to(dctx, cx+u*scale, cy+v*scale);
362
363
364
	cairo_set_source_rgb(dctx, 0.0, 1.0, 0.0);
	cairo_stroke(dctx);

365
	cairo_set_font_size(dctx, 40.0);
366
	snprintf(tmp, 255, "%i%i%i", abs(xh), abs(xk), abs(xl));
367
368
369
	cairo_text_extents(dctx, tmp, &size);

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

373
	snprintf(tmp, 255, "%i%i%i", abs(yh), abs(yk), abs(yl));
374
375
376
	cairo_text_extents(dctx, tmp, &size);

	cairo_move_to(dctx, (double)cx, (double)cy);
377
	u = 0.0;
378
	v = (2.0+max_uy)*bs;
379
	cairo_line_to(dctx, cx+u*scale, cy+v*scale);
380
381
382
	cairo_set_source_rgb(dctx, 0.0, 1.0, 0.0);
	cairo_stroke(dctx);

383
384
	cairo_move_to(dctx, cx+u*scale - size.width/2.0,
	                    cy+v*scale + size.height + 20.0);
385
	render_overlined_indices(dctx, yh, yk, yl);
386
387
	cairo_fill(dctx);

Thomas White's avatar
Thomas White committed
388
389
390
	cairo_surface_finish(surface);
	cairo_destroy(dctx);
}
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
424
425
426
427
428
429
430
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;
}
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458


#else  /* HAVE_CAIRO */


static int render_key(int colscale)
{
	ERROR("This version of CrystFEL was compiled without Cairo");
	ERROR(" support, which is required to draw the colour");
	ERROR(" scale.  Sorry!\n");
	return 1;
}


static void render_za(UnitCell *cell, ReflItemList *items,
                      double *ref, unsigned int *counts,
                      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,
                      const char *outfile)
{
	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
459
460
461
462
463
464
465
466
467
468


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
469
	int config_sqrt = 0;
470
	int config_colkey = 0;
Thomas White's avatar
Thomas White committed
471
	unsigned int nproc = 1;
472
	char *pdb = NULL;
473
	int r = 0;
474
	double boost = 1.0;
475
	char *sym = NULL;
476
477
	char *weighting = NULL;
	int wght;
478
479
	int colscale;
	char *cscale = NULL;
Thomas White's avatar
Thomas White committed
480
	unsigned int *cts;
481
482
483
484
	signed int dh=1, dk=0, dl=0;
	signed int rh=0, rk=1, rl=0;
	char *down = NULL;
	char *right = NULL;
485
	char *outfile = NULL;
Thomas White's avatar
Thomas White committed
486
487
488
489
490
491

	/* Long options */
	const struct option longopts[] = {
		{"help",               0, NULL,               'h'},
		{"povray",             0, &config_povray,      1},
		{"zone-axis",          0, &config_zoneaxis,    1},
492
		{"output",             1, NULL,               'o'},
493
		{"pdb",                1, NULL,               'p'},
494
		{"boost",              1, NULL,               'b'},
495
		{"symmetry",           1, NULL,               'y'},
496
		{"weighting",          1, NULL,               'w'},
497
		{"colscale",           1, NULL,               'c'},
498
499
		{"down",               1, NULL,               'd'},
		{"right",              1, NULL,               'r'},
500
		{"counts",             0, &config_sqrt,        1},
501
		{"colour-key",         0, &config_colkey,      1},
Thomas White's avatar
Thomas White committed
502
503
504
505
		{0, 0, NULL, 0}
	};

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

		switch (c) {
Thomas White's avatar
Thomas White committed
510
		case 'h' :
Thomas White's avatar
Thomas White committed
511
512
513
			show_help(argv[0]);
			return 0;

Thomas White's avatar
Thomas White committed
514
		case 'j' :
Thomas White's avatar
Thomas White committed
515
516
517
			nproc = atoi(optarg);
			break;

518
519
520
521
		case 'p' :
			pdb = strdup(optarg);
			break;

522
523
524
525
		case 'b' :
			boost = atof(optarg);
			break;

526
527
528
529
		case 'y' :
			sym = strdup(optarg);
			break;

530
531
532
533
		case 'w' :
			weighting = strdup(optarg);
			break;

534
535
536
537
		case 'c' :
			cscale = strdup(optarg);
			break;

538
539
540
541
542
543
544
545
		case 'd' :
			down = strdup(optarg);
			break;

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

546
547
548
549
		case 'o' :
			outfile = strdup(optarg);
			break;

Thomas White's avatar
Thomas White committed
550
		case 0 :
Thomas White's avatar
Thomas White committed
551
552
			break;

Thomas White's avatar
Thomas White committed
553
		default :
Thomas White's avatar
Thomas White committed
554
555
556
557
558
			return 1;
		}

	}

559
560
561
562
	if ( pdb == NULL ) {
		pdb = strdup("molecule.pdb");
	}

563
564
565
566
	if ( sym == NULL ) {
		sym = strdup("1");
	}

567
568
569
570
571
572
573
574
575
576
	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;
577
578
	} else if ( strcmp(weighting, "counts") == 0 ) {
		wght = WGHT_COUNTS;
579
580
	} else if ( strcmp(weighting, "rawcts") == 0 ) {
		wght = WGHT_RAWCOUNTS;
581
582
583
584
	} else if ( strcmp(weighting, "rawcount") == 0 ) {
		wght = WGHT_RAWCOUNTS;
	} else if ( strcmp(weighting, "rawcounts") == 0 ) {
		wght = WGHT_RAWCOUNTS;
585
586
587
588
	} else {
		ERROR("Unrecognised weighting '%s'\n", weighting);
		return 1;
	}
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
	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);
608

609
610
611
612
	if ( config_colkey ) {
		return render_key(colscale);
	}

613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
	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
637
638
	infile = argv[optind];

639
	cell = load_cell_from_pdb(pdb);
640
641
642
643
	if ( cell == NULL ) {
		ERROR("Couldn't load unit cell from %s\n", pdb);
		return 1;
	}
Thomas White's avatar
Thomas White committed
644
	ref = new_list_intensity();
Thomas White's avatar
Thomas White committed
645
	cts = new_list_count();
646
	ReflItemList *items = read_reflections(infile, ref, NULL, cts, NULL);
647
	if ( items == NULL ) {
Thomas White's avatar
Thomas White committed
648
649
650
651
652
		ERROR("Couldn't open file '%s'\n", infile);
		return 1;
	}

	if ( config_povray ) {
653
654
		r = povray_render_animation(cell, ref, cts, items,
		                            nproc, sym, wght, boost);
Thomas White's avatar
Thomas White committed
655
	} else if ( config_zoneaxis ) {
656
		render_za(cell, items, ref, cts, boost, sym, wght, colscale,
657
		          rh, rk, rl, dh, dk, dl, outfile);
Thomas White's avatar
Thomas White committed
658
659
660
661
	} else {
		ERROR("Try again with either --povray or --zone-axis.\n");
	}

662
	free(pdb);
663
	free(sym);
664
	delete_items(items);
665
	if ( outfile != NULL ) free(outfile);
666

667
	return r;
668
}