render_hkl.c 16.9 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
40
static void show_help(const char *s)
{
	printf("Syntax: %s [options] <file.hkl>\n\n", s);
	printf(
41
"Render intensity lists in various ways.\n"
42
"\n"
43
"      --povray            Render a 3D animation using POV-ray.\n"
44
#ifdef HAVE_CAIRO
45
"      --zone-axis         Render a 2D zone axis pattern.\n"
46
#endif
47
"\n"
48
"  -d, --down=<h>,<k>,<l>  Indices for the axis in the downward direction.\n"
49
"                           Default: 1,0,0.\n"
50
"  -r, --right=<h>,<k>,<l> Indices for the axis in the 'right' (roughly)\n"
51
52
"                           direction.  Default: 0,1,0.\n"
"  -o, --output=<filename> Output filename (not for POV-ray).\n"
53
54
55
"      --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"
56
57
58
59
"\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
60
"                           colour  : Colour scale:\n"
61
62
"                                     black-blue-pink-red-orange-yellow-white\n"
"\n"
63
64
"  -w  --weighting=<wght>  Colour/shade the reciprocal lattice points\n"
"                           according to:\n"
65
66
"                            I      : the intensity of the reflection.\n"
"                            sqrtI  : the square root of the intensity.\n"
Thomas White's avatar
Thomas White committed
67
"                            count  : the number of measurements for the reflection.\n"
68
"                                     (after correcting for 'epsilon')\n"
Thomas White's avatar
Thomas White committed
69
"                            rawcts : the raw number of measurements for the\n"
70
"                                     reflection (no 'epsilon' correction).\n"
71
72
73
74
"\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"
75
);
76
77
78
}


79
#ifdef HAVE_CAIRO
80
81


82
83
84
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
85
                         RefList *list, const char *sym,
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
                         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
101
	/* Iterate over possible reflections in this zone */
102
103
104
105
106
	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
		Reflection *refl;
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
		refl = find_refl(list, h, k, l);
		if ( refl == NULL ) continue;
116
117
118

		switch ( wght ) {
		case WGHT_I :
Thomas White's avatar
Thomas White committed
119
			val = get_intensity(refl);
120
121
			break;
		case WGHT_SQRTI :
Thomas White's avatar
Thomas White committed
122
			val = get_intensity(refl);
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 = get_redundancy(refl);
			val /= (float)num_equivs(h, k, l, sym);
128
129
			break;
		case WGHT_RAWCOUNTS :
Thomas White's avatar
Thomas White committed
130
			val = get_redundancy(refl);
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);
	}
}


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

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

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

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

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

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

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

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

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

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

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

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

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

343
	draw_circles(xh, xk, xl, yh, yk, yl, zh, zk, zl,
Thomas White's avatar
Thomas White committed
344
	             list, sym, dctx, wght, boost, colscale, cell,
345
346
	             max_r, theta, as, bs, cx, cy, scale,
	             NULL, NULL, &max_val, NULL, NULL, NULL);
347

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

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

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

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

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

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

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

Thomas White's avatar
Thomas White committed
387
388
389
	cairo_surface_finish(surface);
	cairo_destroy(dctx);
}
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
424
425
426
427
428
429
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;
}
430
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


#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
458
459
460
461
462
463


int main(int argc, char *argv[])
{
	int c;
	UnitCell *cell;
Thomas White's avatar
Thomas White committed
464
	RefList *list;
Thomas White's avatar
Thomas White committed
465
466
467
	char *infile;
	int config_povray = 0;
	int config_zoneaxis = 0;
Thomas White's avatar
Thomas White committed
468
	int config_sqrt = 0;
469
	int config_colkey = 0;
Thomas White's avatar
Thomas White committed
470
	unsigned int nproc = 1;
471
	char *pdb = NULL;
472
	int r = 0;
473
	double boost = 1.0;
474
	char *sym = NULL;
475
476
	char *weighting = NULL;
	int wght;
477
478
	int colscale;
	char *cscale = NULL;
479
480
481
482
	signed int dh=1, dk=0, dl=0;
	signed int rh=0, rk=1, rl=0;
	char *down = NULL;
	char *right = NULL;
483
	char *outfile = NULL;
Thomas White's avatar
Thomas White committed
484
485
486
487
488
489

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

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

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

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

516
517
518
519
		case 'p' :
			pdb = strdup(optarg);
			break;

520
521
522
523
		case 'b' :
			boost = atof(optarg);
			break;

524
525
526
527
		case 'y' :
			sym = strdup(optarg);
			break;

528
529
530
531
		case 'w' :
			weighting = strdup(optarg);
			break;

532
533
534
535
		case 'c' :
			cscale = strdup(optarg);
			break;

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

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

544
545
546
547
		case 'o' :
			outfile = strdup(optarg);
			break;

Thomas White's avatar
Thomas White committed
548
		case 0 :
Thomas White's avatar
Thomas White committed
549
550
			break;

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

	}

557
558
559
560
	if ( pdb == NULL ) {
		pdb = strdup("molecule.pdb");
	}

561
562
563
564
	if ( sym == NULL ) {
		sym = strdup("1");
	}

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

607
608
609
610
	if ( config_colkey ) {
		return render_key(colscale);
	}

611
612
613
	if ( config_zoneaxis ) {
		if ( (( down == NULL ) && ( right != NULL ))
		  || (( down != NULL ) && ( right == NULL )) ) {
Thomas White's avatar
Thomas White committed
614
615
			ERROR("Either specify both 'down' and 'right',"
			      " or neither.\n");
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
			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
636
637
	infile = argv[optind];

638
	cell = load_cell_from_pdb(pdb);
639
640
641
642
	if ( cell == NULL ) {
		ERROR("Couldn't load unit cell from %s\n", pdb);
		return 1;
	}
Thomas White's avatar
Thomas White committed
643
644
645
	list = read_reflections(infile);
	if ( list == NULL ) {
		ERROR("Couldn't read file '%s'\n", infile);
Thomas White's avatar
Thomas White committed
646
647
		return 1;
	}
Thomas White's avatar
Thomas White committed
648
	if ( check_list_symmetry(list, sym) ) {
Thomas White's avatar
Thomas White committed
649
650
651
652
		ERROR("The input reflection list does not appear to"
		      " have symmetry %s\n", sym);
		return 1;
	}
Thomas White's avatar
Thomas White committed
653
654

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

664
	free(pdb);
665
	free(sym);
Thomas White's avatar
Thomas White committed
666
	reflist_free(list);
667
	if ( outfile != NULL ) free(outfile);
668

669
	return r;
670
}