render_hkl.c 18.7 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 "symmetry.h"
30
#include "render.h"
31
#include "render_hkl.h"
Thomas White's avatar
Thomas White committed
32
33
#include "reflist.h"
#include "reflist-utils.h"
34
35


36
37
38
#define KEY_FILENAME "key.pdf"


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


76
#ifdef HAVE_CAIRO
77
78


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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
static double max_value(RefList *list, int wght, const SymOpList *sym)
{
	Reflection *refl;
	RefListIterator *iter;
	double max = -INFINITY;
	SymOpMask *m;

	m = new_symopmask(sym);

	for ( refl = first_refl(list, &iter);
	      refl != NULL;
	      refl = next_refl(refl, iter) )
	{
		double val;
		int n;
		signed int h, k, l;

		get_indices(refl, &h, &k, &l);

		special_position(sym, m, h, k, l);
		n = num_equivs(sym, m);

		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);
			val /= (double)n;
			break;
		case WGHT_RAWCOUNTS :
			val = get_redundancy(refl);
			break;
		default :
			ERROR("Invalid weighting.\n");
			abort();
		}

		if ( val > max ) max = val;
	}

	return max;
}


Thomas White's avatar
Thomas White committed
128
129
static void draw_circles(double xh, double xk, double xl,
                         double yh, double yk, double yl,
130
                         signed int zh, signed int zk, signed int zl,
Thomas White's avatar
Thomas White committed
131
                         RefList *list, const SymOpList *sym,
132
133
134
                         cairo_t *dctx, int wght, double boost, int colscale,
                         UnitCell *cell, double radius, double theta,
                         double as, double bs, double cx, double cy,
135
                         double scale, double max_val)
136
{
Thomas White's avatar
Thomas White committed
137
138
	Reflection *refl;
	RefListIterator *iter;
Thomas White's avatar
Thomas White committed
139
	SymOpMask *m;
140
	double nx, ny;
141

Thomas White's avatar
Thomas White committed
142
143
	m = new_symopmask(sym);

144
145
146
	nx = xh*xh + xk*xk + xl*xl;
	ny = yh*yh + yk*yk + yl*yl;

Thomas White's avatar
Thomas White committed
147
148
149
	/* Iterate over all reflections */
	for ( refl = first_refl(list, &iter);
	      refl != NULL;
150
151
	      refl = next_refl(refl, iter) )
	{
Thomas White's avatar
Thomas White committed
152
		double u, v, val;
Thomas White's avatar
Thomas White committed
153
		signed int ha, ka, la;
Thomas White's avatar
Thomas White committed
154
		int i, n;
155
		double r, g, b;
Thomas White's avatar
Thomas White committed
156
157
158

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

Thomas White's avatar
Thomas White committed
159
160
		special_position(sym, m, ha, ka, la);
		n = num_equivs(sym, m);
Thomas White's avatar
Thomas White committed
161
162

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

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

Thomas White's avatar
Thomas White committed
167
			get_equiv(sym, m, i, ha, ka, la, &h, &k, &l);
Thomas White's avatar
Thomas White committed
168
169
170
171

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

172
173
			xi = (h*xh + k*xk + l*xl) / nx;
			yi = (h*yh + k*yk + l*yl) / ny;
Thomas White's avatar
Thomas White committed
174
175
176
177
178
179
180
181
182
183
184

			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
185
				val /= (double)n;
Thomas White's avatar
Thomas White committed
186
187
188
189
190
191
192
193
				break;
			case WGHT_RAWCOUNTS :
				val = get_redundancy(refl);
				break;
			default :
				ERROR("Invalid weighting.\n");
				abort();
			}
194

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

199
200
201
			cairo_arc(dctx, ((double)cx)+u*scale,
				        ((double)cy)+v*scale,
				        radius, 0.0, 2.0*M_PI);
202

203
204
205
206
			render_scale(val, max_val/boost, colscale,
				     &r, &g, &b);
			cairo_set_source_rgb(dctx, r, g, b);
			cairo_fill(dctx);
Thomas White's avatar
Thomas White committed
207

208
209
210
		}

	}
Thomas White's avatar
Thomas White committed
211
212

	free_symopmask(m);
213
214
215
}


216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
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
266
static void render_za(UnitCell *cell, RefList *list,
Thomas White's avatar
Thomas White committed
267
268
                      double boost, const SymOpList *sym, int wght,
                      int colscale,
269
                      signed int xh, signed int xk, signed int xl,
270
                      signed int yh, signed int yk, signed int yl,
271
                      const char *outfile, double scale_top)
272
{
Thomas White's avatar
Thomas White committed
273
274
	cairo_surface_t *surface;
	cairo_t *dctx;
Thomas White's avatar
Thomas White committed
275
276
	double max_val;
	double scale1, scale2, scale;
Thomas White's avatar
Thomas White committed
277
	double sep_u, sep_v, max_r;
278
	double u, v;
Thomas White's avatar
Thomas White committed
279
	double as, bs, theta;
280
281
282
	double asx, asy, asz;
	double bsx, bsy, bsz;
	double csx, csy, csz;
Thomas White's avatar
Thomas White committed
283
	float wh, ht;
284
285
286
287
288
289
290
	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;
291
	int png;
Thomas White's avatar
Thomas White committed
292
	double rmin, rmax;
293

294
	/* Vector product to determine the zone axis. */
295
296
297
298
	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);
299

300
	/* Size of output and centre definition */
Thomas White's avatar
Thomas White committed
301
302
	wh = 1024;
	ht = 1024;
303

Thomas White's avatar
Thomas White committed
304
	/* Work out reciprocal lattice spacings and angles for this cut */
305
	if ( cell_get_reciprocal(cell, &asx, &asy, &asz,
Thomas White's avatar
Thomas White committed
306
	                          &bsx, &bsy, &bsz,
307
308
309
310
	                          &csx, &csy, &csz) ) {
		ERROR("Couldn't get reciprocal parameters\n");
		return;
	}
311
312
313
314
315
316
317
	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
318
319
	as = modulus(xx, xy, xz);
	bs = modulus(yx, yy, yz);
320

Thomas White's avatar
Thomas White committed
321
322
323
324
	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);
325

326
	max_val = max_value(list, wght, sym);
327
	if ( max_val <= 0.0 ) {
328
		STATUS("Couldn't find max value.\n");
Thomas White's avatar
Thomas White committed
329
		return;
330
331
	}

332
333
334
335
336
	/* Use manual scale top if specified */
	if ( scale_top > 0.0 ) {
		max_val = scale_top;
	}

Thomas White's avatar
Thomas White committed
337
338
339
	scale1 = ((double)wh-border) / (2.0*rmax);
	scale2 = ((double)ht-border) / (2.0*rmax);
	scale = (scale1 < scale2) ? scale1 : scale2;
340

Thomas White's avatar
Thomas White committed
341
	/* Work out the spot radius */
342
343
	sep_u = scale*as;
	sep_v = scale*bs;
344
	max_r = (sep_u < sep_v) ? sep_u : sep_v;
345
	max_r /= 2.0;  /* Max radius is half the separation */
346
	max_r -= (max_r/10.0);  /* Add a tiny separation between circles */
347

Thomas White's avatar
Thomas White committed
348
	/* Create surface */
349
350
351
352
353
354
355
356
	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);
	}
357
358

	if ( cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS ) {
Thomas White's avatar
Thomas White committed
359
		ERROR("Couldn't create Cairo surface\n");
360
361
362
363
364
		cairo_surface_destroy(surface);
		return;
	}

	dctx = cairo_create(surface);
Thomas White's avatar
Thomas White committed
365
366
367
368
369
	if ( cairo_status(dctx) != CAIRO_STATUS_SUCCESS ) {
		ERROR("Couldn't create Cairo context\n");
		cairo_surface_destroy(surface);
		return;
	}
370
371
372
373
374
375
376
377
378
379
380
381
382
383

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

384
	draw_circles(xh, xk, xl, yh, yk, yl, zh, zk, zl,
Thomas White's avatar
Thomas White committed
385
	             list, sym, dctx, wght, boost, colscale, cell,
386
	             max_r, theta, as, bs, cx, cy, scale,
387
	             max_val);
388

Thomas White's avatar
Thomas White committed
389
	/* Centre marker */
390
391
	cairo_arc(dctx, (double)cx,
			(double)cy, max_r, 0, 2*M_PI);
Thomas White's avatar
Thomas White committed
392
393
394
	cairo_set_source_rgb(dctx, 1.0, 0.0, 0.0);
	cairo_fill(dctx);

395
	/* Draw indexing lines */
396
	cairo_set_line_cap(dctx, CAIRO_LINE_CAP_ROUND);
397
	cairo_set_line_width(dctx, 4.0);
398
	cairo_move_to(dctx, (double)cx, (double)cy);
Thomas White's avatar
Thomas White committed
399
400
	u = rmax*sin(theta);
	v = rmax*cos(theta);
401
	cairo_line_to(dctx, cx+u*scale, cy+v*scale);
402
403
404
	cairo_set_source_rgb(dctx, 0.0, 1.0, 0.0);
	cairo_stroke(dctx);

405
	cairo_set_font_size(dctx, 40.0);
406
	snprintf(tmp, 255, "%i%i%i", abs(xh), abs(xk), abs(xl));
407
408
409
	cairo_text_extents(dctx, tmp, &size);

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

413
	snprintf(tmp, 255, "%i%i%i", abs(yh), abs(yk), abs(yl));
414
415
416
	cairo_text_extents(dctx, tmp, &size);

	cairo_move_to(dctx, (double)cx, (double)cy);
Thomas White's avatar
Thomas White committed
417
	cairo_line_to(dctx, cx, cy+rmax*scale);
418
419
420
	cairo_set_source_rgb(dctx, 0.0, 1.0, 0.0);
	cairo_stroke(dctx);

Thomas White's avatar
Thomas White committed
421
422
	cairo_move_to(dctx, cx - size.width/2.0,
	                    cy+rmax*scale + size.height + 20.0);
423
	render_overlined_indices(dctx, yh, yk, yl);
424
425
	cairo_fill(dctx);

426
427
428
429
430
431
432
	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
433
434
435
	cairo_surface_finish(surface);
	cairo_destroy(dctx);
}
436

437

438
static int render_key(int colscale, double scale_top)
439
440
441
{
	cairo_surface_t *surface;
	cairo_t *dctx;
442
443
	double top, wh, ht, y;
	double slice;
444

445
446
447
448
449
450
451
452
453
	wh = 128.0;
	ht = 1024.0;
	slice = 1.0;

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

455
	surface = cairo_pdf_surface_create(KEY_FILENAME, wh, ht);
456
457
458
459
460
461
462
463
464

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

465
	for ( y=0.0; y<ht; y+=slice ) {
466

467
468
469
		double r, g, b;
		double val;
		double v = y;
470

471
472
473
474
475
476
477
478
479
480
481
		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;
		}
482

483
		render_scale(val, top, colscale, &r, &g, &b);
484
485
		cairo_set_source_rgb(dctx, r, g, b);

486
		cairo_stroke_preserve(dctx);
487
488
489
490
		cairo_fill(dctx);

	}

491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
	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);

	}


520
521
522
	cairo_surface_finish(surface);
	cairo_destroy(dctx);

523
524
	STATUS("Colour key written to "KEY_FILENAME"\n");

525
526
	return 0;
}
527
528
529
530
531


#else  /* HAVE_CAIRO */


532
static int render_key(int colscale, double scale_top)
533
534
535
536
537
538
539
540
{
	ERROR("This version of CrystFEL was compiled without Cairo");
	ERROR(" support, which is required to draw the colour");
	ERROR(" scale.  Sorry!\n");
	return 1;
}


541
static void render_za(UnitCell *cell, RefList *list,
542
543
544
                      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,
545
                      const char *outfile, double scale_top)
546
547
548
549
550
551
552
553
{
	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
554
555
556
557
558
559


int main(int argc, char *argv[])
{
	int c;
	UnitCell *cell;
Thomas White's avatar
Thomas White committed
560
	RefList *list;
Thomas White's avatar
Thomas White committed
561
	char *infile;
Thomas White's avatar
Thomas White committed
562
	int config_sqrt = 0;
563
	int config_colkey = 0;
564
	int config_zawhinge = 0;
565
	char *pdb = NULL;
566
	int r = 0;
567
	double boost = 1.0;
Thomas White's avatar
Thomas White committed
568
569
	char *sym_str = NULL;
	SymOpList *sym;
570
571
	char *weighting = NULL;
	int wght;
572
573
	int colscale;
	char *cscale = NULL;
574
575
576
577
	signed int dh=1, dk=0, dl=0;
	signed int rh=0, rk=1, rl=0;
	char *down = NULL;
	char *right = NULL;
578
	char *outfile = NULL;
579
580
	double scale_top = -1.0;
	char *endptr;
Thomas White's avatar
Thomas White committed
581
582
583
584

	/* Long options */
	const struct option longopts[] = {
		{"help",               0, NULL,               'h'},
585
		{"zone-axis",          0, &config_zawhinge,    1},
586
		{"output",             1, NULL,               'o'},
587
		{"pdb",                1, NULL,               'p'},
588
		{"boost",              1, NULL,               'b'},
589
		{"symmetry",           1, NULL,               'y'},
590
		{"weighting",          1, NULL,               'w'},
591
		{"colscale",           1, NULL,               'c'},
592
593
		{"down",               1, NULL,               'd'},
		{"right",              1, NULL,               'r'},
594
		{"counts",             0, &config_sqrt,        1},
595
		{"colour-key",         0, &config_colkey,      1},
596
		{"scale-top",          1, NULL,                2},
Thomas White's avatar
Thomas White committed
597
598
599
600
		{0, 0, NULL, 0}
	};

	/* Short options */
Thomas White's avatar
Thomas White committed
601
	while ((c = getopt_long(argc, argv, "hp:w:c:y:d:r:o:",
602
	                        longopts, NULL)) != -1) {
Thomas White's avatar
Thomas White committed
603
604

		switch (c) {
Thomas White's avatar
Thomas White committed
605
		case 'h' :
Thomas White's avatar
Thomas White committed
606
607
608
			show_help(argv[0]);
			return 0;

609
610
611
612
		case 'p' :
			pdb = strdup(optarg);
			break;

613
614
615
616
		case 'b' :
			boost = atof(optarg);
			break;

617
		case 'y' :
Thomas White's avatar
Thomas White committed
618
			sym_str = strdup(optarg);
619
620
			break;

621
622
623
624
		case 'w' :
			weighting = strdup(optarg);
			break;

625
626
627
628
		case 'c' :
			cscale = strdup(optarg);
			break;

629
630
631
632
633
634
635
636
		case 'd' :
			down = strdup(optarg);
			break;

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

637
638
639
640
		case 'o' :
			outfile = strdup(optarg);
			break;

641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
		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
656
		case 0 :
Thomas White's avatar
Thomas White committed
657
658
			break;

Thomas White's avatar
Thomas White committed
659
		default :
Thomas White's avatar
Thomas White committed
660
661
662
663
664
			return 1;
		}

	}

665
	if ( config_zawhinge ) {
666
667
668
669
		ERROR("Friendly warning: The --zone-axis option isn't needed"
		      " any longer (I ignored it for you).\n");
	}

670
671
672
	if ( (pdb == NULL) && !config_colkey ) {
		ERROR("You must specify the PDB containing the unit cell.\n");
		return 1;
673
674
	}

Thomas White's avatar
Thomas White committed
675
676
	if ( sym_str == NULL ) {
		sym_str = strdup("1");
677
	}
Thomas White's avatar
Thomas White committed
678
679
	sym = get_pointgroup(sym_str);
	free(sym_str);
680

681
682
683
684
	if ( weighting == NULL ) {
		weighting = strdup("I");
	}

685
	if ( outfile == NULL ) outfile = strdup("za.pdf");
Thomas White's avatar
Thomas White committed
686

687
688
689
690
691
692
	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;
693
694
	} else if ( strcmp(weighting, "counts") == 0 ) {
		wght = WGHT_COUNTS;
695
696
	} else if ( strcmp(weighting, "rawcts") == 0 ) {
		wght = WGHT_RAWCOUNTS;
697
698
699
700
	} else if ( strcmp(weighting, "rawcount") == 0 ) {
		wght = WGHT_RAWCOUNTS;
	} else if ( strcmp(weighting, "rawcounts") == 0 ) {
		wght = WGHT_RAWCOUNTS;
701
702
703
704
	} else {
		ERROR("Unrecognised weighting '%s'\n", weighting);
		return 1;
	}
705
706
707
708
709
710
711
712
713
714
715
716
717
718
	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;
719
720
	} else if ( strcmp(cscale, "ratio") == 0 ) {
		colscale = SCALE_RATIO;
721
722
723
724
725
	} else {
		ERROR("Unrecognised colour scale '%s'\n", cscale);
		return 1;
	}
	free(cscale);
726

727
	if ( config_colkey ) {
728
		return render_key(colscale, scale_top);
729
730
	}

731
732
733
734
735
736
737
738
739
740
741
	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");
742
743
			return 1;
		}
744
745
746
747
748
749
750
	}
	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;
751
752
753
		}
	}

Thomas White's avatar
Thomas White committed
754
755
	infile = argv[optind];

756
	cell = load_cell_from_pdb(pdb);
757
758
759
760
	if ( cell == NULL ) {
		ERROR("Couldn't load unit cell from %s\n", pdb);
		return 1;
	}
Thomas White's avatar
Thomas White committed
761
762
763
	list = read_reflections(infile);
	if ( list == NULL ) {
		ERROR("Couldn't read file '%s'\n", infile);
Thomas White's avatar
Thomas White committed
764
765
		return 1;
	}
Thomas White's avatar
Thomas White committed
766
	if ( check_list_symmetry(list, sym) ) {
Thomas White's avatar
Thomas White committed
767
		ERROR("The input reflection list does not appear to"
Thomas White's avatar
Thomas White committed
768
		      " have symmetry %s\n", symmetry_name(sym));
Thomas White's avatar
Thomas White committed
769
770
		return 1;
	}
Thomas White's avatar
Thomas White committed
771

772
773
	render_za(cell, list, boost, sym, wght, colscale,
	          rh, rk, rl, dh, dk, dl, outfile, scale_top);
Thomas White's avatar
Thomas White committed
774

775
	free(pdb);
Thomas White's avatar
Thomas White committed
776
	free_symoplist(sym);
Thomas White's avatar
Thomas White committed
777
	reflist_free(list);
778
	if ( outfile != NULL ) free(outfile);
779

780
	return r;
781
}