File: ann2fig.cpp

package info (click to toggle)
ann 1.1.2%2Bdoc-3
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 2,104 kB
  • sloc: cpp: 4,422; makefile: 286; sh: 16
file content (587 lines) | stat: -rw-r--r-- 21,507 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
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
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
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
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
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
458
459
460
461
462
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
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
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
//----------------------------------------------------------------------
// File:			ann2fig.cpp
// Programmer:		David Mount
// Last modified:	05/03/05
// Description:		convert ann dump file to fig file
//----------------------------------------------------------------------
// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
// David Mount.  All Rights Reserved.
// 
// This software and related documentation is part of the Approximate
// Nearest Neighbor Library (ANN).  This software is provided under
// the provisions of the Lesser GNU Public License (LGPL).  See the
// file ../ReadMe.txt for further information.
// 
// The University of Maryland (U.M.) and the authors make no
// representations about the suitability or fitness of this software for
// any purpose.  It is provided "as is" without express or implied
// warranty.
//----------------------------------------------------------------------
// History:
//	Revision 0.1  03/04/98
//		Initial release
//	Revision 1.0  04/01/05
//		Changed dump file suffix from .ann to .dmp.
//	Revision 1.1  05/03/05
//		Fixed usage output string.
//----------------------------------------------------------------------
//	This program inputs an ann dump file of a search structure
//	perhaps along with point coordinates, and outputs a fig (Ver 3.1)
//	file (see fig2dev (1)) displaying the tree.  The fig file may
//	then be displayed using xfig, or converted to any of a number of
//	other formats using fig2dev.
//
//	If the dimension is 2 then the entire tree is display.  If the
//	dimension is larger than 2 then the user has the option of
//	selecting which two dimensions will be displayed, and the slice
//	value for each of the remaining dimensions.  All leaf cells
//	intersecting the slice are shown along with the points in these
//	cells. See the procedure getArgs() below for the command-line
//	arguments.
//----------------------------------------------------------------------

#include <cstdio>						// C standard I/O
#include <cstdlib>						// standard lib defs
#include <cstring>						// C strings
#include <fstream>						// file I/O
#include <string>						// string manipulation
#include <ANN/ANNx.h>					// all ANN includes

using namespace std;					// make std:: accessible

//----------------------------------------------------------------------
// Globals and their defaults
//----------------------------------------------------------------------

const int		STRING_LEN		= 500;	// string lengths
const int		MAX_DIM			= 1000; // maximum dimension
const double	DEF_SLICE_VAL	= 0;	// default slice value
const char		FIG_HEAD[]		= {"#FIG 3.1"}; // fig file header
const char		DUMP_SUFFIX[]	= {".dmp"};	// suffix for dump file
const char		FIG_SUFFIX[]	= {".fig"};	// suffix for fig file

char			file_name[STRING_LEN];	// (root) file name (say xxx)
char			infile_name[STRING_LEN];// input file name (xxx.dmp)
char			outfile_name[STRING_LEN];// output file name (xxx.fig)
char			caption[STRING_LEN];	// caption line (= command line)
ofstream		ofile;					// output file stream
ifstream		ifile;					// input file stream
int				dim_x = 0;				// horizontal dimension
int				dim_y = 1;				// vertical dimension
double			slice_val[MAX_DIM];		// array of slice values
double			u_per_in = 1200;		// fig units per inch (version 3.1)
double			in_size = 5;			// size of figure (in inches)
double			in_low_x = 1;			// fig upper left corner (in inches)
double			in_low_y = 1;			// fig upper left corner (in inches)
double			u_size = 6000;			// size of figure (in units)
double			u_low_x = 1200;			// fig upper left corner (in units)
double			u_low_y = 1200;			// fig upper left corner (in units)
int				pt_size = 10;			// point size (in fig units)

int				dim;					// dimension
int				n_pts;					// number of points
ANNpointArray	pts = NULL;				// point array

double			scale;					// scale factor for transformation
double			offset_x;				// offsets for transformation
double			offset_y;

										// transformations
#define TRANS_X(p)		(offset_x + scale*(p[dim_x]))
#define TRANS_Y(p)		(offset_y - scale*(p[dim_y]))

//----------------------------------------------------------------------
//	Error handler
//----------------------------------------------------------------------

void Error(const char* msg, ANNerr level)
{
	if (level == ANNabort) {
		cerr << "ann2fig: ERROR------->" << msg << "<-------------ERROR\n";
		exit(1);
	}
	else {
		cerr << "ann2fig: WARNING----->" << msg << "<-------------WARNING\n";
	}
}

//----------------------------------------------------------------------
// set_slice_val - set all slice values to given value
//----------------------------------------------------------------------

void set_slice_val(double val)
{
	for (int i = 0; i < MAX_DIM; i++) {
		slice_val[i] = val;
	}
}

//----------------------------------------------------------------------
// getArgs - get input arguments
//
//		Syntax:
//		ann2fig [-upi scale] [-x low_x] [-y low_y] 
//				[-sz size] [-dx dim_x] [-dy dim_y] [-sl dim value]*
//				[-ps pointsize]
//				file
//		
//		where:
//			-upi scale			fig units per inch (default = 1200)
//			-x low_x			x and y offset of upper left corner (inches)
//			-y low_y			...(default = 1)
//			-sz size			maximum side length of figure (in inches)
//								...(default = 5)
//			-dx dim_x			horizontal dimension (default = 0)
//			-dy dim_y			vertical dimension (default = 1)
//			-sv value			default slice value (default = 0)
//			-sl dim value		each such pair defines the value along the
//								...given dimension at which to slice.  This
//								...may be supplied for all dimensions except
//								...dim_x and dim_y.
//			-ps pointsize		size of points in fig units (def = 10)
//			file				file (input=file.dmp, output=file.fig)
//
//----------------------------------------------------------------------

void getArgs(int argc, char **argv)
{
	int i;
	int sl_dim;									// temp slice dimension
	double sl_val;								// temp slice value

	set_slice_val(DEF_SLICE_VAL);				// set initial slice-values

	if (argc <= 1) {
		cerr << "Syntax:\n\
        ann2fig [-upi scale] [-x low_x] [-y low_y]\n\
                [-sz size] [-dx dim_x] [-dy dim_y] [-sl dim value]*\n\
                file\n\
        \n\
        where:\n\
            -upi scale          fig units per inch (default = 1200)\n\
            -x low_x            x and y offset of upper left corner (inches)\n\
            -y low_y            ...(default = 1)\n\
            -sz size            maximum side length of figure (in inches)\n\
                                ...(default = 5)\n\
            -dx dim_x           horizontal dimension (default = 0)\n\
            -dy dim_y           vertical dimension (default = 1)\n\
            -sv value           default slice value (default = 0)\n\
            -sl dim value       each such pair defines the value along the\n\
                                ...given dimension at which to slice.  This\n\
                                ...may be supplied for each dimension except\n\
                                ...dim_x and dim_y.\n\
            -ps pointsize       size of points in fig units (def = 10)\n\
            file                file (input=file.dmp, output=file.fig)\n";
		exit(0);
	}

	ANNbool fileSeen = ANNfalse;				// file argument seen?

	for (i = 1; i < argc; i++) {
		if (!strcmp(argv[i], "-upi")) {			// process -upi option
			sscanf(argv[++i], "%lf", &u_per_in);
		}
		else if (!strcmp(argv[i], "-x")) {		// process -x option
			sscanf(argv[++i], "%lf", &in_low_x);
		}
		else if (!strcmp(argv[i], "-y")) {		// process -y option
			sscanf(argv[++i], "%lf", &in_low_y);
		}
		else if (!strcmp(argv[i], "-sz")) {		// process -sz option
			sscanf(argv[++i], "%lf", &in_size);
		}
		else if (!strcmp(argv[i], "-dx")) {		// process -dx option
			sscanf(argv[++i], "%d", &dim_x);
		}
		else if (!strcmp(argv[i], "-dy")) {		// process -dy option
			sscanf(argv[++i], "%d", &dim_y);
		}
		else if (!strcmp(argv[i], "-sv")) {		// process -sv option
			sscanf(argv[++i], "%lf", &sl_val);
			set_slice_val(sl_val);				// set slice values
		}
		else if (!strcmp(argv[i], "-sl")) {		// process -sl option
			sscanf(argv[++i], "%d", &sl_dim);
			if (sl_dim < 0 || sl_dim >= MAX_DIM) {
				Error("Slice dimension out of bounds", ANNabort);
			}
			sscanf(argv[++i], "%lf", &slice_val[sl_dim]);
		}
		if (!strcmp(argv[i], "-ps")) {			// process -ps option
			sscanf(argv[++i], "%i", &pt_size);
		}
		else {									// must be file name
			fileSeen = ANNtrue;
			sscanf(argv[i], "%s", file_name);
			strcpy(infile_name, file_name);		// copy to input file name
	    	strcat(infile_name, DUMP_SUFFIX);
	    	strcpy(outfile_name, file_name);	// copy to output file name
	    	strcat(outfile_name, FIG_SUFFIX);
		}
	}

	if (!fileSeen) {							// no file seen
		Error("File argument is required", ANNabort);
	}

	ifile.open(infile_name, ios::in);			// open for reading
	if (!ifile) {
		Error("Cannot open input file", ANNabort);
	}
	ofile.open(outfile_name, ios::out);			// open for writing
	if (!ofile) {
		Error("Cannot open output file", ANNabort);
	}

	u_low_x = u_per_in * in_low_x;				// convert inches to fig units
	u_low_y = u_per_in * in_low_y;
	u_size  = u_per_in * in_size;

	strcpy(caption, argv[0]);					// copy command line to caption
	for (i = 1; i < argc; i++) {
		strcat(caption, " ");
		strcat(caption, argv[i]);
	}
}

//----------------------------------------------------------------------
// Graphics utilities for fig output
//
//		writeHeader				write header for fig file
//		writePoint				write a point
//		writeBox				write a box
//		writeLine				write a line
//----------------------------------------------------------------------

void writeHeader()
{
	ofile << FIG_HEAD << "\n"					// fig file header
		 << "Portrait\n"
		 << "Center\n"
		 << "Inches\n"
		 << (int) u_per_in << " 2\n";
}

void writePoint(ANNpoint p)						// write a single point
{
												// filled black point object
	ofile << "1 3 0 1 -1 7 0 0 0 0.000 1 0.0000 ";
	int cent_x = (int) TRANS_X(p);				// transform center coords
	int cent_y = (int) TRANS_Y(p);
	ofile << cent_x << " " << cent_y << " "		// write center, radius, bounds
		 << pt_size << " " << pt_size << " "
		 << cent_x << " " << cent_y << " "
		 << cent_x + pt_size << " " << cent_y + pt_size << "\n";
}

void writeBox(const ANNorthRect &r)				// write box
{
												// unfilled box object
	ofile << "2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5\n";

	int p0_x = (int) TRANS_X(r.lo);				// transform endpoints
	int p0_y = (int) TRANS_Y(r.lo);
	int p1_x = (int) TRANS_X(r.hi);
	int p1_y = (int) TRANS_Y(r.hi);
	ofile << "\t"
		 << p0_x << " " << p0_y << " "			// write vertices
		 << p1_x << " " << p0_y << " "
		 << p1_x << " " << p1_y << " "
		 << p0_x << " " << p1_y << " "
		 << p0_x << " " << p0_y << "\n";
}

void writeLine(ANNpoint p0, ANNpoint p1)		// write line
{
												// unfilled line object
	ofile << "2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2\n";

	int p0_x = (int) TRANS_X(p0);				// transform endpoints
	int p0_y = (int) TRANS_Y(p0);
	int p1_x = (int) TRANS_X(p1);
	int p1_y = (int) TRANS_Y(p1);
	ofile << "\t"
		 << p0_x << " " << p0_y << " "			// write vertices
		 << p1_x << " " << p1_y << "\n";
}

void writeCaption(								// write caption text
	const ANNorthRect	&bnd_box,				// bounding box
	char				*caption)				// caption
{
	if (!strcmp(caption, "\0")) return;			// null string?
	int px = (int) TRANS_X(bnd_box.lo);			// put .5 in. lower left
	int py = (int) (TRANS_Y(bnd_box.lo) + 0.50 * u_per_in); 
	ofile << "4 0 -1 0 0 0 20 0.0000 4 255 2000 ";
	ofile << px << " " << py << " " << caption << "\\001\n";
}

//----------------------------------------------------------------------
// overlap - test whether a box overlap slicing region
//
//		The slicing region is a 2-dimensional plane in space
//		which contains points (x1, x2, ..., xn) satisfying the
//		n-2 linear equalities:
//
//						xi == slice_val[i]		for i != dim_x, dim_y
//
//		This procedure returns true of the box defined by
//		corner points box.lo and box.hi overlap this plane.
//----------------------------------------------------------------------

ANNbool overlap(const ANNorthRect &box)
{
	for (int i = 0; i < dim; i++) {
		if (i != dim_x && i != dim_y &&
		   (box.lo[i] > slice_val[i] || box.hi[i] < slice_val[i]))
			return ANNfalse;
	}
	return ANNtrue;
}

//----------------------------------------------------------------------
// readTree, recReadTree - inputs tree and outputs figure
//
//		readTree procedure initializes things and then calls recReadTree
//		which does all the work.
//
//		recReadTree reads in a node of the tree, makes any recursive
//		calls as needed to input the children of this node (if internal)
//		and maintains the bounding box.  Note that the bounding box
//		is modified within this procedure, but it is the responsibility
//		of the procedure that it be restored to its original value
//		on return.
//
//		Recall that these are the formats.  The tree is given in
//		preorder.
//
//		Leaf node:
//				leaf <n_pts> <bkt[0]> <bkt[1]> ... <bkt[n-1]>
//		Splitting nodes:
//				split <cut_dim> <cut_val> <lo_bound> <hi_bound>
//		Shrinking nodes:
//				shrink <n_bnds>
//						<cut_dim> <cut_val> <side>
//						<cut_dim> <cut_val> <side>
//						... (repeated n_bnds times)
//
//		On reading a leaf we determine whether we should output the
//		cell's points (if dimension = 2 or this cell overlaps the
//		slicing region).  For splitting nodes we check whether the
//		current cell overlaps the slicing plane and whether the
//		cutting dimension coincides with either the x or y drawing
//		dimensions.  If so, we output the corresponding splitting
//		segment.
//----------------------------------------------------------------------

void recReadTree(ANNorthRect &box)
{
	char tag[STRING_LEN];						// tag (leaf, split, shrink)
	int n_pts;									// number of points in leaf
	int idx;									// point index
	int cd;										// cut dimension
	ANNcoord cv;								// cut value
	ANNcoord lb;								// low bound
	ANNcoord hb;								// high bound
	int n_bnds;									// number of bounding sides
	int sd;										// which side

	ifile >> tag;								// input node tag
	if (strcmp(tag, "leaf") == 0) {				// leaf node

		ifile >> n_pts;							// input number of points
												// check for overlap
		if (dim == 2 || overlap(box)) { 
			for (int i = 0; i < n_pts; i++) {	// yes, write the points
				ifile >> idx;
				writePoint(pts[idx]);
			}
		}
		else {									// input but ignore points
			for (int i = 0; i < n_pts; i++) {
				ifile >> idx;
			}
		}
	}
	else if (strcmp(tag, "split") == 0) {		// splitting node

		ifile >> cd >> cv >> lb >> hb;
		if (lb != box.lo[cd] || hb != box.hi[cd]) {
			Error("Bounding box coordinates are fishy", ANNwarn);
		}

		ANNcoord lv = box.lo[cd];				// save bounds for cutting dim
		ANNcoord hv = box.hi[cd];

		//--------------------------------------------------------------
		//	The following code is rather fragile so modify at your
		//	own risk.  We first decrease the high-end of the bounding
		//	box down to the cutting plane and then read the left subtree.
		//	Then we increase the low-end of the bounding box up to the
		//	cutting plane (thus collapsing the bounding box to a d-1
		//	dimensional hyperrectangle).  Then we draw the projection of
		//	its diagonal if it crosses the slicing plane.  This will have
		//	the effect of drawing its intersection on the slicing plane.
		//	Then we restore the high-end of the bounding box and read
		//	the right subtree.  Finally we restore the low-end of the
		//	bounding box, before returning.
		//--------------------------------------------------------------
		box.hi[cd] = cv;						// decrease high bounds
		recReadTree(box);						// read left subtree
												// check for overlap
		box.lo[cd] = cv;						// increase low bounds
		if (dim == 2 || overlap(box)) {			// check for overlap
			if (cd == dim_x || cd == dim_y) {	// cut through slice plane
				writeLine(box.lo, box.hi);		// draw cutting line
			}
		}
		box.hi[cd] = hv;						// restore high bounds

		recReadTree(box);						// read right subtree
		box.lo[cd] = lv;						// restore low bounds
	}
	else if (strcmp(tag, "shrink") == 0) {		// splitting node

		ANNorthRect inner(dim, box);			// copy bounding box
		ifile >> n_bnds;						// number of bounding sides
		for (int i = 0; i < n_bnds; i++) {
			ifile >> cd >> cv >> sd;			// input bounding halfspace
			ANNorthHalfSpace hs(cd, cv, sd);	// create orthogonal halfspace
			hs.project(inner.lo);				// intersect by projecting
			hs.project(inner.hi);
		}
		if (dim == 2 || overlap(inner)) {
			writeBox(inner);					// draw inner rectangle
		}
		recReadTree(inner);						// read inner subtree
		recReadTree(box);						// read outer subtree
	}
	else {
		Error("Illegal node type in dump file", ANNabort);
	}
}

void readTree(ANNorthRect &bnd_box)
{
	writeHeader();								// output header
	writeBox(bnd_box);							// draw bounding box
	writeCaption(bnd_box, caption);				// write caption
	recReadTree(bnd_box);						// do it
}

//----------------------------------------------------------------------
// readANN - read the ANN dump file
//
//		This procedure reads in the dump file.  See the format below.
//		It first reads the header line with version number.  If the
//		points section is present it reads them (otherwise just leaves
//		points = NULL), and then it reads the tree section.  It inputs
//		the bounding box and determines the parameters for transforming
//		the image to figure units.  It then invokes the procedure
//		readTree to do all the real work.
//
//		Dump File Format: <xxx> = coordinate value (ANNcoord)
//
//		#ANN <version number> <comments> [END_OF_LINE]
//		points <dim> <n_pts>			(point coordinates: this is optional)
//		0 <xxx> <xxx> ... <xxx>			(point indices and coordinates)
//		1 <xxx> <xxx> ... <xxx>
//		  ...
//		tree <dim> <n_pts> <bkt_size>
//		<xxx> <xxx> ... <xxx>			(lower end of bounding box)
//		<xxx> <xxx> ... <xxx>			(upper end of bounding box)
//				If the tree is null, then a single line "null" is
//				output.  Otherwise the nodes of the tree are printed
//				one per line in preorder.  Leaves and splitting nodes 
//				have the following formats:
//		Leaf node:
//				leaf <n_pts> <bkt[0]> <bkt[1]> ... <bkt[n-1]>
//		Splitting nodes:
//				split <cut_dim> <cut_val> <lo_bound> <hi_bound>
//		Shrinking nodes:
//				shrink <n_bnds>
//						<cut_dim> <cut_val> <side>
//						<cut_dim> <cut_val> <side>
//						... (repeated n_bnds times)
//
//		Note: Infinite lo_ and hi_bounds are printed as the special
//				values "-INF" and "+INF", respectively.  We do not
//				check for this, because the current version of ANN
//				starts with a finite bounding box if the tree is
//				nonempty.
//----------------------------------------------------------------------

void readANN()
{
	int j;
	char str[STRING_LEN];						// storage for string
    char version[STRING_LEN];					// storage for version
	int  bkt_size;								// bucket size

	ifile >> str;								// input header
	if (strcmp(str, "#ANN") != 0) {				// incorrect header
		Error("Incorrect header for dump file", ANNabort);
	}
    ifile.getline(version, STRING_LEN);			// get version (ignore)
	ifile >> str;								// get major heading
	if (strcmp(str, "points") == 0) {			// points section
		ifile >> dim;							// read dimension
		ifile >> n_pts;							// number of points
		pts = annAllocPts(n_pts, dim);			// allocate points
		for (int i = 0; i < n_pts; i++) {		// input point coordinates
			int idx;							// point index
			ifile >> idx;						// input point index
			if (idx < 0 || idx >= n_pts) {
				Error("Point index is out of range", ANNabort);
			}
			for (j = 0; j < dim; j++) {
				ifile >> pts[idx][j];			// read point coordinates
			}
		}
		ifile >> str;							// get next major heading
	}
	if (strcmp(str, "tree") == 0) {				// tree section
		ifile >> dim;							// read dimension
		if (dim_x > dim || dim_y > dim) {
			Error("Dimensions out of bounds", ANNabort);
		}
		ifile >> n_pts;							// number of points
		ifile >> bkt_size;						// bucket size (ignored)
												// read bounding box
		ANNorthRect bnd_box(dim);				// create bounding box
		for (j = 0; j < dim; j++) {
			ifile >> bnd_box.lo[j];				// read box low coordinates
		}
		for (j = 0; j < dim; j++) {
			ifile >> bnd_box.hi[j];				// read box high coordinates
		}
												// compute scaling factors
		double box_len_x = bnd_box.hi[dim_x] - bnd_box.lo[dim_x];
		double box_len_y = bnd_box.hi[dim_y] - bnd_box.lo[dim_y];
												// longer side determines scale
		if (box_len_x > box_len_y) scale = u_size/box_len_x;
		else					   scale = u_size/box_len_y;
												// compute offsets
		offset_x = u_low_x - scale*bnd_box.lo[dim_x];
		offset_y = u_low_y + scale*bnd_box.hi[dim_y];
		readTree(bnd_box);						// read the tree and process
	}
	else if (strcmp(str, "null") == 0) return;	// empty tree
	else {
		cerr << "Input string: " << str << "\n";
		Error("Illegal ann format.  Expecting section heading", ANNabort);
	}
}

//----------------------------------------------------------------------
// Main program
//
// Gets the command-line arguments and invokes the main scanning
// procedure.
//----------------------------------------------------------------------

main(int argc, char **argv)
{
	getArgs(argc, argv);						// get input arguments
	readANN();									// read the dump file
}