render_hkl.c 19.2 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
"                           direction.  Default: 0,1,0.\n"
52
"  -o, --output=<filename> Output filename (not for POV-ray).  Default: za.pdf\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
		signed int he, ke, le;
Thomas White's avatar
Thomas White committed
108
		Reflection *refl;
Thomas White's avatar
Thomas White committed
109
		int r;
110
111
112
113
114
115

		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
116
117
118
		r = find_equiv_in_list(list, h, k, l, sym, &he, &ke, &le);
		if ( !r ) continue;
		refl = find_refl(list, he, ke, le);
119
120
121

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

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

144
		if ( dctx != NULL ) {
145

146
			double r, g, b;
147

148
149
150
			cairo_arc(dctx, ((double)cx)+u*scale,
			                ((double)cy)+v*scale,
			                radius, 0, 2*M_PI);
151

152
153
154
155
			render_scale(val, *max_val/boost, colscale,
			             &r, &g, &b);
			cairo_set_source_rgb(dctx, r, g, b);
			cairo_fill(dctx);
156

157
		} else {
158

159
160
161
			/* 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);
162

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

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

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

264
	/* Vector product to determine the zone axis. */
265
266
267
268
	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);
269

270
	/* Size of output and centre definition */
Thomas White's avatar
Thomas White committed
271
272
	wh = 1024;
	ht = 1024;
273

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

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

Thomas White's avatar
Thomas White committed
297
	max_res /= 1e9;
298
299
	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
300

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

306
307
308
309
310
	/* Use manual scale top if specified */
	if ( scale_top > 0.0 ) {
		max_val = scale_top;
	}

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

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

326
	if ( outfile == NULL ) outfile = "za.pdf";
327
328
329
330
331
332
333
334
335

	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);
	}
336
337

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

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

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

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

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

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

384
	cairo_set_font_size(dctx, 40.0);
385
	snprintf(tmp, 255, "%i%i%i", abs(xh), abs(xk), abs(xl));
386
387
388
	cairo_text_extents(dctx, tmp, &size);

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

392
	snprintf(tmp, 255, "%i%i%i", abs(yh), abs(yk), abs(yl));
393
394
395
	cairo_text_extents(dctx, tmp, &size);

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

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

407
408
409
410
411
412
413
	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
414
415
416
	cairo_surface_finish(surface);
	cairo_destroy(dctx);
}
417

418

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

426
427
428
429
430
431
432
433
434
	wh = 128.0;
	ht = 1024.0;
	slice = 1.0;

	if ( scale_top > 0.0 ) {
		top = scale_top;
	} else {
		top = 1.0;
	}
435
436
437
438
439
440
441
442
443
444
445

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

446
	for ( y=0.0; y<ht; y+=slice ) {
447

448
449
450
		double r, g, b;
		double val;
		double v = y;
451

452
453
454
455
456
457
458
459
460
461
462
		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;
		}
463

464
		render_scale(val, top, colscale, &r, &g, &b);
465
466
		cairo_set_source_rgb(dctx, r, g, b);

467
		cairo_stroke_preserve(dctx);
468
469
470
471
		cairo_fill(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
	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);

	}


501
502
503
504
505
	cairo_surface_finish(surface);
	cairo_destroy(dctx);

	return 0;
}
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533


#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
534
535
536
537
538
539


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

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

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

		switch (c) {
Thomas White's avatar
Thomas White committed
587
		case 'h' :
Thomas White's avatar
Thomas White committed
588
589
590
			show_help(argv[0]);
			return 0;

Thomas White's avatar
Thomas White committed
591
		case 'j' :
Thomas White's avatar
Thomas White committed
592
593
594
			nproc = atoi(optarg);
			break;

595
596
597
598
		case 'p' :
			pdb = strdup(optarg);
			break;

599
600
601
602
		case 'b' :
			boost = atof(optarg);
			break;

603
604
605
606
		case 'y' :
			sym = strdup(optarg);
			break;

607
608
609
610
		case 'w' :
			weighting = strdup(optarg);
			break;

611
612
613
614
		case 'c' :
			cscale = strdup(optarg);
			break;

615
616
617
618
619
620
621
622
		case 'd' :
			down = strdup(optarg);
			break;

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

623
624
625
626
		case 'o' :
			outfile = strdup(optarg);
			break;

627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
		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
642
		case 0 :
Thomas White's avatar
Thomas White committed
643
644
			break;

Thomas White's avatar
Thomas White committed
645
		default :
Thomas White's avatar
Thomas White committed
646
647
648
649
650
			return 1;
		}

	}

651
652
653
	if ( (pdb == NULL) && !config_colkey ) {
		ERROR("You must specify the PDB containing the unit cell.\n");
		return 1;
654
655
	}

656
657
658
659
	if ( sym == NULL ) {
		sym = strdup("1");
	}

660
661
662
663
664
665
666
667
668
669
	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;
670
671
	} else if ( strcmp(weighting, "counts") == 0 ) {
		wght = WGHT_COUNTS;
672
673
	} else if ( strcmp(weighting, "rawcts") == 0 ) {
		wght = WGHT_RAWCOUNTS;
674
675
676
677
	} else if ( strcmp(weighting, "rawcount") == 0 ) {
		wght = WGHT_RAWCOUNTS;
	} else if ( strcmp(weighting, "rawcounts") == 0 ) {
		wght = WGHT_RAWCOUNTS;
678
679
680
681
	} else {
		ERROR("Unrecognised weighting '%s'\n", weighting);
		return 1;
	}
682
683
684
685
686
687
688
689
690
691
692
693
694
695
	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;
696
697
	} else if ( strcmp(cscale, "ratio") == 0 ) {
		colscale = SCALE_RATIO;
698
699
700
701
702
	} else {
		ERROR("Unrecognised colour scale '%s'\n", cscale);
		return 1;
	}
	free(cscale);
703

704
	if ( config_colkey ) {
705
		return render_key(colscale, scale_top);
706
707
	}

708
709
710
	if ( config_zoneaxis ) {
		if ( (( down == NULL ) && ( right != NULL ))
		  || (( down != NULL ) && ( right == NULL )) ) {
Thomas White's avatar
Thomas White committed
711
712
			ERROR("Either specify both 'down' and 'right',"
			      " or neither.\n");
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
			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
733
734
	infile = argv[optind];

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

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

761
	free(pdb);
762
	free(sym);
Thomas White's avatar
Thomas White committed
763
	reflist_free(list);
764
	if ( outfile != NULL ) free(outfile);
765

766
	return r;
767
}