render_hkl.c 18.6 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
#define KEY_FILENAME "key.pdf"


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


82
#ifdef HAVE_CAIRO
83
84


Thomas White's avatar
Thomas White committed
85
86
static void draw_circles(double xh, double xk, double xl,
                         double yh, double yk, double yl,
87
                         signed int zh, signed int zk, signed int zl,
Thomas White's avatar
Thomas White committed
88
                         RefList *list, const SymOpList *sym,
89
90
91
                         cairo_t *dctx, int wght, double boost, int colscale,
                         UnitCell *cell, double radius, double theta,
                         double as, double bs, double cx, double cy,
Thomas White's avatar
Thomas White committed
92
                         double scale, double *max_val)
93
{
Thomas White's avatar
Thomas White committed
94
95
	Reflection *refl;
	RefListIterator *iter;
Thomas White's avatar
Thomas White committed
96
	SymOpMask *m;
97
	double nx, ny;
98

Thomas White's avatar
Thomas White committed
99
100
	m = new_symopmask(sym);

101
102
103
	nx = xh*xh + xk*xk + xl*xl;
	ny = yh*yh + yk*yk + yl*yl;

Thomas White's avatar
Thomas White committed
104
105
106
107
	/* Iterate over all reflections */
	for ( refl = first_refl(list, &iter);
	      refl != NULL;
	      refl = next_refl(refl, iter) ) {
108

Thomas White's avatar
Thomas White committed
109
		double u, v, val;
Thomas White's avatar
Thomas White committed
110
		signed int ha, ka, la;
Thomas White's avatar
Thomas White committed
111
		int i, n;
Thomas White's avatar
Thomas White committed
112
113
114

		get_indices(refl, &ha, &ka, &la);

Thomas White's avatar
Thomas White committed
115
116
		special_position(sym, m, ha, ka, la);
		n = num_equivs(sym, m);
Thomas White's avatar
Thomas White committed
117
118

		for ( i=0; i<n; i++ ) {
Thomas White's avatar
Thomas White committed
119
120

			signed int h, k, l;
Thomas White's avatar
Thomas White committed
121
			double xi, yi;
Thomas White's avatar
Thomas White committed
122

Thomas White's avatar
Thomas White committed
123
			get_equiv(sym, m, i, ha, ka, la, &h, &k, &l);
Thomas White's avatar
Thomas White committed
124
125
126
127

			/* Is the reflection in the zone? */
			if ( h*zh + k*zk + l*zl != 0 ) continue;

128
129
			xi = (h*xh + k*xk + l*xl) / nx;
			yi = (h*yh + k*yk + l*yl) / ny;
Thomas White's avatar
Thomas White committed
130
131
132
133
134
135
136
137
138
139
140

			switch ( wght) {
			case WGHT_I :
				val = get_intensity(refl);
				break;
			case WGHT_SQRTI :
				val = get_intensity(refl);
				val = (val>0.0) ? sqrt(val) : 0.0;
				break;
			case WGHT_COUNTS :
				val = get_redundancy(refl);
Thomas White's avatar
Thomas White committed
141
				val /= (double)n;
Thomas White's avatar
Thomas White committed
142
143
144
145
146
147
148
149
				break;
			case WGHT_RAWCOUNTS :
				val = get_redundancy(refl);
				break;
			default :
				ERROR("Invalid weighting.\n");
				abort();
			}
150

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

Thomas White's avatar
Thomas White committed
155
			if ( dctx != NULL ) {
156

Thomas White's avatar
Thomas White committed
157
				double r, g, b;
158

Thomas White's avatar
Thomas White committed
159
160
161
				cairo_arc(dctx, ((double)cx)+u*scale,
					        ((double)cy)+v*scale,
					        radius, 0, 2*M_PI);
162

Thomas White's avatar
Thomas White committed
163
164
165
166
				render_scale(val, *max_val/boost, colscale,
					     &r, &g, &b);
				cairo_set_source_rgb(dctx, r, g, b);
				cairo_fill(dctx);
167

Thomas White's avatar
Thomas White committed
168
			} else {
169

Thomas White's avatar
Thomas White committed
170
171
172
173
174
175
				/* Find max value for colour scale */
				if ( !isnan(val) && !isinf(val)
				  && (fabs(val) > fabs(*max_val)) )
				{
					*max_val = fabs(val);
				}
176

Thomas White's avatar
Thomas White committed
177
			}
Thomas White's avatar
Thomas White committed
178

179
180
181
		}

	}
Thomas White's avatar
Thomas White committed
182
183

	free_symopmask(m);
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,
Thomas White's avatar
Thomas White committed
238
239
                      double boost, const SymOpList *sym, int wght,
                      int colscale,
240
                      signed int xh, signed int xk, signed int xl,
241
                      signed int yh, signed int yk, signed int yl,
242
                      const char *outfile, double scale_top)
243
{
Thomas White's avatar
Thomas White committed
244
245
	cairo_surface_t *surface;
	cairo_t *dctx;
Thomas White's avatar
Thomas White committed
246
247
	double max_val;
	double scale1, scale2, scale;
Thomas White's avatar
Thomas White committed
248
	double sep_u, sep_v, max_r;
249
	double u, v;
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;
Thomas White's avatar
Thomas White committed
263
	double rmin, rmax;
264

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

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

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

Thomas White's avatar
Thomas White committed
292
293
294
295
	resolution_limits(list, cell, &rmin, &rmax);
	printf("Resolution limits: 1/d = %.2f - %.2f nm^-1"
	       " (d = %.2f - %.2f A)\n",
	       rmin/1e9, rmax/1e9, (1.0/rmin)/1e-10, (1.0/rmax)/1e-10);
296

Thomas White's avatar
Thomas White committed
297

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

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

Thomas White's avatar
Thomas White committed
309
310
311
	scale1 = ((double)wh-border) / (2.0*rmax);
	scale2 = ((double)ht-border) / (2.0*rmax);
	scale = (scale1 < scale2) ? scale1 : scale2;
312

Thomas White's avatar
Thomas White committed
313
	/* Work out the spot radius */
314
315
	sep_u = scale*as;
	sep_v = scale*bs;
316
	max_r = (sep_u < sep_v) ? sep_u : sep_v;
317
	max_r /= 2.0;  /* Max radius is half the separation */
318
	max_r -= 1.0;  /* Add a tiny separation between circles */
319

Thomas White's avatar
Thomas White committed
320
	/* Create surface */
321
322
323
324
325
326
327
328
	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);
	}
329
330

	if ( cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS ) {
Thomas White's avatar
Thomas White committed
331
		ERROR("Couldn't create Cairo surface\n");
332
333
334
335
336
		cairo_surface_destroy(surface);
		return;
	}

	dctx = cairo_create(surface);
Thomas White's avatar
Thomas White committed
337
338
339
340
341
	if ( cairo_status(dctx) != CAIRO_STATUS_SUCCESS ) {
		ERROR("Couldn't create Cairo context\n");
		cairo_surface_destroy(surface);
		return;
	}
342
343
344
345
346
347
348
349
350
351
352
353
354
355

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

356
	draw_circles(xh, xk, xl, yh, yk, yl, zh, zk, zl,
Thomas White's avatar
Thomas White committed
357
	             list, sym, dctx, wght, boost, colscale, cell,
358
	             max_r, theta, as, bs, cx, cy, scale,
Thomas White's avatar
Thomas White committed
359
	             &max_val);
360

Thomas White's avatar
Thomas White committed
361
	/* Centre marker */
362
363
	cairo_arc(dctx, (double)cx,
			(double)cy, max_r, 0, 2*M_PI);
Thomas White's avatar
Thomas White committed
364
365
366
	cairo_set_source_rgb(dctx, 1.0, 0.0, 0.0);
	cairo_fill(dctx);

367
	/* Draw indexing lines */
368
	cairo_set_line_cap(dctx, CAIRO_LINE_CAP_ROUND);
369
	cairo_set_line_width(dctx, 4.0);
370
	cairo_move_to(dctx, (double)cx, (double)cy);
Thomas White's avatar
Thomas White committed
371
372
	u = rmax*sin(theta);
	v = rmax*cos(theta);
373
	cairo_line_to(dctx, cx+u*scale, cy+v*scale);
374
375
376
	cairo_set_source_rgb(dctx, 0.0, 1.0, 0.0);
	cairo_stroke(dctx);

377
	cairo_set_font_size(dctx, 40.0);
378
	snprintf(tmp, 255, "%i%i%i", abs(xh), abs(xk), abs(xl));
379
380
381
	cairo_text_extents(dctx, tmp, &size);

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

385
	snprintf(tmp, 255, "%i%i%i", abs(yh), abs(yk), abs(yl));
386
387
388
	cairo_text_extents(dctx, tmp, &size);

	cairo_move_to(dctx, (double)cx, (double)cy);
Thomas White's avatar
Thomas White committed
389
	cairo_line_to(dctx, cx, cy+rmax*scale);
390
391
392
	cairo_set_source_rgb(dctx, 0.0, 1.0, 0.0);
	cairo_stroke(dctx);

Thomas White's avatar
Thomas White committed
393
394
	cairo_move_to(dctx, cx - size.width/2.0,
	                    cy+rmax*scale + size.height + 20.0);
395
	render_overlined_indices(dctx, yh, yk, yl);
396
397
	cairo_fill(dctx);

398
399
400
401
402
403
404
	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
405
406
407
	cairo_surface_finish(surface);
	cairo_destroy(dctx);
}
408

409

410
static int render_key(int colscale, double scale_top)
411
412
413
{
	cairo_surface_t *surface;
	cairo_t *dctx;
414
415
	double top, wh, ht, y;
	double slice;
416

417
418
419
420
421
422
423
424
425
	wh = 128.0;
	ht = 1024.0;
	slice = 1.0;

	if ( scale_top > 0.0 ) {
		top = scale_top;
	} else {
		top = 1.0;
	}
426

427
	surface = cairo_pdf_surface_create(KEY_FILENAME, wh, ht);
428
429
430
431
432
433
434
435
436

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

437
	for ( y=0.0; y<ht; y+=slice ) {
438

439
440
441
		double r, g, b;
		double val;
		double v = y;
442

443
444
445
446
447
448
449
450
451
452
453
		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;
		}
454

455
		render_scale(val, top, colscale, &r, &g, &b);
456
457
		cairo_set_source_rgb(dctx, r, g, b);

458
		cairo_stroke_preserve(dctx);
459
460
461
462
		cairo_fill(dctx);

	}

463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
	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);

	}


492
493
494
	cairo_surface_finish(surface);
	cairo_destroy(dctx);

495
496
	STATUS("Colour key written to "KEY_FILENAME"\n");

497
498
	return 0;
}
499
500
501
502
503


#else  /* HAVE_CAIRO */


504
static int render_key(int colscale, double scale_top)
505
506
507
508
509
510
511
512
{
	ERROR("This version of CrystFEL was compiled without Cairo");
	ERROR(" support, which is required to draw the colour");
	ERROR(" scale.  Sorry!\n");
	return 1;
}


513
static void render_za(UnitCell *cell, RefList *list,
514
515
516
                      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,
517
                      const char *outfile, double scale_top)
518
519
520
521
522
523
524
525
{
	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
526
527
528
529
530
531


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

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

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

		switch (c) {
Thomas White's avatar
Thomas White committed
580
		case 'h' :
Thomas White's avatar
Thomas White committed
581
582
583
			show_help(argv[0]);
			return 0;

Thomas White's avatar
Thomas White committed
584
		case 'j' :
Thomas White's avatar
Thomas White committed
585
586
587
			nproc = atoi(optarg);
			break;

588
589
590
591
		case 'p' :
			pdb = strdup(optarg);
			break;

592
593
594
595
		case 'b' :
			boost = atof(optarg);
			break;

596
		case 'y' :
Thomas White's avatar
Thomas White committed
597
			sym_str = strdup(optarg);
598
599
			break;

600
601
602
603
		case 'w' :
			weighting = strdup(optarg);
			break;

604
605
606
607
		case 'c' :
			cscale = strdup(optarg);
			break;

608
609
610
611
612
613
614
615
		case 'd' :
			down = strdup(optarg);
			break;

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

616
617
618
619
		case 'o' :
			outfile = strdup(optarg);
			break;

620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
		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
635
		case 0 :
Thomas White's avatar
Thomas White committed
636
637
			break;

Thomas White's avatar
Thomas White committed
638
		default :
Thomas White's avatar
Thomas White committed
639
640
641
642
643
			return 1;
		}

	}

644
645
646
	if ( (pdb == NULL) && !config_colkey ) {
		ERROR("You must specify the PDB containing the unit cell.\n");
		return 1;
647
648
	}

Thomas White's avatar
Thomas White committed
649
650
	if ( sym_str == NULL ) {
		sym_str = strdup("1");
651
	}
Thomas White's avatar
Thomas White committed
652
653
	sym = get_pointgroup(sym_str);
	free(sym_str);
654

655
656
657
658
	if ( weighting == NULL ) {
		weighting = strdup("I");
	}

659
	if ( outfile == NULL ) outfile = strdup("za.pdf");
Thomas White's avatar
Thomas White committed
660
661


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

702
	if ( config_colkey ) {
703
		return render_key(colscale, scale_top);
704
705
	}

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

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

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

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

764
	return r;
765
}