]> git.mxchange.org Git - flightgear.git/blob - Triangle/showme.c
Let's not pass copies of huge structures on the stack ... ye might see a
[flightgear.git] / Triangle / showme.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*    ,d88^^o 888                                   o    o                   */
4 /*    8888    888o^88,  o88^^o Y88b    o    /      d8b  d8b      o88^^8o     */
5 /*    "Y88b   888  888 d888   b Y88b  d8b  /      d888bdY88b    d888  88b    */
6 /*     "Y88b, 888  888 8888   8  Y888/Y88b/      / Y88Y Y888b   8888oo888    */
7 /*    o  8888 888  888 q888   p   Y8/  Y8/      /   YY   Y888b  q888         */
8 /*    "oo88P" 888  888  "88oo"     Y    Y      /          Y888b  "88oooo"    */
9 /*                                                                           */
10 /*  A Display Program for Meshes and More.                                   */
11 /*  (showme.c)                                                               */
12 /*                                                                           */
13 /*  Version 1.3                                                              */
14 /*  July 20, 1996                                                            */
15 /*                                                                           */
16 /*  Copyright 1996                                                           */
17 /*  Jonathan Richard Shewchuk                                                */
18 /*  School of Computer Science                                               */
19 /*  Carnegie Mellon University                                               */
20 /*  5000 Forbes Avenue                                                       */
21 /*  Pittsburgh, Pennsylvania  15213-3891                                     */
22 /*  jrs@cs.cmu.edu                                                           */
23 /*                                                                           */
24 /*  This program may be freely redistributed under the condition that the    */
25 /*    copyright notices (including this entire header and the copyright      */
26 /*    notice printed when the `-h' switch is selected) are not removed, and  */
27 /*    no compensation is received.  Private, research, and institutional     */
28 /*    use is free.  You may distribute modified versions of this code UNDER  */
29 /*    THE CONDITION THAT THIS CODE AND ANY MODIFICATIONS MADE TO IT IN THE   */
30 /*    SAME FILE REMAIN UNDER COPYRIGHT OF THE ORIGINAL AUTHOR, BOTH SOURCE   */
31 /*    AND OBJECT CODE ARE MADE FREELY AVAILABLE WITHOUT CHARGE, AND CLEAR    */
32 /*    NOTICE IS GIVEN OF THE MODIFICATIONS.  Distribution of this code as    */
33 /*    part of a commercial system is permissible ONLY BY DIRECT ARRANGEMENT  */
34 /*    WITH THE AUTHOR.  (If you are not directly supplying this code to a    */
35 /*    customer, and you are instead telling them how they can obtain it for  */
36 /*    free, then you are not required to make any arrangement with me.)      */
37 /*                                                                           */
38 /*  Hypertext instructions for Triangle are available on the Web at          */
39 /*                                                                           */
40 /*      http://www.cs.cmu.edu/~quake/showme.html                             */
41 /*                                                                           */
42 /*  Show Me was created as part of the Archimedes project in the School of   */
43 /*    Computer Science at Carnegie Mellon University.  Archimedes is a       */
44 /*    system for compiling parallel finite element solvers.  For further     */
45 /*    information, see Anja Feldmann, Omar Ghattas, John R. Gilbert, Gary L. */
46 /*    Miller, David R. O'Hallaron, Eric J. Schwabe, Jonathan R. Shewchuk,    */
47 /*    and Shang-Hua Teng.  "Automated Parallel Solution of Unstructured PDE  */
48 /*    Problems."  To appear in Communications of the ACM, we hope.           */
49 /*                                                                           */
50 /*  If you make any improvements to this code, please please please let me   */
51 /*    know, so that I may obtain the improvements.  Even if you don't change */
52 /*    the code, I'd still love to hear what it's being used for.             */
53 /*                                                                           */
54 /*  Disclaimer:  Neither I nor Carnegie Mellon warrant this code in any way  */
55 /*    whatsoever.  Use at your own risk.                                     */
56 /*                                                                           */
57 /*****************************************************************************/
58
59 /* For single precision (which will save some memory and reduce paging),     */
60 /*   write "#define SINGLE" below.                                           */
61 /*                                                                           */
62 /* For double precision (which will allow you to display triangulations of   */
63 /*   a finer resolution), leave SINGLE undefined.                            */
64
65 /* #define SINGLE */
66
67 #ifdef SINGLE
68 #define REAL float
69 #else
70 #define REAL double
71 #endif
72
73 /* Maximum number of characters in a file name (including the null).         */
74
75 #define FILENAMESIZE 1024
76
77 /* Maximum number of characters in a line read from a file (including the    */
78 /*   null).                                                                  */
79
80 #define INPUTLINESIZE 512
81
82 #define STARTWIDTH 414
83 #define STARTHEIGHT 414
84 #define MINWIDTH 50
85 #define MINHEIGHT 50
86 #define BUTTONHEIGHT 21
87 #define BUTTONROWS 3
88 #define PANELHEIGHT (BUTTONHEIGHT * BUTTONROWS)
89 #define MAXCOLORS 64
90
91 #define IMAGE_TYPES 7
92 #define NOTHING -1
93 #define NODE 0
94 #define POLY 1
95 #define ELE 2
96 #define EDGE 3
97 #define PART 4
98 #define ADJ 5
99 #define VORO 6
100
101 #define STARTEXPLOSION 0.5
102
103 #include <stdio.h>
104 #include <string.h>
105 #include <X11/Xlib.h>
106 #include <X11/Xutil.h>
107 #include <X11/Xatom.h>
108
109 /* The following obscenity seems to be necessary to ensure that this program */
110 /* will port to Dec Alphas running OSF/1, because their stdio.h file commits */
111 /* the unpardonable sin of including stdlib.h.  Hence, malloc(), free(), and */
112 /* exit() may or may not already be defined at this point.  I declare these  */
113 /* functions explicitly because some non-ANSI C compilers lack stdlib.h.     */
114
115 #ifndef _STDLIB_H_
116 extern char *malloc();
117 extern void free();
118 extern void exit();
119 extern double strtod();
120 extern long strtol();
121 #endif
122
123 /* A necessary forward declaration.                                          */
124
125 int load_image();
126
127 Display *display;
128 int screen;
129 Window rootwindow;
130 Window mainwindow;
131 Window quitwin;
132 Window leftwin;
133 Window rightwin;
134 Window upwin;
135 Window downwin;
136 Window resetwin;
137 Window pswin;
138 Window epswin;
139 Window expwin;
140 Window exppluswin;
141 Window expminuswin;
142 Window widthpluswin;
143 Window widthminuswin;
144 Window versionpluswin;
145 Window versionminuswin;
146 Window fillwin;
147 Window nodewin[2];
148 Window polywin[2];
149 Window elewin[2];
150 Window edgewin[2];
151 Window partwin[2];
152 Window adjwin[2];
153 Window voronoiwin[2];
154
155 int windowdepth;
156 XEvent event;
157 Colormap rootmap;
158 XFontStruct *font;
159 int width, height;
160 int black, white;
161 int showme_foreground;
162 GC fontgc;
163 GC blackfontgc;
164 GC linegc;
165 GC trianglegc;
166 int colors[MAXCOLORS];
167 XColor rgb[MAXCOLORS];
168 int color;
169
170 int start_image, current_image;
171 int start_inc, current_inc;
172 int loweriteration;
173 int line_width;
174 int loaded[2][IMAGE_TYPES];
175 REAL xlo[2][IMAGE_TYPES], ylo[2][IMAGE_TYPES];
176 REAL xhi[2][IMAGE_TYPES], yhi[2][IMAGE_TYPES];
177 REAL xscale, yscale;
178 REAL xoffset, yoffset;
179 int zoom;
180
181 int nodes[2], node_dim[2];
182 REAL *nodeptr[2];
183 int polynodes[2], poly_dim[2], polyedges[2], polyholes[2];
184 REAL *polynodeptr[2], *polyholeptr[2];
185 int *polyedgeptr[2];
186 int elems[2], ele_corners[2];
187 int *eleptr[2];
188 int edges[2];
189 int *edgeptr[2];
190 REAL *normptr[2];
191 int subdomains[2];
192 int *partpart[2];
193 REAL *partcenter[2], *partshift[2];
194 int adjsubdomains[2];
195 int *adjptr[2];
196 int vnodes[2], vnode_dim[2];
197 REAL *vnodeptr[2];
198 int vedges[2];
199 int *vedgeptr[2];
200 REAL *vnormptr[2];
201 int firstnumber[2];
202
203 int quiet, fillelem, bw_ps, explode;
204 REAL explosion;
205
206 char filename[FILENAMESIZE];
207 char nodefilename[2][FILENAMESIZE];
208 char polyfilename[2][FILENAMESIZE];
209 char elefilename[2][FILENAMESIZE];
210 char edgefilename[2][FILENAMESIZE];
211 char partfilename[2][FILENAMESIZE];
212 char adjfilename[2][FILENAMESIZE];
213 char vnodefilename[2][FILENAMESIZE];
214 char vedgefilename[2][FILENAMESIZE];
215
216 char *colorname[] = {"aquamarine", "red", "green yellow", "magenta",
217                      "yellow", "green", "orange", "blue",
218                      "white", "sandy brown", "cyan", "moccasin",
219                      "cadet blue", "coral", "cornflower blue", "sky blue",
220                      "firebrick", "forest green", "gold", "goldenrod",
221                      "gray", "hot pink", "chartreuse", "pale violet red",
222                      "indian red", "khaki", "lavender", "light blue",
223                      "light gray", "light steel blue", "lime green", "azure",
224                      "maroon", "medium aquamarine", "dodger blue", "honeydew",
225                      "medium orchid", "medium sea green", "moccasin",
226                      "medium slate blue", "medium spring green",
227                      "medium turquoise", "medium violet red",
228                      "orange red", "chocolate", "light goldenrod",
229                      "orchid", "pale green", "pink", "plum",
230                      "purple", "salmon", "sea green",
231                      "sienna", "slate blue", "spring green",
232                      "steel blue", "tan", "thistle", "turquoise",
233                      "violet", "violet red", "wheat",
234                      "yellow green"};
235
236 void syntax()
237 {
238   printf("showme [-bfw_Qh] input_file\n");
239   printf("    -b  Black and white PostScript (default is color).\n");
240   printf("    -f  Fill triangles of partitioned mesh with color.\n");
241   printf("    -w  Set line width to some specified number.\n");
242   printf("    -Q  Quiet:  No terminal output except errors.\n");
243   printf("    -h  Help:  Detailed instructions for Show Me.\n");
244   exit(0);
245 }
246
247 void info()
248 {
249   printf("Show Me\n");
250   printf("A Display Program for Meshes and More.\n");
251   printf("Version 1.3\n\n");
252   printf(
253 "Copyright 1996 Jonathan Richard Shewchuk  (bugs/comments to jrs@cs.cmu.edu)\n"
254 );
255   printf("School of Computer Science / Carnegie Mellon University\n");
256   printf("5000 Forbes Avenue / Pittsburgh, Pennsylvania  15213-3891\n");
257   printf(
258 "Created as part of the Archimedes project (tools for parallel FEM).\n");
259   printf(
260 "Supported in part by NSF Grant CMS-9318163 and an NSERC 1967 Scholarship.\n");
261   printf("There is no warranty whatsoever.  Use at your own risk.\n");
262 #ifdef SINGLE
263   printf("This executable is compiled for single precision arithmetic.\n\n\n");
264 #else
265   printf("This executable is compiled for double precision arithmetic.\n\n\n");
266 #endif
267   printf(
268 "Show Me graphically displays the contents of geometric files, especially\n");
269   printf(
270 "those generated by Triangle, my two-dimensional quality mesh generator and\n"
271 );
272   printf(
273 "Delaunay triangulator.  Show Me can also write images in PostScript form.\n");
274   printf(
275 "Show Me is also useful for checking the consistency of the files you create\n"
276 );
277   printf(
278 "as input to Triangle; Show Me does these checks more thoroughly than\n");
279   printf("Triangle does.  The command syntax is:\n\n");
280   printf("showme [-bfw_Qh] input_file\n\n");
281   printf(
282 "The underscore indicates that a number should follow the -w switch.\n");
283   printf(
284 "input_file may be one of several types of file.  It must have extension\n");
285   printf(
286 ".node, .poly, .ele, .edge, .part, or .adj.  If no extension is provided,\n");
287   printf(
288 "Show Me will assume the extension .ele.  A .node file represents a set of\n");
289   printf(
290 "points; a .poly file represents a Planar Straight Line Graph; an .ele file\n"
291 );
292   printf(
293 "(coupled with a .node file) represents the elements of a mesh or the\n");
294   printf(
295 "triangles of a triangulation; an .edge file (coupled with a .node file)\n");
296   printf(
297 "represents a set of edges; a .part file specifies a partition of a mesh;\n");
298   printf(
299 "and a .adj file represents the adjacency graph defined by a partition.\n");
300   printf("\n");
301   printf("Command Line Switches:\n");
302   printf("\n");
303   printf(
304 "    -b  Makes all PostScript output black and white.  If this switch is not\n"
305 );
306   printf(
307 "        selected, color PostScript is used for partitioned meshes and\n");
308   printf("        adjacency graphs (.part and .adj files).\n");
309   printf(
310 "    -f  On color displays and in color PostScript, displays partitioned\n");
311   printf(
312 "        meshes by filling triangles with color, rather than by coloring the\n"
313 );
314   printf(
315 "        edges.  This switch will result in a clearer picture if all\n");
316   printf(
317 "        triangles are reasonably large, and a less clear picture if small\n");
318   printf(
319 "        triangles are present.  (There is also a button to toggle this\n");
320   printf("        behavior.)\n");
321   printf(
322 "    -w  Followed by an integer, specifies the line width used in all\n");
323   printf(
324 "        images.  (There are also buttons to change the line width.)\n");
325   printf(
326 "    -Q  Quiet:  Suppresses all explanation of what Show Me is doing, unless\n"
327 );
328   printf("        an error occurs.\n");
329   printf("    -h  Help:  Displays these instructions.\n");
330   printf("\n");
331   printf("Controls:\n");
332   printf("\n");
333   printf(
334 "  To zoom in on an image, point at the location where you want a closer\n");
335   printf(
336 "  look, and click the left mouse button.  To zoom out, click the right\n");
337   printf(
338 "  mouse button.  In either case, the point you click on will be centered in\n"
339 );
340   printf(
341 "  the window.  If you want to know the coordinates of a point, click the\n");
342   printf(
343 "  middle mouse button; the coordinates will be printed on the terminal you\n"
344 );
345   printf("  invoked Show Me from.\n\n");
346   printf(
347 "  If you resize the window, the image will grow or shrink to match.\n");
348   printf("\n");
349   printf(
350 "  There is a panel of control buttons at the bottom of the Show Me window:\n"
351 );
352   printf("\n");
353   printf("  Quit:  Shuts down Show Me.\n");
354   printf("  <, >, ^, v:  Moves the image in the indicated direction.\n");
355   printf(
356 "  Reset: Unzooms and centers the image in the window.  When you switch from\n"
357 );
358   printf(
359 "    one image to another, the viewing region does not change, so you may\n");
360   printf(
361 "    need to reset the new image to make it fully visible.  This often is\n");
362   printf(
363 "    the case when switching between Delaunay triangulations and their\n");
364   printf(
365 "    corresponding Voronoi diagrams, as Voronoi vertices can be far from the\n"
366 );
367   printf("    initial point set.\n");
368   printf(
369 "  Width+, -:  Increases or decreases the width of all lines and points.\n");
370   printf(
371 "  Exp, +, -:  These buttons appear only when you are viewing a partitioned\n"
372 );
373   printf(
374 "    mesh (.part file).  `Exp' toggles between an exploded and non-exploded\n"
375 );
376   printf(
377 "    image of the mesh.  The non-exploded image will not show the partition\n"
378 );
379   printf(
380 "    on a black and white monitor.  `+' and `-' allow you to adjust the\n");
381   printf(
382 "    spacing between pieces of the mesh to better distinguish them.\n");
383   printf(
384 "  Fill:  This button appears only when you are viewing a partitioned mesh\n");
385   printf(
386 "    (.part file).  It toggles between color-filled triangles and colored\n");
387   printf(
388 "    edges (as the -f switch does).  Filled triangles look better when all\n");
389   printf(
390 "    triangles are reasonably large; colored edges look better when there\n");
391   printf("    are very small triangles present.\n");
392   printf(
393 "  PS:  Creates a PostScript file containing the image you are viewing.  If\n"
394 );
395   printf(
396 "    the -b switch is selected, all PostScript output will be black and\n");
397   printf(
398 "    white; otherwise, .part.ps and .adj.ps files will be color, independent\n"
399 );
400   printf(
401 "    of whether you are using a color monitor.  Normally the output will\n");
402   printf(
403 "    preserve the properties of the image you see on the screen, including\n");
404   printf(
405 "    zoom and line width; however, if black and white output is selected (-b\n"
406 );
407   printf(
408 "    switch), partitioned meshes will always be drawn exploded.  The output\n"
409 );
410   printf(
411 "    file name depends on the image being viewed.  If you want several\n");
412   printf(
413 "    different snapshots (zooming in on different parts) of the same object,\n"
414 );
415   printf(
416 "    you'll have to rename each file after Show Me creates it so that it\n");
417   printf("    isn't overwritten by the next snapshot.\n");
418   printf(
419 "  EPS:  Creates an encapsulated PostScript file, suitable for inclusion in\n"
420 );
421   printf(
422 "    documents.  Otherwise, this button is just like the PS button.  (The\n");
423   printf(
424 "    main difference is that .eps files lack a `showpage' command at the\n");
425   printf("    end.)\n\n");
426   printf(
427 "  There are two nearly-identical rows of buttons that load different images\n"
428 );
429   printf("  from disk.  Each row contains the following buttons:\n\n");
430   printf("  node:  Loads a .node file.\n");
431   printf(
432 "  poly:  Loads a .poly file (and possibly an associated .node file).\n");
433   printf("  ele:  Loads an .ele file (and associated .node file).\n");
434   printf("  edge:  Loads an .edge file (and associated .node file).\n");
435   printf(
436 "  part:  Loads a .part file (and associated .node and .ele files).\n");
437   printf(
438 "  adj:  Loads an .adj file (and associated .node, .ele, and .part files).\n");
439   printf("  voro:  Loads a .v.node and .v.edge file for a Voronoi diagram.\n");
440   printf("\n");
441   printf(
442 "  Each row represents a different iteration number of the geometry files.\n");
443   printf(
444 "  For a full explanation of iteration numbers, read the instructions for\n");
445   printf(
446 "  Triangle.  Briefly, iteration numbers are used to allow a user to easily\n"
447 );
448   printf(
449 "  represent a sequence of related triangulations.  Iteration numbers are\n");
450   printf(
451 "  used in the names of geometry files; for instance, mymesh.3.ele is a\n");
452   printf(
453 "  triangle file with iteration number three, and mymesh.ele has an implicit\n"
454 );
455   printf("  iteration number of zero.\n\n");
456   printf(
457 "  The control buttons at the right end of each row display the two\n");
458   printf(
459 "  iterations currently under view.  These buttons can be clicked to\n");
460   printf(
461 "  increase or decrease the iteration numbers, and thus conveniently view\n");
462   printf("  a sequence of meshes.\n\n");
463   printf(
464 "  Show Me keeps each file in memory after loading it, but you can force\n");
465   printf(
466 "  Show Me to reread a set of files (for one iteration number) by reclicking\n"
467 );
468   printf(
469 "  the button that corresponds to the current image.  This is convenient if\n"
470 );
471   printf("  you have changed a geometry file.\n\n");
472   printf("File Formats:\n\n");
473   printf(
474 "  All files may contain comments prefixed by the character '#'.  Points,\n");
475   printf(
476 "  segments, holes, triangles, edges, and subdomains must be numbered\n");
477   printf(
478 "  consecutively, starting from either 1 or 0.  Whichever you choose, all\n");
479   printf(
480 "  input files must be consistent (for any single iteration number); if the\n"
481 );
482   printf(
483 "  nodes are numbered from 1, so must be all other objects.  Show Me\n");
484   printf(
485 "  automatically detects your choice while reading a .node (or .poly) file.\n"
486 );
487   printf("  Examples of these file formats are given below.\n\n");
488   printf("  .node files:\n");
489   printf(
490 "    First line:  <# of points> <dimension (must be 2)> <# of attributes>\n");
491   printf(
492 "                                           <# of boundary markers (0 or 1)>\n"
493 );
494   printf(
495 "    Remaining lines:  <point #> <x> <y> [attributes] [boundary marker]\n");
496   printf("\n");
497   printf(
498 "    The attributes, which are typically floating-point values of physical\n");
499   printf(
500 "    quantities (such as mass or conductivity) associated with the nodes of\n"
501 );
502   printf(
503 "    a finite element mesh, are ignored by Show Me.  Show Me also ignores\n");
504   printf(
505 "    boundary markers.  See the instructions for Triangle to find out what\n");
506   printf("    attributes and boundary markers are.\n\n");
507   printf("  .poly files:\n");
508   printf(
509 "    First line:  <# of points> <dimension (must be 2)> <# of attributes>\n");
510   printf(
511 "                                           <# of boundary markers (0 or 1)>\n"
512 );
513   printf(
514 "    Following lines:  <point #> <x> <y> [attributes] [boundary marker]\n");
515   printf("    One line:  <# of segments> <# of boundary markers (0 or 1)>\n");
516   printf(
517 "    Following lines:  <segment #> <endpoint> <endpoint> [boundary marker]\n");
518   printf("    One line:  <# of holes>\n");
519   printf("    Following lines:  <hole #> <x> <y>\n");
520   printf("    [Optional additional lines that are ignored]\n\n");
521   printf(
522 "    A .poly file represents a Planar Straight Line Graph (PSLG), an idea\n");
523   printf(
524 "    familiar to computational geometers.  By definition, a PSLG is just a\n");
525   printf(
526 "    list of points and edges.  A .poly file also contains some additional\n");
527   printf("    information.\n\n");
528   printf(
529 "    The first section lists all the points, and is identical to the format\n"
530 );
531   printf(
532 "    of .node files.  <# of points> may be set to zero to indicate that the\n"
533 );
534   printf(
535 "    points are listed in a separate .node file; .poly files produced by\n");
536   printf(
537 "    Triangle always have this format.  When Show Me reads such a file, it\n");
538   printf("    also reads the corresponding .node file.\n\n");
539   printf(
540 "    The second section lists the segments.  Segments are edges whose\n");
541   printf(
542 "    presence in a triangulation produced from the PSLG is enforced.  Each\n");
543   printf(
544 "    segment is specified by listing the indices of its two endpoints.  This\n"
545 );
546   printf(
547 "    means that its endpoints must be included in the point list.  Each\n");
548   printf(
549 "    segment, like each point, may have a boundary marker, which is ignored\n"
550 );
551   printf("    by Show Me.\n\n");
552   printf(
553 "    The third section lists holes and concavities that are desired in any\n");
554   printf(
555 "    triangulation generated from the PSLG.  Holes are specified by\n");
556   printf("    identifying a point inside each hole.\n\n");
557   printf("  .ele files:\n");
558   printf(
559 "    First line:  <# of triangles> <points per triangle> <# of attributes>\n");
560   printf(
561 "    Remaining lines:  <triangle #> <point> <point> <point> ... [attributes]\n"
562 );
563   printf("\n");
564   printf(
565 "    Points are indices into the corresponding .node file.  Show Me ignores\n"
566 );
567   printf(
568 "    all but the first three points of each triangle; these should be the\n");
569   printf(
570 "    corners listed in counterclockwise order around the triangle.  The\n");
571   printf("    attributes are ignored by Show Me.\n\n");
572   printf("  .edge files:\n");
573   printf("    First line:  <# of edges> <# of boundary markers (0 or 1)>\n");
574   printf(
575 "    Following lines:  <edge #> <endpoint> <endpoint> [boundary marker]\n");
576   printf("\n");
577   printf(
578 "    Endpoints are indices into the corresponding .node file.  The boundary\n"
579 );
580   printf("    markers are ignored by Show Me.\n\n");
581   printf(
582 "    In Voronoi diagrams, one also finds a special kind of edge that is an\n");
583   printf(
584 "    infinite ray with only one endpoint.  For these edges, a different\n");
585   printf("    format is used:\n\n");
586   printf("        <edge #> <endpoint> -1 <direction x> <direction y>\n\n");
587   printf(
588 "    The `direction' is a floating-point vector that indicates the direction\n"
589 );
590   printf("    of the infinite ray.\n\n");
591   printf("  .part files:\n");
592   printf("    First line:  <# of triangles> <# of subdomains>\n");
593   printf("    Remaining lines:  <triangle #> <subdomain #>\n\n");
594   printf(
595 "    The set of triangles is partitioned by a .part file; each triangle is\n");
596   printf("    mapped to a subdomain.\n\n");
597   printf("  .adj files:\n");
598   printf("    First line:  <# of subdomains>\n");
599   printf("    Remaining lines:  <adjacency matrix entry>\n\n");
600   printf(
601 "    An .adj file represents adjacencies between subdomains (presumably\n");
602   printf("    computed by a partitioner).  The first line is followed by\n");
603   printf(
604 "    (subdomains X subdomains) lines, each containing one entry of the\n");
605   printf(
606 "    adjacency matrix.  A nonzero entry indicates that two subdomains are\n");
607   printf("    adjacent (share a point).\n\n");
608   printf("Example:\n\n");
609   printf(
610 "  Here is a sample file `box.poly' describing a square with a square hole:\n"
611 );
612   printf("\n");
613   printf(
614 "    # A box with eight points in 2D, no attributes, no boundary marker.\n");
615   printf("    8 2 0 0\n");
616   printf("    # Outer box has these vertices:\n");
617   printf("     1   0 0\n");
618   printf("     2   0 3\n");
619   printf("     3   3 0\n");
620   printf("     4   3 3\n");
621   printf("    # Inner square has these vertices:\n");
622   printf("     5   1 1\n");
623   printf("     6   1 2\n");
624   printf("     7   2 1\n");
625   printf("     8   2 2\n");
626   printf("    # Five segments without boundary markers.\n");
627   printf("    5 0\n");
628   printf("     1   1 2          # Left side of outer box.\n");
629   printf("     2   5 7          # Segments 2 through 5 enclose the hole.\n");
630   printf("     3   7 8\n");
631   printf("     4   8 6\n");
632   printf("     5   6 5\n");
633   printf("    # One hole in the middle of the inner square.\n");
634   printf("    1\n");
635   printf("     1   1.5 1.5\n\n");
636   printf(
637 "  After this PSLG is triangulated by Triangle, the resulting triangulation\n"
638 );
639   printf(
640 "  consists of a .node and .ele file.  Here is the former, `box.1.node',\n");
641   printf("  which duplicates the points of the PSLG:\n\n");
642   printf("    8  2  0  0\n");
643   printf("       1    0  0\n");
644   printf("       2    0  3\n");
645   printf("       3    3  0\n");
646   printf("       4    3  3\n");
647   printf("       5    1  1\n");
648   printf("       6    1  2\n");
649   printf("       7    2  1\n");
650   printf("       8    2  2\n");
651   printf("    # Generated by triangle -pcBev box\n");
652   printf("\n");
653   printf("  Here is the triangulation file, `box.1.ele'.\n");
654   printf("\n");
655   printf("    8  3  0\n");
656   printf("       1       1     5     6\n");
657   printf("       2       5     1     3\n");
658   printf("       3       2     6     8\n");
659   printf("       4       6     2     1\n");
660   printf("       5       7     3     4\n");
661   printf("       6       3     7     5\n");
662   printf("       7       8     4     2\n");
663   printf("       8       4     8     7\n");
664   printf("    # Generated by triangle -pcBev box\n\n");
665   printf("  Here is the edge file for the triangulation, `box.1.edge'.\n\n");
666   printf("    16  0\n");
667   printf("       1   1  5\n");
668   printf("       2   5  6\n");
669   printf("       3   6  1\n");
670   printf("       4   1  3\n");
671   printf("       5   3  5\n");
672   printf("       6   2  6\n");
673   printf("       7   6  8\n");
674   printf("       8   8  2\n");
675   printf("       9   2  1\n");
676   printf("      10   7  3\n");
677   printf("      11   3  4\n");
678   printf("      12   4  7\n");
679   printf("      13   7  5\n");
680   printf("      14   8  4\n");
681   printf("      15   4  2\n");
682   printf("      16   8  7\n");
683   printf("    # Generated by triangle -pcBev box\n");
684   printf("\n");
685   printf(
686 "  Here's a file `box.1.part' that partitions the mesh into four subdomains.\n"
687 );
688   printf("\n");
689   printf("    8  4\n");
690   printf("       1    3\n");
691   printf("       2    3\n");
692   printf("       3    4\n");
693   printf("       4    4\n");
694   printf("       5    1\n");
695   printf("       6    1\n");
696   printf("       7    2\n");
697   printf("       8    2\n");
698   printf("    # Generated by slice -s4 box.1\n\n");
699   printf(
700 "  Here's a file `box.1.adj' that represents the resulting adjacencies.\n");
701   printf("\n");
702   printf("    4\n");
703   printf("      9\n");
704   printf("      2\n");
705   printf("      2\n");
706   printf("      0\n");
707   printf("      2\n");
708   printf("      9\n");
709   printf("      0\n");
710   printf("      2\n");
711   printf("      2\n");
712   printf("      0\n");
713   printf("      9\n");
714   printf("      2\n");
715   printf("      0\n");
716   printf("      2\n");
717   printf("      2\n");
718   printf("      9\n");
719   printf("\n");
720   printf("Display Speed:\n");
721   printf("\n");
722   printf(
723 "  It is worthwhile to note that .edge files typically plot and print twice\n"
724 );
725   printf(
726 "  as quickly as .ele files, because .ele files cause each internal edge to\n"
727 );
728   printf(
729 "  be drawn twice.  For the same reason, PostScript files created from edge\n"
730 );
731   printf("  sets are smaller than those created from triangulations.\n\n");
732   printf("Show Me on the Web:\n\n");
733   printf(
734 "  To see an illustrated, updated version of these instructions, check out\n");
735   printf("\n");
736   printf("    http://www.cs.cmu.edu/~quake/showme.html\n");
737   printf("\n");
738   printf("A Brief Plea:\n");
739   printf("\n");
740   printf(
741 "  If you use Show Me (or Triangle), and especially if you use it to\n");
742   printf(
743 "  accomplish real work, I would like very much to hear from you.  A short\n");
744   printf(
745 "  letter or email (to jrs@cs.cmu.edu) describing how you use Show Me (and\n");
746   printf(
747 "  its sister programs) will mean a lot to me.  The more people I know\n");
748   printf(
749 "  are using my programs, the more easily I can justify spending time on\n");
750   printf(
751 "  improvements, which in turn will benefit you.  Also, I can put you\n");
752   printf(
753 "  on a list to receive email whenever new versions are available.\n");
754   printf("\n");
755   printf(
756 "  If you use a PostScript file generated by Show Me in a publication,\n");
757   printf("  please include an acknowledgment as well.\n\n");
758   exit(0);
759 }
760
761 void set_filenames(filename, lowermeshnumber)
762 char *filename;
763 int lowermeshnumber;
764 {
765   char numberstring[100];
766   int i;
767
768   for (i = 0; i < 2; i++) {
769     strcpy(nodefilename[i], filename);
770     strcpy(polyfilename[i], filename);
771     strcpy(elefilename[i], filename);
772     strcpy(edgefilename[i], filename);
773     strcpy(partfilename[i], filename);
774     strcpy(adjfilename[i], filename);
775     strcpy(vnodefilename[i], filename);
776     strcpy(vedgefilename[i], filename);
777
778     if (lowermeshnumber + i > 0) {
779       sprintf(numberstring, ".%d", lowermeshnumber + i);
780       strcat(nodefilename[i], numberstring);
781       strcat(polyfilename[i], numberstring);
782       strcat(elefilename[i], numberstring);
783       strcat(edgefilename[i], numberstring);
784       strcat(partfilename[i], numberstring);
785       strcat(adjfilename[i], numberstring);
786       strcat(vnodefilename[i], numberstring);
787       strcat(vedgefilename[i], numberstring);
788     }
789
790     strcat(nodefilename[i], ".node");
791     strcat(polyfilename[i], ".poly");
792     strcat(elefilename[i], ".ele");
793     strcat(edgefilename[i], ".edge");
794     strcat(partfilename[i], ".part");
795     strcat(adjfilename[i], ".adj");
796     strcat(vnodefilename[i], ".v.node");
797     strcat(vedgefilename[i], ".v.edge");
798   }
799 }
800
801 void parsecommandline(argc, argv)
802 int argc;
803 char **argv;
804 {
805   int increment;
806   int meshnumber;
807   int i, j;
808
809   quiet = 0;
810   fillelem = 0;
811   line_width = 1;
812   bw_ps = 0;
813   start_image = ELE;
814   filename[0] = '\0';
815   for (i = 1; i < argc; i++) {
816     if (argv[i][0] == '-') {
817       for (j = 1; argv[i][j] != '\0'; j++) {
818         if (argv[i][j] == 'f') {
819           fillelem = 1;
820         }
821         if (argv[i][j] == 'w') {
822           if ((argv[i][j + 1] >= '1') && (argv[i][j + 1] <= '9')) {
823             line_width = 0;
824             while ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
825               j++;
826               line_width = line_width * 10 + (int) (argv[i][j] - '0');
827             }
828             if (line_width > 100) {
829               printf("Error:  Line width cannot exceed 100.\n");
830               line_width = 1;
831             }
832           }
833         }
834         if (argv[i][j] == 'b') {
835           bw_ps = 1;
836         }
837         if (argv[i][j] == 'Q') {
838           quiet = 1;
839         }
840         if ((argv[i][j] == 'h') || (argv[i][j] == 'H') ||
841             (argv[i][j] == '?')) {
842           info();
843         }
844       }
845     } else {
846       strcpy(filename, argv[i]);
847     }
848   }
849   if (filename[0] == '\0') {
850     syntax();
851   }
852   if (!strcmp(&filename[strlen(filename) - 5], ".node")) {
853     filename[strlen(filename) - 5] = '\0';
854     start_image = NODE;
855   }
856   if (!strcmp(&filename[strlen(filename) - 5], ".poly")) {
857     filename[strlen(filename) - 5] = '\0';
858     start_image = POLY;
859   }
860   if (!strcmp(&filename[strlen(filename) - 4], ".ele")) {
861     filename[strlen(filename) - 4] = '\0';
862     start_image = ELE;
863   }
864   if (!strcmp(&filename[strlen(filename) - 5], ".edge")) {
865     filename[strlen(filename) - 5] = '\0';
866     start_image = EDGE;
867   }
868   if (!strcmp(&filename[strlen(filename) - 5], ".part")) {
869     filename[strlen(filename) - 5] = '\0';
870     start_image = PART;
871   }
872   if (!strcmp(&filename[strlen(filename) - 4], ".adj")) {
873     filename[strlen(filename) - 4] = '\0';
874     start_image = ADJ;
875   }
876
877   increment = 0;
878   j = 1;
879   while (filename[j] != '\0') {
880     if ((filename[j] == '.') && (filename[j + 1] != '\0')) {
881       increment = j + 1;
882     }
883     j++;
884   }
885   meshnumber = 0;
886   if (increment > 0) {
887     j = increment;
888     do {
889       if ((filename[j] >= '0') && (filename[j] <= '9')) {
890         meshnumber = meshnumber * 10 + (int) (filename[j] - '0');
891       } else {
892         increment = 0;
893       }
894       j++;
895     } while (filename[j] != '\0');
896   }
897   if (increment > 0) {
898     filename[increment - 1] = '\0';
899   }
900
901   if (meshnumber == 0) {
902     start_inc = 0;
903     loweriteration = 0;
904   } else {
905     start_inc = 1;
906     loweriteration = meshnumber - 1;
907   }
908   set_filenames(filename, loweriteration);
909 }
910
911 void free_inc(inc)
912 int inc;
913 {
914   if (loaded[inc][NODE]) {
915     free(nodeptr[inc]);
916   }
917   if (loaded[inc][POLY]) {
918     if (polynodes[inc] > 0) {
919       free(polynodeptr[inc]);
920     }
921     free(polyedgeptr[inc]);
922     free(polyholeptr[inc]);
923   }
924   if (loaded[inc][ELE]) {
925     free(eleptr[inc]);
926   }
927   if (loaded[inc][PART]) {
928     free(partpart[inc]);
929     free(partcenter[inc]);
930     free(partshift[inc]);
931   }
932   if (loaded[inc][EDGE]) {
933     free(edgeptr[inc]);
934     free(normptr[inc]);
935   }
936   if (loaded[inc][ADJ]) {
937     free(adjptr[inc]);
938   }
939   if (loaded[inc][VORO]) {
940     free(vnodeptr[inc]);
941     free(vedgeptr[inc]);
942     free(vnormptr[inc]);
943   }
944 }
945
946 void move_inc(inc)
947 int inc;
948 {
949   int i;
950
951   free_inc(1 - inc);
952   for (i = 0; i < IMAGE_TYPES; i++) {
953     loaded[1 - inc][i] = loaded[inc][i];
954     loaded[inc][i] = 0;
955     xlo[1 - inc][i] = xlo[inc][i];
956     ylo[1 - inc][i] = ylo[inc][i];
957     xhi[1 - inc][i] = xhi[inc][i];
958     yhi[1 - inc][i] = yhi[inc][i];
959   }
960   nodes[1 - inc] = nodes[inc];
961   node_dim[1 - inc] = node_dim[inc];
962   nodeptr[1 - inc] = nodeptr[inc];
963   polynodes[1 - inc] = polynodes[inc];
964   poly_dim[1 - inc] = poly_dim[inc];
965   polyedges[1 - inc] = polyedges[inc];
966   polyholes[1 - inc] = polyholes[inc];
967   polynodeptr[1 - inc] = polynodeptr[inc];
968   polyedgeptr[1 - inc] = polyedgeptr[inc];
969   polyholeptr[1 - inc] = polyholeptr[inc];
970   elems[1 - inc] = elems[inc];
971   ele_corners[1 - inc] = ele_corners[inc];
972   eleptr[1 - inc] = eleptr[inc];
973   edges[1 - inc] = edges[inc];
974   edgeptr[1 - inc] = edgeptr[inc];
975   normptr[1 - inc] = normptr[inc];
976   subdomains[1 - inc] = subdomains[inc];
977   partpart[1 - inc] = partpart[inc];
978   partcenter[1 - inc] = partcenter[inc];
979   partshift[1 - inc] = partshift[inc];
980   adjsubdomains[1 - inc] = adjsubdomains[inc];
981   adjptr[1 - inc] = adjptr[inc];
982   vnodes[1 - inc] = vnodes[inc];
983   vnode_dim[1 - inc] = vnode_dim[inc];
984   vnodeptr[1 - inc] = vnodeptr[inc];
985   vedges[1 - inc] = vedges[inc];
986   vedgeptr[1 - inc] = vedgeptr[inc];
987   vnormptr[1 - inc] = vnormptr[inc];
988   firstnumber[1 - inc] = firstnumber[inc];
989   firstnumber[inc] = -1;
990 }
991
992 void unload_inc(inc)
993 int inc;
994 {
995   int i;
996
997   current_image = NOTHING;
998   for (i = 0; i < IMAGE_TYPES; i++) {
999     loaded[inc][i] = 0;
1000     firstnumber[inc] = -1;
1001   }
1002 }
1003
1004 void showme_init()
1005 {
1006   current_image = NOTHING;
1007   current_inc = 0;
1008   explosion = STARTEXPLOSION;
1009   unload_inc(0);
1010   unload_inc(1);
1011 }
1012
1013 char *readline(string, infile, infilename)
1014 char *string;
1015 FILE *infile;
1016 char *infilename;
1017 {
1018   char *result;
1019
1020   do {
1021     result = fgets(string, INPUTLINESIZE, infile);
1022     if (result == (char *) NULL) {
1023       printf("  Error:  Unexpected end of file in %s.\n",
1024              infilename);
1025       exit(1);
1026     }
1027     while ((*result != '\0') && (*result != '#')
1028            && (*result != '.') && (*result != '+') && (*result != '-')
1029            && ((*result < '0') || (*result > '9'))) {
1030       result++;
1031     }
1032   } while ((*result == '#') || (*result == '\0'));
1033   return result;
1034 }
1035
1036 char *findfield(string)
1037 char *string;
1038 {
1039   char *result;
1040
1041   result = string;
1042   while ((*result != '\0') && (*result != '#')
1043          && (*result != ' ') && (*result != '\t')) {
1044     result++;
1045   }
1046   while ((*result != '\0') && (*result != '#')
1047          && (*result != '.') && (*result != '+') && (*result != '-')
1048          && ((*result < '0') || (*result > '9'))) {
1049     result++;
1050   }
1051   if (*result == '#') {
1052     *result = '\0';
1053   }
1054   return result;
1055 }
1056
1057 int load_node(fname, firstnumber, nodes, dim, ptr, xmin, ymin, xmax, ymax)
1058 char *fname;
1059 int *firstnumber;
1060 int *nodes;
1061 int *dim;
1062 REAL **ptr;
1063 REAL *xmin;
1064 REAL *ymin;
1065 REAL *xmax;
1066 REAL *ymax;
1067 {
1068   FILE *infile;
1069   char inputline[INPUTLINESIZE];
1070   char *stringptr;
1071   int extras;
1072   int nodemarks;
1073   int index;
1074   int nodenumber;
1075   int i, j;
1076   int smallerr;
1077   REAL x, y;
1078
1079   *xmin = *ymin = 0.0;
1080   *xmax = *ymax = 1.0;
1081   if (!quiet) {
1082     printf("Opening %s.\n", fname);
1083   }
1084   infile = fopen(fname, "r");
1085   if (infile == (FILE *) NULL) {
1086     printf("  Error:  Cannot access file %s.\n", fname);
1087     return 1;
1088   }
1089   stringptr = readline(inputline, infile, fname);
1090   *nodes = (int) strtol (stringptr, &stringptr, 0);
1091   if (*nodes < 3) {
1092     printf("  Error:  %s contains %d points.\n", fname, *nodes);
1093     return 1;
1094   }
1095   stringptr = findfield(stringptr);
1096   if (*stringptr == '\0') {
1097     *dim = 2;
1098   } else {
1099     *dim = (int) strtol (stringptr, &stringptr, 0);
1100   }
1101   if (*dim < 1) {
1102     printf("  Error:  %s has dimensionality %d.\n", fname, *dim);
1103     return 1;
1104   }
1105   if (*dim != 2) {
1106     printf("  I only understand two-dimensional meshes.\n");
1107     return 1;
1108   }
1109   stringptr = findfield(stringptr);
1110   if (*stringptr == '\0') {
1111     extras = 0;
1112   } else {
1113     extras = (int) strtol (stringptr, &stringptr, 0);
1114   }
1115   if (extras < 0) {
1116     printf("  Error:  %s has negative value for number of attributes.\n",
1117            fname);
1118     return 1;
1119   }
1120   stringptr = findfield(stringptr);
1121   if (*stringptr == '\0') {
1122     nodemarks = 0;
1123   } else {
1124     nodemarks = (int) strtol (stringptr, &stringptr, 0);
1125   }
1126   if (nodemarks < 0) {
1127     printf("  Warning:  %s has negative value for number of point markers.\n",
1128            fname);
1129   }
1130   if (nodemarks > 1) {
1131     printf(
1132    "  Warning:  %s has value greater than one for number of point markers.\n",
1133            fname);
1134   }
1135   *ptr = (REAL *) malloc((*nodes + 1) * *dim * sizeof(REAL));
1136   if (*ptr == (REAL *) NULL) {
1137     printf("  Out of memory.\n");
1138     return 1;
1139   }
1140   index = *dim;
1141   smallerr = 1;
1142   for (i = 0; i < *nodes; i++) {
1143     stringptr = readline(inputline, infile, fname);
1144     nodenumber = (int) strtol (stringptr, &stringptr, 0);
1145     if ((i == 0) && (*firstnumber == -1)) {
1146       if (nodenumber == 0) {
1147         *firstnumber = 0;
1148       } else {
1149         *firstnumber = 1;
1150       }
1151     }
1152     if ((nodenumber != *firstnumber + i) && (smallerr)) {
1153       printf("  Warning:  Points in %s are not numbered correctly\n", fname);
1154       printf("            (starting with point %d).\n", *firstnumber + i);
1155       smallerr = 0;
1156     }
1157     for (j = 0; j < *dim; j++) {
1158       stringptr = findfield(stringptr);
1159       if (*stringptr == '\0') {
1160         printf("Error:  Point %d is missing a coordinate in %s.\n",
1161                *firstnumber + i, fname);
1162         free(*ptr);
1163         return 1;
1164       }
1165       (*ptr)[index++] = (REAL) strtod(stringptr, &stringptr);
1166     }
1167   }
1168   fclose(infile);
1169   index = *dim;
1170   *xmin = *xmax = (*ptr)[index];
1171   *ymin = *ymax = (*ptr)[index + 1];
1172   for (i = 2; i <= *nodes; i++) {
1173     index += *dim;
1174     x = (*ptr)[index];
1175     y = (*ptr)[index + 1];
1176     if (x < *xmin) {
1177       *xmin = x;
1178     }
1179     if (y < *ymin) {
1180       *ymin = y;
1181     }
1182     if (x > *xmax) {
1183       *xmax = x;
1184     }
1185     if (y > *ymax) {
1186       *ymax = y;
1187     }
1188   }
1189   if (*xmin == *xmax) {
1190     *xmin -= 0.5;
1191     *xmax += 0.5;
1192   }
1193   if (*ymin == *ymax) {
1194     *ymin -= 0.5;
1195     *ymax += 0.5;
1196   }
1197   return 0;
1198 }
1199
1200 int load_poly(inc, fname, firstnumber, pnodes, dim, edges, holes, nodeptr,
1201               edgeptr, holeptr, xmin, ymin, xmax, ymax)
1202 int inc;
1203 char *fname;
1204 int *firstnumber;
1205 int *pnodes;
1206 int *dim;
1207 int *edges;
1208 int *holes;
1209 REAL **nodeptr;
1210 int **edgeptr;
1211 REAL **holeptr;
1212 REAL *xmin;
1213 REAL *ymin;
1214 REAL *xmax;
1215 REAL *ymax;
1216 {
1217   FILE *infile;
1218   char inputline[INPUTLINESIZE];
1219   char *stringptr;
1220   int extras;
1221   int nodemarks;
1222   int segmentmarks;
1223   int index;
1224   int nodenumber, edgenumber, holenumber;
1225   int maxnode;
1226   int i, j;
1227   int smallerr;
1228   REAL x, y;
1229
1230   if (!quiet) {
1231     printf("Opening %s.\n", fname);
1232   }
1233   infile = fopen(fname, "r");
1234   if (infile == (FILE *) NULL) {
1235     printf("  Error:  Cannot access file %s.\n", fname);
1236     return 1;
1237   }
1238   stringptr = readline(inputline, infile, fname);
1239   *pnodes = (int) strtol (stringptr, &stringptr, 0);
1240   if (*pnodes == 0) {
1241     if (!loaded[inc][NODE]) {
1242       if (load_image(inc, NODE)) {
1243         return 1;
1244       }
1245     }
1246     maxnode = nodes[inc];
1247     *xmin = xlo[inc][NODE];
1248     *ymin = ylo[inc][NODE];
1249     *xmax = xhi[inc][NODE];
1250     *ymax = yhi[inc][NODE];
1251   } else {
1252     if (*pnodes < 1) {
1253       printf("  Error:  %s contains %d points.\n", fname, *pnodes);
1254       return 1;
1255     }
1256     maxnode = *pnodes;
1257   }
1258   stringptr = findfield(stringptr);
1259   if (*stringptr == '\0') {
1260     *dim = 2;
1261   } else {
1262     *dim = (int) strtol (stringptr, &stringptr, 0);
1263   }
1264   if (*dim < 1) {
1265     printf("  Error:  %s has dimensionality %d.\n", fname, *dim);
1266     return 1;
1267   }
1268   if (*dim != 2) {
1269     printf("  I only understand two-dimensional meshes.\n");
1270     return 1;
1271   }
1272   stringptr = findfield(stringptr);
1273   if (*stringptr == '\0') {
1274     extras = 0;
1275   } else {
1276     extras = (int) strtol (stringptr, &stringptr, 0);
1277   }
1278   if (extras < 0) {
1279     printf("  Error:  %s has negative value for number of attributes.\n",
1280            fname);
1281     return 1;
1282   }
1283   stringptr = findfield(stringptr);
1284   if (*stringptr == '\0') {
1285     nodemarks = 0;
1286   } else {
1287     nodemarks = (int) strtol (stringptr, &stringptr, 0);
1288   }
1289   if (nodemarks < 0) {
1290     printf("  Warning:  %s has negative value for number of point markers.\n",
1291            fname);
1292   }
1293   if (nodemarks > 1) {
1294     printf(
1295    "  Warning:  %s has value greater than one for number of point markers.\n",
1296            fname);
1297   }
1298   if (*pnodes > 0) {
1299     *nodeptr = (REAL *) malloc((*pnodes + 1) * *dim * sizeof(REAL));
1300     if (*nodeptr == (REAL *) NULL) {
1301       printf("  Out of memory.\n");
1302       return 1;
1303     }
1304     index = *dim;
1305     smallerr = 1;
1306     for (i = 0; i < *pnodes; i++) {
1307       stringptr = readline(inputline, infile, fname);
1308       nodenumber = (int) strtol (stringptr, &stringptr, 0);
1309       if ((i == 0) && (*firstnumber == -1)) {
1310         if (nodenumber == 0) {
1311           *firstnumber = 0;
1312         } else {
1313           *firstnumber = 1;
1314         }
1315       }
1316       if ((nodenumber != *firstnumber + i) && (smallerr)) {
1317         printf("  Warning:  Points in %s are not numbered correctly.\n",
1318                fname);
1319         printf("            (starting with point %d).\n", *firstnumber + i);
1320         smallerr = 0;
1321       }
1322       for (j = 0; j < *dim; j++) {
1323         stringptr = findfield(stringptr);
1324         if (*stringptr == '\0') {
1325           printf("Error:  Point %d is missing a coordinate in %s.\n",
1326                  *firstnumber + i, fname);
1327           free(*nodeptr);
1328           return 1;
1329         }
1330         (*nodeptr)[index++] = (REAL) strtod(stringptr, &stringptr);
1331       }
1332     }
1333   }
1334   stringptr = readline(inputline, infile, fname);
1335   *edges = (int) strtol (stringptr, &stringptr, 0);
1336   if (*edges < 0) {
1337     printf("  Error:  %s contains %d segments.\n", fname, *edges);
1338     free(*nodeptr);
1339     return 1;
1340   }
1341   stringptr = findfield(stringptr);
1342   if (*stringptr == '\0') {
1343     segmentmarks = 0;
1344   } else {
1345     segmentmarks = (int) strtol (stringptr, &stringptr, 0);
1346   }
1347   if (segmentmarks < 0) {
1348     printf("  Error:  %s has negative value for number of segment markers.\n",
1349            fname);
1350     free(*nodeptr);
1351     return 1;
1352   }
1353   if (segmentmarks > 1) {
1354     printf(
1355    "  Error:  %s has value greater than one for number of segment markers.\n",
1356            fname);
1357     free(*nodeptr);
1358     return 1;
1359   }
1360   *edgeptr = (int *) malloc(((*edges + 1) << 1) * sizeof(int));
1361   if (*edgeptr == (int *) NULL) {
1362     printf("  Out of memory.\n");
1363     free(*nodeptr);
1364     return 1;
1365   }
1366   index = 2;
1367   smallerr = 1;
1368   for (i = *firstnumber; i < *firstnumber + *edges; i++) {
1369     stringptr = readline(inputline, infile, fname);
1370     edgenumber = (int) strtol (stringptr, &stringptr, 0);
1371     if ((edgenumber != i) && (smallerr)) {
1372       printf("  Warning:  Segments in %s are not numbered correctly.\n",
1373              fname);
1374       printf("            (starting with segment %d).\n", i);
1375       smallerr = 0;
1376     }
1377     stringptr = findfield(stringptr);
1378     if (*stringptr == '\0') {
1379       printf("Error:  Segment %d is missing its endpoints in %s.\n", i, fname);
1380       free(*nodeptr);
1381       free(*edgeptr);
1382       return 1;
1383     }
1384     (*edgeptr)[index] = (int) strtol (stringptr, &stringptr, 0) + 1 -
1385                         *firstnumber;
1386     if (((*edgeptr)[index] < 1) || ((*edgeptr)[index] > maxnode)) {
1387       printf("Error:  Segment %d has invalid endpoint in %s.\n", i, fname);
1388       return 1;
1389     }
1390     stringptr = findfield(stringptr);
1391     if (*stringptr == '\0') {
1392       printf("Error:  Segment %d is missing an endpoint in %s.\n", i, fname);
1393       free(*nodeptr);
1394       free(*edgeptr);
1395       return 1;
1396     }
1397     (*edgeptr)[index + 1] = (int) strtol (stringptr, &stringptr, 0) + 1 -
1398                             *firstnumber;
1399     if (((*edgeptr)[index + 1] < 1) || ((*edgeptr)[index + 1] > maxnode)) {
1400       printf("Error:  Segment %d has invalid endpoint in %s.\n", i, fname);
1401       return 1;
1402     }
1403     index += 2;
1404   }
1405   stringptr = readline(inputline, infile, fname);
1406   *holes = (int) strtol (stringptr, &stringptr, 0);
1407   if (*holes < 0) {
1408     printf("  Error:  %s contains %d holes.\n", fname, *holes);
1409     free(*nodeptr);
1410     free(*edgeptr);
1411     return 1;
1412   }
1413   *holeptr = (REAL *) malloc((*holes + 1) * *dim * sizeof(REAL));
1414   if (*holeptr == (REAL *) NULL) {
1415     printf("  Out of memory.\n");
1416     free(*nodeptr);
1417     free(*edgeptr);
1418     return 1;
1419   }
1420   index = *dim;
1421   smallerr = 1;
1422   for (i = *firstnumber; i < *firstnumber + *holes; i++) {
1423     stringptr = readline(inputline, infile, fname);
1424     holenumber = (int) strtol (stringptr, &stringptr, 0);
1425     if ((holenumber != i) && (smallerr)) {
1426       printf("  Warning:  Holes in %s are not numbered correctly.\n", fname);
1427       printf("            (starting with hole %d).\n", i);
1428       smallerr = 0;
1429     }
1430     for (j = 0; j < *dim; j++) {
1431       stringptr = findfield(stringptr);
1432       if (*stringptr == '\0') {
1433         printf("Error:  Hole %d is missing a coordinate in %s.\n", i,
1434                fname);
1435         free(*nodeptr);
1436         free(*edgeptr);
1437         free(*holeptr);
1438         return 1;
1439       }
1440       (*holeptr)[index++] = (REAL) strtod(stringptr, &stringptr);
1441     }
1442   }
1443   fclose(infile);
1444   if (*pnodes > 0) {
1445     index = *dim;
1446     *xmin = *xmax = (*nodeptr)[index];
1447     *ymin = *ymax = (*nodeptr)[index + 1];
1448     for (i = 2; i <= *pnodes; i++) {
1449       index += *dim;
1450       x = (*nodeptr)[index];
1451       y = (*nodeptr)[index + 1];
1452       if (x < *xmin) {
1453         *xmin = x;
1454       }
1455       if (y < *ymin) {
1456         *ymin = y;
1457       }
1458       if (x > *xmax) {
1459         *xmax = x;
1460       }
1461       if (y > *ymax) {
1462         *ymax = y;
1463       }
1464     }
1465   }
1466   index = *dim;
1467   for (i = 1; i <= *holes; i++) {
1468     x = (*holeptr)[index];
1469     y = (*holeptr)[index + 1];
1470     if (x < *xmin) {
1471       *xmin = x;
1472     }
1473     if (y < *ymin) {
1474       *ymin = y;
1475     }
1476     if (x > *xmax) {
1477       *xmax = x;
1478     }
1479     if (y > *ymax) {
1480       *ymax = y;
1481     }
1482     index += *dim;
1483   }
1484   return 0;
1485 }
1486
1487 int load_ele(fname, firstnumber, nodes, elems, corners, ptr)
1488 char *fname;
1489 int firstnumber;
1490 int nodes;
1491 int *elems;
1492 int *corners;
1493 int **ptr;
1494 {
1495   FILE *infile;
1496   char inputline[INPUTLINESIZE];
1497   char *stringptr;
1498   int extras;
1499   int index;
1500   int elemnumber;
1501   int i, j;
1502   int smallerr;
1503
1504   if (!quiet) {
1505     printf("Opening %s.\n", fname);
1506   }
1507   infile = fopen(fname, "r");
1508   if (infile == (FILE *) NULL) {
1509     printf("  Error:  Cannot access file %s.\n", fname);
1510     return 1;
1511   }
1512   stringptr = readline(inputline, infile, fname);
1513   *elems = (int) strtol (stringptr, &stringptr, 0);
1514   if (*elems < 1) {
1515     printf("  Error:  %s contains %d triangles.\n", fname, *elems);
1516     return 1;
1517   }
1518   stringptr = findfield(stringptr);
1519   if (*stringptr == '\0') {
1520     *corners = 3;
1521   } else {
1522     *corners = (int) strtol (stringptr, &stringptr, 0);
1523   }
1524   if (*corners < 3) {
1525     printf("  Error:  Triangles in %s have only %d corners.\n", fname,
1526            *corners);
1527     return 1;
1528   }
1529   stringptr = findfield(stringptr);
1530   if (*stringptr == '\0') {
1531     extras = 0;
1532   } else {
1533     extras = (int) strtol (stringptr, &stringptr, 0);
1534   }
1535   if (extras < 0) {
1536     printf("  Error:  %s has negative value for extra fields.\n", fname);
1537     return 1;
1538   }
1539   *ptr = (int *) malloc((*elems + 1) * 3 * sizeof(int));
1540   if (*ptr == (int *) NULL) {
1541     printf("  Out of memory.\n");
1542     return 1;
1543   }
1544   index = 3;
1545   smallerr = 1;
1546   for (i = firstnumber; i < firstnumber + *elems; i++) {
1547     stringptr = readline(inputline, infile, fname);
1548     elemnumber = (int) strtol (stringptr, &stringptr, 0);
1549     if ((elemnumber != i) && (smallerr)) {
1550       printf("  Warning:  Triangles in %s are not numbered correctly.\n",
1551              fname);
1552       printf("            (starting with triangle %d).\n", i);
1553       smallerr = 0;
1554     }
1555     for (j = 0; j < 3; j++) {
1556       stringptr = findfield(stringptr);
1557       if (*stringptr == '\0') {
1558         printf("Error:  Triangle %d is missing a corner in %s.\n", i, fname);
1559         free(*ptr);
1560         return 1;
1561       }
1562       (*ptr)[index] = (int) strtol (stringptr, &stringptr, 0) + 1 -
1563                       firstnumber;
1564       if (((*ptr)[index] < 1) || ((*ptr)[index] > nodes)) {
1565         printf("Error:  Triangle %d has invalid corner in %s.\n", i, fname);
1566         return 1;
1567       }
1568       index++;
1569     }
1570   }
1571   fclose(infile);
1572   return 0;
1573 }
1574
1575 int load_edge(fname, firstnumber, nodes, edges, edgeptr, normptr)
1576 char *fname;
1577 int firstnumber;
1578 int nodes;
1579 int *edges;
1580 int **edgeptr;
1581 REAL **normptr;
1582 {
1583   FILE *infile;
1584   char inputline[INPUTLINESIZE];
1585   char *stringptr;
1586   int index;
1587   int edgenumber;
1588   int edgemarks;
1589   int i;
1590   int smallerr;
1591
1592   if (!quiet) {
1593     printf("Opening %s.\n", fname);
1594   }
1595   infile = fopen(fname, "r");
1596     if (infile == (FILE *) NULL) {
1597       printf("  Error:  Cannot access file %s.\n", fname);
1598       return 1;
1599     }
1600   stringptr = readline(inputline, infile, fname);
1601   *edges = (int) strtol (stringptr, &stringptr, 0);
1602   if (*edges < 1) {
1603     printf("  Error:  %s contains %d edges.\n", fname, *edges);
1604     return 1;
1605   }
1606   stringptr = findfield(stringptr);
1607   if (*stringptr == '\0') {
1608     edgemarks = 0;
1609   } else {
1610     edgemarks = (int) strtol (stringptr, &stringptr, 0);
1611   }
1612   if (edgemarks < 0) {
1613     printf("  Error:  %s has negative value for number of edge markers.\n",
1614            fname);
1615     return 1;
1616   }
1617   if (edgemarks > 1) {
1618     printf(
1619    "  Error:  %s has value greater than one for number of edge markers.\n",
1620            fname);
1621     return 1;
1622   }
1623   *edgeptr = (int *) malloc(((*edges + 1) << 1) * sizeof(int));
1624   if (*edgeptr == (int *) NULL) {
1625     printf("  Out of memory.\n");
1626     return 1;
1627   }
1628   *normptr = (REAL *) malloc(((*edges + 1) << 1) * sizeof(REAL));
1629   if (*normptr == (REAL *) NULL) {
1630     printf("  Out of memory.\n");
1631     free(*edgeptr);
1632     return 1;
1633   }
1634   index = 2;
1635   smallerr = 1;
1636   for (i = firstnumber; i < firstnumber + *edges; i++) {
1637     stringptr = readline(inputline, infile, fname);
1638     edgenumber = (int) strtol (stringptr, &stringptr, 0);
1639     if ((edgenumber != i) && (smallerr)) {
1640       printf("  Warning:  Edges in %s are not numbered correctly.\n", fname);
1641       printf("            (starting with edge %d).\n", i);
1642       smallerr = 0;
1643     }
1644     stringptr = findfield(stringptr);
1645     if (*stringptr == '\0') {
1646       printf("Error:  Edge %d is missing its endpoints in %s.\n", i, fname);
1647       free(*edgeptr);
1648       free(*normptr);
1649       return 1;
1650     }
1651     (*edgeptr)[index] = (int) strtol (stringptr, &stringptr, 0) + 1 -
1652                         firstnumber;
1653     if (((*edgeptr)[index] < 1) || ((*edgeptr)[index] > nodes)) {
1654       printf("Error:  Edge %d has invalid endpoint in %s.\n", i, fname);
1655       return 1;
1656     }
1657     stringptr = findfield(stringptr);
1658     if (*stringptr == '\0') {
1659       printf("Error:  Edge %d is missing an endpoint in %s.\n", i, fname);
1660       free(*edgeptr);
1661       free(*normptr);
1662       return 1;
1663     }
1664     (*edgeptr)[index + 1] = (int) strtol (stringptr, &stringptr, 0);
1665     if ((*edgeptr)[index + 1] == -1) {
1666       stringptr = findfield(stringptr);
1667       if (*stringptr == '\0') {
1668         printf("Error:  Edge %d is missing its direction in %s.\n", i, fname);
1669         free(*edgeptr);
1670         free(*normptr);
1671         return 1;
1672       }
1673       (*normptr)[index] = (REAL) strtod(stringptr, &stringptr);
1674       stringptr = findfield(stringptr);
1675       if (*stringptr == '\0') {
1676         printf("Error:  Edge %d is missing a direction coordinate in %s.\n",
1677                i, fname);
1678         free(*edgeptr);
1679         free(*normptr);
1680         return 1;
1681       }
1682       (*normptr)[index + 1] = (REAL) strtod(stringptr, &stringptr);
1683     } else {
1684       (*edgeptr)[index + 1] += 1 - firstnumber;
1685       if (((*edgeptr)[index + 1] < 1) || ((*edgeptr)[index + 1] > nodes)) {
1686         printf("Error:  Edge %d has invalid endpoint in %s.\n", i, fname);
1687         return 1;
1688       }
1689     }
1690     index += 2;
1691   }
1692   fclose(infile);
1693   return 0;
1694 }
1695
1696 int load_part(fname, dim, firstnumber, elems, nodeptr, eleptr, parts,
1697               partition, partcenter, partshift)
1698 char *fname;
1699 int dim;
1700 int firstnumber;
1701 int elems;
1702 REAL *nodeptr;
1703 int *eleptr;
1704 int *parts;
1705 int **partition;
1706 REAL **partcenter;
1707 REAL **partshift;
1708 {
1709   FILE *infile;
1710   char inputline[INPUTLINESIZE];
1711   char *stringptr;
1712   int partelems;
1713   int index;
1714   int elemnumber;
1715   int i, j;
1716   int smallerr;
1717   int *partsize;
1718
1719   if (!quiet) {
1720     printf("Opening %s.\n", fname);
1721   }
1722   infile = fopen(fname, "r");
1723   if (infile == (FILE *) NULL) {
1724     printf("  Error:  Cannot access file %s.\n", fname);
1725     return 1;
1726   }
1727   stringptr = readline(inputline, infile, fname);
1728   partelems = (int) strtol (stringptr, &stringptr, 0);
1729   if (partelems != elems) {
1730     printf(
1731       "  Error:  .ele and .part files do not agree on number of triangles.\n");
1732     return 1;
1733   }
1734   stringptr = findfield(stringptr);
1735   if (*stringptr == '\0') {
1736     *parts = 1;
1737   } else {
1738     *parts = (int) strtol (stringptr, &stringptr, 0);
1739   }
1740   if (*parts < 1) {
1741     printf("  Error:  %s specifies %d subdomains.\n", fname, *parts);
1742     return 1;
1743   }
1744   *partition = (int *) malloc((elems + 1) * sizeof(int));
1745   if (*partition == (int *) NULL) {
1746     printf("  Out of memory.\n");
1747     return 1;
1748   }
1749   smallerr = 1;
1750   for (i = firstnumber; i < firstnumber + partelems; i++) {
1751     stringptr = readline(inputline, infile, fname);
1752     elemnumber = (int) strtol (stringptr, &stringptr, 0);
1753     if ((elemnumber != i) && (smallerr)) {
1754       printf("  Warning:  Triangles in %s are not numbered correctly.\n",
1755              fname);
1756       printf("            (starting with triangle %d).\n", i);
1757       smallerr = 0;
1758     }
1759     stringptr = findfield(stringptr);
1760     if (*stringptr == '\0') {
1761       printf("Error:  Triangle %d has no subdomain in %s.\n", i, fname);
1762       free(*partition);
1763       return 1;
1764     }
1765     (*partition)[i] = (int) strtol (stringptr, &stringptr, 0) - firstnumber;
1766     if (((*partition)[i] >= *parts) || ((*partition)[i] < 0)) {
1767       printf("  Error:  Triangle %d of %s has an invalid subdomain.\n",
1768              i, fname);
1769       free(*partition);
1770       return 1;
1771     }
1772   }
1773   fclose(infile);
1774   *partcenter = (REAL *) malloc(((*parts + 1) << 1) * sizeof(REAL));
1775   if (*partcenter == (REAL *) NULL) {
1776     printf("Error:  Out of memory.\n");
1777     free(*partition);
1778     return 1;
1779   }
1780   *partshift = (REAL *) malloc((*parts << 1) * sizeof(REAL));
1781   if (*partshift == (REAL *) NULL) {
1782     printf("Error:  Out of memory.\n");
1783     free(*partition);
1784     free(*partcenter);
1785     return 1;
1786   }
1787   partsize = (int *) malloc((*parts + 1) * sizeof(int));
1788   if (partsize == (int *) NULL) {
1789     printf("Error:  Out of memory.\n");
1790     free(*partition);
1791     free(*partcenter);
1792     free(*partshift);
1793     return 1;
1794   }
1795   index = 3;
1796   for (i = 0; i <= *parts; i++) {
1797     partsize[i] = 0;
1798     (*partcenter)[i << 1] = 0.0;
1799     (*partcenter)[(i << 1) + 1] = 0.0;
1800   }
1801   for (i = 1; i <= elems; i++) {
1802     partsize[(*partition)[i]] += 3;
1803     for (j = 0; j < 3; j++) {
1804       (*partcenter)[(*partition)[i] << 1] +=
1805                 nodeptr[eleptr[index] * dim];
1806       (*partcenter)[((*partition)[i] << 1) + 1] +=
1807                 nodeptr[eleptr[index++] * dim + 1];
1808     }
1809   }
1810   for (i = 0; i < *parts; i++) {
1811     (*partcenter)[i << 1] /= (REAL) partsize[i];
1812     (*partcenter)[(i << 1) + 1] /= (REAL) partsize[i];
1813     (*partcenter)[*parts << 1] += (*partcenter)[i << 1];
1814     (*partcenter)[(*parts << 1) + 1] += (*partcenter)[(i << 1) + 1];
1815   }
1816   (*partcenter)[*parts << 1] /= (REAL) *parts;
1817   (*partcenter)[(*parts << 1) + 1] /= (REAL) *parts;
1818   free(partsize);
1819   return 0;
1820 }
1821
1822 int load_adj(fname, subdomains, ptr)
1823 char *fname;
1824 int *subdomains;
1825 int **ptr;
1826 {
1827   FILE *infile;
1828   char inputline[INPUTLINESIZE];
1829   char *stringptr;
1830   int i, j;
1831
1832   if (!quiet) {
1833     printf("Opening %s.\n", fname);
1834   }
1835   infile = fopen(fname, "r");
1836   if (infile == (FILE *) NULL) {
1837     printf("  Error:  Cannot access file %s.\n", fname);
1838     return 1;
1839   }
1840   stringptr = readline(inputline, infile, fname);
1841   *subdomains = (int) strtol (stringptr, &stringptr, 0);
1842   if (*subdomains < 1) {
1843     printf("  Error:  %s contains %d subdomains.\n", fname, *subdomains);
1844     return 1;
1845   }
1846   *ptr = (int *) malloc(*subdomains * *subdomains * sizeof(int));
1847   if (*ptr == (int *) NULL) {
1848     printf("  Out of memory.\n");
1849     return 1;
1850   }
1851   for (i = 0; i < *subdomains; i++) {
1852     for (j = 0; j < *subdomains; j++) {
1853       stringptr = readline(inputline, infile, fname);
1854       (*ptr)[i * *subdomains + j] = (int) strtol (stringptr, &stringptr, 0);
1855     }
1856   }
1857   return 0;
1858 }
1859
1860 void findpartshift(parts, explosion, partcenter, partshift)
1861 int parts;
1862 REAL explosion;
1863 REAL *partcenter;
1864 REAL *partshift;
1865 {
1866   int i;
1867
1868   for (i = 0; i < parts; i++) {
1869     partshift[i << 1] = explosion *
1870           (partcenter[i << 1] - partcenter[parts << 1]);
1871     partshift[(i << 1) + 1] = explosion *
1872           (partcenter[(i << 1) + 1] - partcenter[(parts << 1) + 1]);
1873   }
1874 }
1875
1876 int load_image(inc, image)
1877 int inc;
1878 int image;
1879 {
1880   int error;
1881
1882   switch (image) {
1883     case NODE:
1884       error = load_node(nodefilename[inc], &firstnumber[inc], &nodes[inc],
1885                         &node_dim[inc], &nodeptr[inc], &xlo[inc][NODE],
1886                         &ylo[inc][NODE], &xhi[inc][NODE], &yhi[inc][NODE]);
1887       break;
1888     case POLY:
1889       error = load_poly(inc, polyfilename[inc], &firstnumber[inc],
1890                         &polynodes[inc], &poly_dim[inc], &polyedges[inc],
1891                         &polyholes[inc], &polynodeptr[inc], &polyedgeptr[inc],
1892                         &polyholeptr[inc],
1893                         &xlo[inc][POLY], &ylo[inc][POLY],
1894                         &xhi[inc][POLY], &yhi[inc][POLY]);
1895       break;
1896     case ELE:
1897       error = load_ele(elefilename[inc], firstnumber[inc], nodes[inc],
1898                        &elems[inc], &ele_corners[inc], &eleptr[inc]);
1899       xlo[inc][ELE] = xlo[inc][NODE];
1900       ylo[inc][ELE] = ylo[inc][NODE];
1901       xhi[inc][ELE] = xhi[inc][NODE];
1902       yhi[inc][ELE] = yhi[inc][NODE];
1903       break;
1904     case EDGE:
1905       error = load_edge(edgefilename[inc], firstnumber[inc], nodes[inc],
1906                         &edges[inc], &edgeptr[inc], &normptr[inc]);
1907       xlo[inc][EDGE] = xlo[inc][NODE];
1908       ylo[inc][EDGE] = ylo[inc][NODE];
1909       xhi[inc][EDGE] = xhi[inc][NODE];
1910       yhi[inc][EDGE] = yhi[inc][NODE];
1911       break;
1912     case PART:
1913       error = load_part(partfilename[inc], node_dim[inc], firstnumber[inc],
1914                         elems[inc], nodeptr[inc], eleptr[inc],
1915                         &subdomains[inc], &partpart[inc], &partcenter[inc],
1916                         &partshift[inc]);
1917       if (!error) {
1918         findpartshift(subdomains[inc], explosion, partcenter[inc],
1919                       partshift[inc]);
1920       }
1921       xlo[inc][PART] = xlo[inc][NODE];
1922       ylo[inc][PART] = ylo[inc][NODE];
1923       xhi[inc][PART] = xhi[inc][NODE];
1924       yhi[inc][PART] = yhi[inc][NODE];
1925       break;
1926     case ADJ:
1927       error = load_adj(adjfilename[inc], &adjsubdomains[inc], &adjptr[inc]);
1928       xlo[inc][ADJ] = xlo[inc][NODE];
1929       ylo[inc][ADJ] = ylo[inc][NODE];
1930       xhi[inc][ADJ] = xhi[inc][NODE];
1931       yhi[inc][ADJ] = yhi[inc][NODE];
1932       break;
1933     case VORO:
1934       error = load_node(vnodefilename[inc], &firstnumber[inc], &vnodes[inc],
1935                         &vnode_dim[inc], &vnodeptr[inc], &xlo[inc][VORO],
1936                         &ylo[inc][VORO], &xhi[inc][VORO], &yhi[inc][VORO]);
1937       if (!error) {
1938         error = load_edge(vedgefilename[inc], firstnumber[inc], vnodes[inc],
1939                           &vedges[inc], &vedgeptr[inc], &vnormptr[inc]);
1940       }
1941       break;
1942     default:
1943       error = 1;
1944   }
1945   if (!error) {
1946     loaded[inc][image] = 1;
1947   }
1948   return error;
1949 }
1950
1951 void choose_image(inc, image)
1952 int inc;
1953 int image;
1954 {
1955   if (!loaded[inc][image]) {
1956     if ((image == ELE) || (image == EDGE) || (image == PART)
1957         || (image == ADJ)) {
1958       if (!loaded[inc][NODE]) {
1959         if (load_image(inc, NODE)) {
1960           return;
1961         }
1962       }
1963     }
1964     if ((image == PART) || (image == ADJ)) {
1965       if (!loaded[inc][ELE]) {
1966         if (load_image(inc, ELE)) {
1967           return;
1968         }
1969       }
1970     }
1971     if (image == ADJ) {
1972       if (!loaded[inc][PART]) {
1973         if (load_image(inc, PART)) {
1974           return;
1975         }
1976       }
1977     }
1978     if (load_image(inc, image)) {
1979       return;
1980     }
1981   }
1982   current_inc = inc;
1983   current_image = image;
1984 }
1985
1986 Window make_button(name, x, y, width)
1987 char *name;
1988 int x;
1989 int y;
1990 int width;
1991 {
1992   XSetWindowAttributes attr;
1993   XSizeHints hints;
1994   Window button;
1995
1996   attr.background_pixel = black;
1997   attr.border_pixel = white;
1998   attr.backing_store = NotUseful;
1999   attr.event_mask = ExposureMask | ButtonReleaseMask | ButtonPressMask;
2000   attr.bit_gravity = SouthWestGravity;
2001   attr.win_gravity = SouthWestGravity;
2002   attr.save_under = False;
2003   button = XCreateWindow(display, mainwindow, x, y, width, BUTTONHEIGHT - 4,
2004                          2, 0, InputOutput, CopyFromParent,
2005                          CWBackPixel | CWBorderPixel | CWEventMask |
2006                          CWBitGravity | CWWinGravity | CWBackingStore |
2007                          CWSaveUnder, &attr);
2008   hints.width = width;
2009   hints.height = BUTTONHEIGHT - 4;
2010   hints.min_width = 0;
2011   hints.min_height = BUTTONHEIGHT - 4;
2012   hints.max_width = width;
2013   hints.max_height = BUTTONHEIGHT - 4;
2014   hints.width_inc = 1;
2015   hints.height_inc = 1;
2016   hints.flags = PMinSize | PMaxSize | PSize | PResizeInc;
2017   XSetStandardProperties(display, button, name, "showme", None, (char **) NULL,
2018                          0, &hints);
2019   return button;
2020 }
2021
2022 void make_buttons(y)
2023 int y;
2024 {
2025   int i;
2026
2027   for (i = 1; i >= 0; i--) {
2028     nodewin[i] = make_button("node", 0, y + (1 - i) * BUTTONHEIGHT, 42);
2029     XMapWindow(display, nodewin[i]);
2030     polywin[i] = make_button("poly", 44, y + (1 - i) * BUTTONHEIGHT, 42);
2031     XMapWindow(display, polywin[i]);
2032     elewin[i] = make_button("ele", 88, y + (1 - i) * BUTTONHEIGHT, 33);
2033     XMapWindow(display, elewin[i]);
2034     edgewin[i] = make_button("edge", 123, y + (1 - i) * BUTTONHEIGHT, 42);
2035     XMapWindow(display, edgewin[i]);
2036     partwin[i] = make_button("part", 167, y + (1 - i) * BUTTONHEIGHT, 42);
2037     XMapWindow(display, partwin[i]);
2038     adjwin[i] = make_button("adj", 211, y + (1 - i) * BUTTONHEIGHT, 33);
2039     XMapWindow(display, adjwin[i]);
2040     voronoiwin[i] = make_button("voro", 246, y + (1 - i) * BUTTONHEIGHT, 42);
2041     XMapWindow(display, voronoiwin[i]);
2042   }
2043   versionpluswin = make_button("    +", 290, y, 52);
2044   XMapWindow(display, versionpluswin);
2045   versionminuswin = make_button("    -", 290, y + BUTTONHEIGHT, 52);
2046   XMapWindow(display, versionminuswin);
2047
2048   quitwin = make_button("Quit", 0, y + 2 * BUTTONHEIGHT, 42);
2049   XMapWindow(display, quitwin);
2050   leftwin = make_button("<", 44, y + 2 * BUTTONHEIGHT, 14);
2051   XMapWindow(display, leftwin);
2052   rightwin = make_button(">", 60, y + 2 * BUTTONHEIGHT, 14);
2053   XMapWindow(display, rightwin);
2054   upwin = make_button("^", 76, y + 2 * BUTTONHEIGHT, 14);
2055   XMapWindow(display, upwin);
2056   downwin = make_button("v", 92, y + 2 * BUTTONHEIGHT, 14);
2057   XMapWindow(display, downwin);
2058   resetwin = make_button("Reset", 108, y + 2 * BUTTONHEIGHT, 52);
2059   XMapWindow(display, resetwin);
2060   widthpluswin = make_button("Width+", 162, y + 2 * BUTTONHEIGHT, 61);
2061   XMapWindow(display, widthpluswin);
2062   widthminuswin = make_button("-", 225, y + 2 * BUTTONHEIGHT, 14);
2063   XMapWindow(display, widthminuswin);
2064   expwin = make_button("Exp", 241, y + 2 * BUTTONHEIGHT, 33);
2065   XMapWindow(display, expwin);
2066   exppluswin = make_button("+", 276, y + 2 * BUTTONHEIGHT, 14);
2067   XMapWindow(display, exppluswin);
2068   expminuswin = make_button("-", 292, y + 2 * BUTTONHEIGHT, 14);
2069   XMapWindow(display, expminuswin);
2070   fillwin = make_button("Fill", 308, y + 2 * BUTTONHEIGHT, 41);
2071   XMapWindow(display, fillwin);
2072   pswin = make_button("PS", 351, y + 2 * BUTTONHEIGHT, 24);
2073   XMapWindow(display, pswin);
2074   epswin = make_button("EPS", 377, y + 2 * BUTTONHEIGHT, 33);
2075   XMapWindow(display, epswin);
2076 }
2077
2078 void fill_button(button)
2079 Window button;
2080 {
2081   int x, y;
2082   unsigned int w, h, d, b;
2083   Window rootw;
2084
2085   XGetGeometry(display, button, &rootw, &x, &y, &w, &h, &d, &b);
2086   XFillRectangle(display, button, fontgc, 0, 0, w, h);
2087 }
2088
2089 void draw_buttons()
2090 {
2091   char numberstring[32];
2092   char buttonstring[6];
2093   int i;
2094
2095   for (i = 1; i >= 0; i--) {
2096     if ((current_image == NODE) && (current_inc == i)) {
2097       fill_button(nodewin[i]);
2098       XDrawString(display, nodewin[i], blackfontgc, 2, 13, "node", 4);
2099     } else {
2100       XClearWindow(display, nodewin[i]);
2101       XDrawString(display, nodewin[i], fontgc, 2, 13, "node", 4);
2102     }
2103     if ((current_image == POLY) && (current_inc == i)) {
2104       fill_button(polywin[i]);
2105       XDrawString(display, polywin[i], blackfontgc, 2, 13, "poly", 4);
2106     } else {
2107       XClearWindow(display, polywin[i]);
2108       XDrawString(display, polywin[i], fontgc, 2, 13, "poly", 4);
2109     }
2110     if ((current_image == ELE) && (current_inc == i)) {
2111       fill_button(elewin[i]);
2112       XDrawString(display, elewin[i], blackfontgc, 2, 13, "ele", 3);
2113     } else {
2114       XClearWindow(display, elewin[i]);
2115       XDrawString(display, elewin[i], fontgc, 2, 13, "ele", 3);
2116     }
2117     if ((current_image == EDGE) && (current_inc == i)) {
2118       fill_button(edgewin[i]);
2119       XDrawString(display, edgewin[i], blackfontgc, 2, 13, "edge", 4);
2120     } else {
2121       XClearWindow(display, edgewin[i]);
2122       XDrawString(display, edgewin[i], fontgc, 2, 13, "edge", 4);
2123     }
2124     if ((current_image == PART) && (current_inc == i)) {
2125       fill_button(partwin[i]);
2126       XDrawString(display, partwin[i], blackfontgc, 2, 13, "part", 4);
2127     } else {
2128       XClearWindow(display, partwin[i]);
2129       XDrawString(display, partwin[i], fontgc, 2, 13, "part", 4);
2130     }
2131     if ((current_image == ADJ) && (current_inc == i)) {
2132       fill_button(adjwin[i]);
2133       XDrawString(display, adjwin[i], blackfontgc, 2, 13, "adj", 3);
2134     } else {
2135       XClearWindow(display, adjwin[i]);
2136       XDrawString(display, adjwin[i], fontgc, 2, 13, "adj", 3);
2137     }
2138     if ((current_image == VORO) && (current_inc == i)) {
2139       fill_button(voronoiwin[i]);
2140       XDrawString(display, voronoiwin[i], blackfontgc, 2, 13, "voro", 4);
2141     } else {
2142       XClearWindow(display, voronoiwin[i]);
2143       XDrawString(display, voronoiwin[i], fontgc, 2, 13, "voro", 4);
2144     }
2145   }
2146
2147   XClearWindow(display, versionpluswin);
2148   sprintf(numberstring, "%d", loweriteration + 1);
2149   sprintf(buttonstring, "%-4.4s+", numberstring);
2150   XDrawString(display, versionpluswin, fontgc, 2, 13, buttonstring, 5);
2151   XClearWindow(display, versionminuswin);
2152   sprintf(numberstring, "%d", loweriteration);
2153   if (loweriteration == 0) {
2154     sprintf(buttonstring, "%-4.4s", numberstring);
2155   } else {
2156     sprintf(buttonstring, "%-4.4s-", numberstring);
2157   }
2158   XDrawString(display, versionminuswin, fontgc, 2, 13, buttonstring, 5);
2159
2160   XClearWindow(display, quitwin);
2161   XDrawString(display, quitwin, fontgc, 2, 13, "Quit", 4);
2162   XClearWindow(display, leftwin);
2163   XDrawString(display, leftwin, fontgc, 2, 13, "<", 1);
2164   XClearWindow(display, rightwin);
2165   XDrawString(display, rightwin, fontgc, 2, 13, ">", 1);
2166   XClearWindow(display, upwin);
2167   XDrawString(display, upwin, fontgc, 2, 13, "^", 1);
2168   XClearWindow(display, downwin);
2169   XDrawString(display, downwin, fontgc, 2, 13, "v", 1);
2170   XClearWindow(display, resetwin);
2171   XDrawString(display, resetwin, fontgc, 2, 13, "Reset", 6);
2172   XClearWindow(display, widthpluswin);
2173   if (line_width < 100) {
2174     XDrawString(display, widthpluswin, fontgc, 2, 13, "Width+", 6);
2175   } else {
2176     XDrawString(display, widthpluswin, fontgc, 2, 13, "Width ", 6);
2177   }
2178   XClearWindow(display, widthminuswin);
2179   if (line_width > 1) {
2180     XDrawString(display, widthminuswin, fontgc, 2, 13, "-", 1);
2181   }
2182   XClearWindow(display, expwin);
2183   XClearWindow(display, exppluswin);
2184   XClearWindow(display, expminuswin);
2185   XClearWindow(display, fillwin);
2186   if (current_image == PART) {
2187     if (explode) {
2188       fill_button(expwin);
2189       XDrawString(display, expwin, blackfontgc, 2, 13, "Exp", 3);
2190     } else {
2191       XDrawString(display, expwin, fontgc, 2, 13, "Exp", 3);
2192     }
2193     XDrawString(display, exppluswin, fontgc, 2, 13, "+", 1);
2194     XDrawString(display, expminuswin, fontgc, 2, 13, "-", 1);
2195     if (fillelem) {
2196       fill_button(fillwin);
2197       XDrawString(display, fillwin, blackfontgc, 2, 13, "Fill", 4);
2198     } else {
2199       XDrawString(display, fillwin, fontgc, 2, 13, "Fill", 4);
2200     }
2201   }
2202   XClearWindow(display, pswin);
2203   XDrawString(display, pswin, fontgc, 2, 13, "PS", 2);
2204   XClearWindow(display, epswin);
2205   XDrawString(display, epswin, fontgc, 2, 13, "EPS", 3);
2206 }
2207
2208 void showme_window(argc, argv)
2209 int argc;
2210 char **argv;
2211 {
2212   XSetWindowAttributes attr;
2213   XSizeHints hints;
2214   XGCValues fontvalues, linevalues;
2215   XColor alloc_color, exact_color;
2216   int i;
2217
2218   display = XOpenDisplay((char *) NULL);
2219   if (!display) {
2220     printf("Error:  Cannot open display.\n");
2221     exit(1);
2222   }
2223   screen = DefaultScreen(display);
2224   rootwindow = DefaultRootWindow(display);
2225   black = BlackPixel(display, screen);
2226   white = WhitePixel(display, screen);
2227   windowdepth = DefaultDepth(display, screen);
2228   rootmap = DefaultColormap(display, screen);
2229   width = STARTWIDTH;
2230   height = STARTHEIGHT;
2231   attr.background_pixel = black;
2232   attr.border_pixel = white;
2233   attr.backing_store = NotUseful;
2234   attr.event_mask = ExposureMask | ButtonReleaseMask | ButtonPressMask |
2235                     StructureNotifyMask;
2236   attr.bit_gravity = NorthWestGravity;
2237   attr.win_gravity = NorthWestGravity;
2238   attr.save_under = False;
2239   mainwindow = XCreateWindow(display, rootwindow, 0, 0, width,
2240                              height + PANELHEIGHT, 3, 0,
2241                              InputOutput, CopyFromParent,
2242                              CWBackPixel | CWBorderPixel | CWEventMask |
2243                              CWBitGravity | CWWinGravity | CWBackingStore |
2244                              CWSaveUnder, &attr);
2245   hints.width = width;
2246   hints.height = height + PANELHEIGHT;
2247   hints.min_width = MINWIDTH;
2248   hints.min_height = MINHEIGHT + PANELHEIGHT;
2249   hints.width_inc = 1;
2250   hints.height_inc = 1;
2251   hints.flags = PMinSize | PSize | PResizeInc;
2252   XSetStandardProperties(display, mainwindow, "Show Me", "showme", None,
2253                          argv, argc, &hints);
2254   XChangeProperty(display, mainwindow, XA_WM_CLASS, XA_STRING, 8,
2255                   PropModeReplace, "showme\0Archimedes", 18);
2256   XClearWindow(display, mainwindow);
2257   XMapWindow(display, mainwindow);
2258   if ((windowdepth > 1) &&
2259       XAllocNamedColor(display, rootmap, "yellow", &alloc_color,
2260                        &exact_color)) {
2261     color = 1;
2262     explode = bw_ps;
2263     fontvalues.foreground = alloc_color.pixel;
2264     linevalues.foreground = alloc_color.pixel;
2265     showme_foreground = alloc_color.pixel;
2266     for (i = 0; i < 64; i++) {
2267       if (XAllocNamedColor(display, rootmap, colorname[i], &alloc_color,
2268                            &rgb[i])) {
2269         colors[i] = alloc_color.pixel;
2270       } else {
2271         colors[i] = white;
2272         rgb[i].red = alloc_color.red;
2273         rgb[i].green = alloc_color.green;
2274         rgb[i].blue = alloc_color.blue;
2275         if (!quiet) {
2276           printf("Warning:  I could not allocate %s.\n", colorname[i]);
2277         }
2278       }
2279     }
2280   } else {
2281     color = 0;
2282     fillelem = 0;
2283     explode = 1;
2284     fontvalues.foreground = white;
2285     linevalues.foreground = white;
2286     showme_foreground = white;
2287   }
2288   font = XLoadQueryFont(display, "9x15");
2289   fontvalues.background = black;
2290   fontvalues.font = font->fid;
2291   fontvalues.fill_style = FillSolid;
2292   fontvalues.line_width = 2;
2293   fontgc = XCreateGC(display, rootwindow, GCForeground | GCBackground |
2294                       GCFont | GCLineWidth | GCFillStyle, &fontvalues);
2295   fontvalues.foreground = black;
2296   blackfontgc = XCreateGC(display, rootwindow, GCForeground | GCBackground |
2297                          GCFont | GCLineWidth | GCFillStyle, &fontvalues);
2298   linevalues.background = black;
2299   linevalues.line_width = line_width;
2300   linevalues.cap_style = CapRound;
2301   linevalues.join_style = JoinRound;
2302   linevalues.fill_style = FillSolid;
2303   linegc = XCreateGC(display, rootwindow, GCForeground | GCBackground |
2304                      GCLineWidth | GCCapStyle | GCJoinStyle | GCFillStyle,
2305                      &linevalues);
2306   trianglegc = XCreateGC(display, rootwindow, GCForeground | GCBackground |
2307                          GCLineWidth | GCCapStyle | GCJoinStyle | GCFillStyle,
2308                          &linevalues);
2309   make_buttons(height);
2310   XFlush(display);
2311 }
2312
2313 void draw_node(nodes, dim, ptr, xscale, yscale, xoffset, yoffset)
2314 int nodes;
2315 int dim;
2316 REAL *ptr;
2317 REAL xscale;
2318 REAL yscale;
2319 REAL xoffset;
2320 REAL yoffset;
2321 {
2322   int i;
2323   int index;
2324
2325   index = dim;
2326   for (i = 1; i <= nodes; i++) {
2327     XFillRectangle(display, mainwindow, linegc,
2328                    (int) (ptr[index] * xscale + xoffset) - (line_width >> 1),
2329                    (int) (ptr[index + 1] * yscale + yoffset) -
2330                          (line_width >> 1), line_width, line_width);
2331     index += dim;
2332   }
2333 }
2334
2335 void draw_poly(nodes, dim, edges, holes, nodeptr, edgeptr, holeptr,
2336                xscale, yscale, xoffset, yoffset)
2337 int nodes;
2338 int dim;
2339 int edges;
2340 int holes;
2341 REAL *nodeptr;
2342 int *edgeptr;
2343 REAL *holeptr;
2344 REAL xscale;
2345 REAL yscale;
2346 REAL xoffset;
2347 REAL yoffset;
2348 {
2349   int i;
2350   int index;
2351   REAL *point1, *point2;
2352   int x1, y1, x2, y2;
2353
2354   index = dim;
2355   for (i = 1; i <= nodes; i++) {
2356     XFillRectangle(display, mainwindow, linegc,
2357                    (int) (nodeptr[index] * xscale + xoffset) -
2358                          (line_width >> 1),
2359                    (int) (nodeptr[index + 1] * yscale + yoffset) -
2360                          (line_width >> 1), line_width, line_width);
2361     index += dim;
2362   }
2363   index = 2;
2364   for (i = 1; i <= edges; i++) {
2365     point1 = &nodeptr[edgeptr[index++] * dim];
2366     point2 = &nodeptr[edgeptr[index++] * dim];
2367     XDrawLine(display, mainwindow, linegc,
2368               (int) (point1[0] * xscale + xoffset),
2369               (int) (point1[1] * yscale + yoffset),
2370               (int) (point2[0] * xscale + xoffset),
2371               (int) (point2[1] * yscale + yoffset));
2372   }
2373   index = dim;
2374   if (color) {
2375     XSetForeground(display, linegc, colors[0]);
2376   }
2377   for (i = 1; i <= holes; i++) {
2378     x1 = (int) (holeptr[index] * xscale + xoffset) - 3;
2379     y1 = (int) (holeptr[index + 1] * yscale + yoffset) - 3;
2380     x2 = x1 + 6;
2381     y2 = y1 + 6;
2382     XDrawLine(display, mainwindow, linegc, x1, y1, x2, y2);
2383     XDrawLine(display, mainwindow, linegc, x1, y2, x2, y1);
2384     index += dim;
2385   }
2386   XSetForeground(display, linegc, showme_foreground);
2387 }
2388
2389 void draw_ele(inc, elems, corners, ptr, partition, shift,
2390               xscale, yscale, xoffset, yoffset)
2391 int inc;
2392 int elems;
2393 int corners;
2394 int *ptr;
2395 int *partition;
2396 REAL *shift;
2397 REAL xscale;
2398 REAL yscale;
2399 REAL xoffset;
2400 REAL yoffset;
2401 {
2402   int i, j;
2403   int index;
2404   REAL shiftx, shifty;
2405   REAL *prevpoint, *nowpoint;
2406   XPoint *vertices;
2407
2408   if (color && fillelem && (partition != (int *) NULL)) {
2409     vertices = (XPoint *) malloc(3 * sizeof(XPoint));
2410     if (vertices == (XPoint *) NULL) {
2411       printf("Error:  Out of memory.\n");
2412       exit(1);
2413     }
2414   }
2415   index = 3;
2416   for (i = 1; i <= elems; i++) {
2417     if ((partition != (int *) NULL) && explode) {
2418       shiftx = shift[partition[i] << 1];
2419       shifty = shift[(partition[i] << 1) + 1];
2420     }
2421     if (color && (partition != (int *) NULL)) {
2422       if (fillelem) {
2423         XSetForeground(display, trianglegc, colors[partition[i] & 63]);
2424       } else {
2425         XSetForeground(display, linegc, colors[partition[i] & 63]);
2426       }
2427     }
2428     if (color && fillelem && (partition != (int *) NULL)) {
2429       if ((partition != (int *) NULL) && explode) {
2430         for (j = 0; j < 3; j++) {
2431           nowpoint = &nodeptr[inc][ptr[index + j] * node_dim[inc]];
2432           vertices[j].x = (nowpoint[0] + shiftx) * xscale + xoffset;
2433           vertices[j].y = (nowpoint[1] + shifty) * yscale + yoffset;
2434         }
2435       } else {
2436         for (j = 0; j < 3; j++) {
2437           nowpoint = &nodeptr[inc][ptr[index + j] * node_dim[inc]];
2438           vertices[j].x = nowpoint[0] * xscale + xoffset;
2439           vertices[j].y = nowpoint[1] * yscale + yoffset;
2440         }
2441       }
2442       XFillPolygon(display, mainwindow, trianglegc, vertices, 3,
2443                    Convex, CoordModeOrigin);
2444     }
2445     prevpoint = &nodeptr[inc][ptr[index + 2] * node_dim[inc]];
2446     if ((partition != (int *) NULL) && explode) {
2447       for (j = 0; j < 3; j++) {
2448         nowpoint = &nodeptr[inc][ptr[index++] * node_dim[inc]];
2449         XDrawLine(display, mainwindow, linegc,
2450                   (int) ((prevpoint[0] + shiftx) * xscale + xoffset),
2451                   (int) ((prevpoint[1] + shifty) * yscale + yoffset),
2452                   (int) ((nowpoint[0] + shiftx) * xscale + xoffset),
2453                   (int) ((nowpoint[1] + shifty) * yscale + yoffset));
2454         prevpoint = nowpoint;
2455       }
2456     } else {
2457       for (j = 0; j < 3; j++) {
2458         nowpoint = &nodeptr[inc][ptr[index++] * node_dim[inc]];
2459         XDrawLine(display, mainwindow, linegc,
2460                   (int) (prevpoint[0] * xscale + xoffset),
2461                   (int) (prevpoint[1] * yscale + yoffset),
2462                   (int) (nowpoint[0] * xscale + xoffset),
2463                   (int) (nowpoint[1] * yscale + yoffset));
2464         prevpoint = nowpoint;
2465       }
2466     }
2467   }
2468   if (color && fillelem && (partition != (int *) NULL)) {
2469     free(vertices);
2470   }
2471   XSetForeground(display, linegc, showme_foreground);
2472 }
2473
2474 void draw_edge(nodes, dim, edges, nodeptr, edgeptr, normptr,
2475                xscale, yscale, xoffset, yoffset)
2476 int nodes;
2477 int dim;
2478 int edges;
2479 REAL *nodeptr;
2480 int *edgeptr;
2481 REAL *normptr;
2482 REAL xscale;
2483 REAL yscale;
2484 REAL xoffset;
2485 REAL yoffset;
2486 {
2487   int i;
2488   int index;
2489   REAL *point1, *point2;
2490   REAL normx, normy;
2491   REAL normmult, normmultx, normmulty;
2492   REAL windowxmin, windowymin, windowxmax, windowymax;
2493
2494   index = 2;
2495   for (i = 1; i <= edges; i++) {
2496     point1 = &nodeptr[edgeptr[index++] * dim];
2497     if (edgeptr[index] == -1) {
2498       normx = normptr[index - 1];
2499       normy = normptr[index++];
2500       normmultx = 0.0;
2501       if (normx > 0) {
2502         windowxmax = (width - 1 - xoffset) / xscale;
2503         normmultx = (windowxmax - point1[0]) / normx;
2504       } else if (normx < 0) {
2505         windowxmin = -xoffset / xscale;
2506         normmultx = (windowxmin - point1[0]) / normx;
2507       }
2508       normmulty = 0.0;
2509       if (normy > 0) {
2510         windowymax = -yoffset / yscale;
2511         normmulty = (windowymax - point1[1]) / normy;
2512       } else if (normy < 0) {
2513         windowymin = (height - 1 - yoffset) / yscale;
2514         normmulty = (windowymin - point1[1]) / normy;
2515       }
2516       if (normmultx == 0.0) {
2517         normmult = normmulty;
2518       } else if (normmulty == 0.0) {
2519         normmult = normmultx;
2520       } else if (normmultx < normmulty) {
2521         normmult = normmultx;
2522       } else {
2523         normmult = normmulty;
2524       }
2525       if (normmult > 0.0) {
2526         XDrawLine(display, mainwindow, linegc,
2527                   (int) (point1[0] * xscale + xoffset),
2528                   (int) (point1[1] * yscale + yoffset),
2529                   (int) ((point1[0] + normmult * normx) * xscale + xoffset),
2530                   (int) ((point1[1] + normmult * normy) * yscale + yoffset));
2531       }
2532     } else {
2533       point2 = &nodeptr[edgeptr[index++] * dim];
2534       XDrawLine(display, mainwindow, linegc,
2535                 (int) (point1[0] * xscale + xoffset),
2536                 (int) (point1[1] * yscale + yoffset),
2537                 (int) (point2[0] * xscale + xoffset),
2538                 (int) (point2[1] * yscale + yoffset));
2539     }
2540   }
2541 }
2542
2543 void draw_adj(dim, subdomains, ptr, center, xscale, yscale,
2544               xoffset, yoffset)
2545 int dim;
2546 int subdomains;
2547 int *ptr;
2548 REAL *center;
2549 REAL xscale;
2550 REAL yscale;
2551 REAL xoffset;
2552 REAL yoffset;
2553 {
2554   int i, j;
2555   REAL *point1, *point2;
2556
2557   for (i = 0; i < subdomains; i++) {
2558     for (j = i + 1; j < subdomains; j++) {
2559       if (ptr[i * subdomains + j]) {
2560         point1 = &center[i * dim];
2561         point2 = &center[j * dim];
2562         XDrawLine(display, mainwindow, linegc,
2563                   (int) (point1[0] * xscale + xoffset),
2564                   (int) (point1[1] * yscale + yoffset),
2565                   (int) (point2[0] * xscale + xoffset),
2566                   (int) (point2[1] * yscale + yoffset));
2567       }
2568     }
2569   }
2570   for (i = 0; i < subdomains; i++) {
2571     point1 = &center[i * dim];
2572     if (color) {
2573       XSetForeground(display, linegc, colors[i & 63]);
2574     }
2575     XFillArc(display, mainwindow, linegc,
2576              (int) (point1[0] * xscale + xoffset) - 5 - (line_width >> 1),
2577              (int) (point1[1] * yscale + yoffset) - 5 - (line_width >> 1),
2578              line_width + 10, line_width + 10, 0, 23040);
2579   }
2580   XSetForeground(display, linegc, showme_foreground);
2581 }
2582
2583 void draw(inc, image, xmin, ymin, xmax, ymax)
2584 int inc;
2585 int image;
2586 REAL xmin;
2587 REAL ymin;
2588 REAL xmax;
2589 REAL ymax;
2590 {
2591   draw_buttons();
2592   XClearWindow(display, mainwindow);
2593   if (image == NOTHING) {
2594     return;
2595   }
2596   if (!loaded[inc][image]) {
2597     return;
2598   }
2599   if ((image == PART) && explode) {
2600     xmin += (xmin - partcenter[inc][subdomains[inc] << 1]) * explosion;
2601     xmax += (xmax - partcenter[inc][subdomains[inc] << 1]) * explosion;
2602     ymin += (ymin - partcenter[inc][(subdomains[inc] << 1) + 1]) * explosion;
2603     ymax += (ymax - partcenter[inc][(subdomains[inc] << 1) + 1]) * explosion;
2604   }
2605   xscale = (REAL) (width - line_width - 4) / (xmax - xmin);
2606   yscale = (REAL) (height - line_width - 4) / (ymax - ymin);
2607   if (xscale > yscale) {
2608     xscale = yscale;
2609   } else {
2610     yscale = xscale;
2611   }
2612   xoffset = 0.5 * ((REAL) width - xscale * (xmax - xmin)) -
2613             xscale * xmin;
2614   yoffset = (REAL) height - 0.5 * ((REAL) height - yscale * (ymax - ymin)) +
2615             yscale * ymin;
2616   yscale = - yscale;
2617   switch(image) {
2618     case NODE:
2619       draw_node(nodes[inc], node_dim[inc], nodeptr[inc],
2620                 xscale, yscale, xoffset, yoffset);
2621       break;
2622     case POLY:
2623       if (polynodes[inc] > 0) {
2624         draw_poly(polynodes[inc], poly_dim[inc], polyedges[inc],
2625                   polyholes[inc], polynodeptr[inc], polyedgeptr[inc],
2626                   polyholeptr[inc],
2627                   xscale, yscale, xoffset, yoffset);
2628       } else {
2629         draw_poly(nodes[inc], node_dim[inc], polyedges[inc],
2630                   polyholes[inc], nodeptr[inc], polyedgeptr[inc],
2631                   polyholeptr[inc],
2632                   xscale, yscale, xoffset, yoffset);
2633       }
2634       break;
2635     case ELE:
2636       draw_ele(inc, elems[inc], ele_corners[inc], eleptr[inc],
2637                (int *) NULL, (REAL *) NULL,
2638                xscale, yscale, xoffset, yoffset);
2639       break;
2640     case EDGE:
2641       draw_edge(nodes[inc], node_dim[inc], edges[inc],
2642                 nodeptr[inc], edgeptr[inc], normptr[inc],
2643                 xscale, yscale, xoffset, yoffset);
2644       break;
2645     case PART:
2646       draw_ele(inc, elems[inc], ele_corners[inc], eleptr[inc],
2647                partpart[inc], partshift[inc],
2648                xscale, yscale, xoffset, yoffset);
2649       break;
2650     case ADJ:
2651       draw_adj(node_dim[inc], adjsubdomains[inc], adjptr[inc], partcenter[inc],
2652                xscale, yscale, xoffset, yoffset);
2653       break;
2654     case VORO:
2655       if (loaded[inc][NODE]) {
2656         draw_node(nodes[inc], node_dim[inc], nodeptr[inc],
2657                   xscale, yscale, xoffset, yoffset);
2658       }
2659       draw_edge(vnodes[inc], vnode_dim[inc], vedges[inc],
2660                 vnodeptr[inc], vedgeptr[inc], vnormptr[inc],
2661                 xscale, yscale, xoffset, yoffset);
2662       break;
2663     default:
2664       break;
2665   }
2666 }
2667
2668 void addps(instring, outstring, eps)
2669 char *instring;
2670 char *outstring;
2671 int eps;
2672 {
2673   strcpy(outstring, instring);
2674   if (eps) {
2675     strcat(outstring, ".eps");
2676   } else {
2677     strcat(outstring, ".ps");
2678   }
2679 }
2680
2681 int print_head(fname, file, llcornerx, llcornery, eps)
2682 char *fname;
2683 FILE **file;
2684 int llcornerx;
2685 int llcornery;
2686 int eps;
2687 {
2688   if (!quiet) {
2689     printf("Writing %s\n", fname);
2690   }
2691   *file = fopen(fname, "w");
2692   if (*file == (FILE *) NULL) {
2693     printf("  Error:  Could not open %s\n", fname);
2694     return 1;
2695   }
2696   if (eps) {
2697     fprintf(*file, "%%!PS-Adobe-2.0 EPSF-2.0\n");
2698   } else {
2699     fprintf(*file, "%%!PS-Adobe-2.0\n");
2700   }
2701   fprintf(*file, "%%%%BoundingBox: %d %d %d %d\n", llcornerx, llcornery,
2702           612 - llcornerx, 792 - llcornery);
2703   fprintf(*file, "%%%%Creator: Show Me\n");
2704   fprintf(*file, "%%%%EndComments\n\n");
2705   fprintf(*file, "1 setlinecap\n");
2706   fprintf(*file, "1 setlinejoin\n");
2707   fprintf(*file, "%d setlinewidth\n", line_width);
2708   fprintf(*file, "%d %d moveto\n", llcornerx, llcornery);
2709   fprintf(*file, "%d %d lineto\n", 612 - llcornerx, llcornery);
2710   fprintf(*file, "%d %d lineto\n", 612 - llcornerx, 792 - llcornery);
2711   fprintf(*file, "%d %d lineto\n", llcornerx, 792 - llcornery);
2712   fprintf(*file, "closepath\nclip\nnewpath\n");
2713   return 0;
2714 }
2715
2716 void print_node(nodefile, nodes, dim, ptr, xscale, yscale,
2717                 xoffset, yoffset)
2718 FILE *nodefile;
2719 int nodes;
2720 int dim;
2721 REAL *ptr;
2722 REAL xscale;
2723 REAL yscale;
2724 REAL xoffset;
2725 REAL yoffset;
2726 {
2727   int i;
2728   int index;
2729
2730   index = dim;
2731   for (i = 1; i <= nodes; i++) {
2732     fprintf(nodefile, "%d %d %d 0 360 arc\nfill\n",
2733             (int) (ptr[index] * xscale + xoffset),
2734             (int) (ptr[index + 1] * yscale + yoffset),
2735             1 + (line_width >> 1));
2736     index += dim;
2737   }
2738 }
2739
2740 void print_poly(polyfile, nodes, dim, edges, holes, nodeptr, edgeptr, holeptr,
2741                 xscale, yscale, xoffset, yoffset)
2742 FILE *polyfile;
2743 int nodes;
2744 int dim;
2745 int edges;
2746 int holes;
2747 REAL *nodeptr;
2748 int *edgeptr;
2749 REAL *holeptr;
2750 REAL xscale;
2751 REAL yscale;
2752 REAL xoffset;
2753 REAL yoffset;
2754 {
2755   int i;
2756   int index;
2757   REAL *point1, *point2;
2758
2759   index = dim;
2760   for (i = 1; i <= nodes; i++) {
2761     fprintf(polyfile, "%d %d %d 0 360 arc\nfill\n",
2762             (int) (nodeptr[index] * xscale + xoffset),
2763             (int) (nodeptr[index + 1] * yscale + yoffset),
2764             1 + (line_width >> 1));
2765     index += dim;
2766   }
2767   index = 2;
2768   for (i = 1; i <= edges; i++) {
2769     point1 = &nodeptr[edgeptr[index++] * dim];
2770     point2 = &nodeptr[edgeptr[index++] * dim];
2771     fprintf(polyfile, "%d %d moveto\n",
2772             (int) (point1[0] * xscale + xoffset),
2773             (int) (point1[1] * yscale + yoffset));
2774     fprintf(polyfile, "%d %d lineto\nstroke\n",
2775             (int) (point2[0] * xscale + xoffset),
2776             (int) (point2[1] * yscale + yoffset));
2777   }
2778 }
2779
2780 void print_ele(elefile, nodes, dim, elems, corners, nodeptr, eleptr,
2781                partition, shift,
2782                xscale, yscale, xoffset, yoffset, llcornerx, llcornery)
2783 FILE *elefile;
2784 int nodes;
2785 int dim;
2786 int elems;
2787 int corners;
2788 REAL *nodeptr;
2789 int *eleptr;
2790 int *partition;
2791 REAL *shift;
2792 REAL xscale;
2793 REAL yscale;
2794 REAL xoffset;
2795 REAL yoffset;
2796 int llcornerx;
2797 int llcornery;
2798 {
2799   int i, j;
2800   int index, colorindex;
2801   REAL shiftx, shifty;
2802   REAL *nowpoint;
2803
2804   index = 3;
2805   if ((partition != (int *) NULL) && !bw_ps) {
2806     fprintf(elefile, "0 0 0 setrgbcolor\n");
2807     fprintf(elefile, "%d %d moveto\n", llcornerx, llcornery);
2808     fprintf(elefile, "%d %d lineto\n", 612 - llcornerx, llcornery);
2809     fprintf(elefile, "%d %d lineto\n", 612 - llcornerx, 792 - llcornery);
2810     fprintf(elefile, "%d %d lineto\n", llcornerx, 792 - llcornery);
2811     fprintf(elefile, "fill\n");
2812   }
2813   for (i = 1; i <= elems; i++) {
2814     if ((partition != (int *) NULL) && !bw_ps) {
2815       colorindex = partition[i] & 63;
2816       fprintf(elefile, "%6.3f %6.3f %6.3f setrgbcolor\n",
2817               (REAL) rgb[colorindex].red / 65535.0,
2818               (REAL) rgb[colorindex].green / 65535.0,
2819               (REAL) rgb[colorindex].blue / 65535.0);
2820     }
2821     nowpoint = &nodeptr[eleptr[index + 2] * dim];
2822     if ((partition != (int *) NULL) && (explode || bw_ps)) {
2823       shiftx = shift[partition[i] << 1];
2824       shifty = shift[(partition[i] << 1) + 1];
2825       fprintf(elefile, "%d %d moveto\n",
2826               (int) ((nowpoint[0] + shiftx) * xscale + xoffset),
2827               (int) ((nowpoint[1] + shifty) * yscale + yoffset));
2828       for (j = 0; j < 3; j++) {
2829         nowpoint = &nodeptr[eleptr[index++] * dim];
2830         fprintf(elefile, "%d %d lineto\n",
2831                 (int) ((nowpoint[0] + shiftx) * xscale + xoffset),
2832                 (int) ((nowpoint[1] + shifty) * yscale + yoffset));
2833       }
2834     } else {
2835       fprintf(elefile, "%d %d moveto\n",
2836               (int) (nowpoint[0] * xscale + xoffset),
2837               (int) (nowpoint[1] * yscale + yoffset));
2838       for (j = 0; j < 3; j++) {
2839         nowpoint = &nodeptr[eleptr[index++] * dim];
2840         fprintf(elefile, "%d %d lineto\n",
2841                 (int) (nowpoint[0] * xscale + xoffset),
2842                 (int) (nowpoint[1] * yscale + yoffset));
2843       }
2844     }
2845     if (fillelem && !bw_ps) {
2846       fprintf(elefile, "gsave\nfill\ngrestore\n1 1 0 setrgbcolor\n");
2847     }
2848     fprintf(elefile, "stroke\n");
2849   }
2850 }
2851
2852 void print_edge(edgefile, nodes, dim, edges, nodeptr, edgeptr, normptr,
2853                 xscale, yscale, xoffset, yoffset, llcornerx, llcornery)
2854 FILE *edgefile;
2855 int nodes;
2856 int dim;
2857 int edges;
2858 REAL *nodeptr;
2859 int *edgeptr;
2860 REAL *normptr;
2861 REAL xscale;
2862 REAL yscale;
2863 REAL xoffset;
2864 REAL yoffset;
2865 int llcornerx;
2866 int llcornery;
2867 {
2868   int i;
2869   int index;
2870   REAL *point1, *point2;
2871   REAL normx, normy;
2872   REAL normmult, normmultx, normmulty;
2873   REAL windowxmin, windowymin, windowxmax, windowymax;
2874
2875   index = 2;
2876   for (i = 1; i <= edges; i++) {
2877     point1 = &nodeptr[edgeptr[index++] * dim];
2878     if (edgeptr[index] == -1) {
2879       normx = normptr[index - 1];
2880       normy = normptr[index++];
2881       normmultx = 0.0;
2882       if (normx > 0) {
2883         windowxmax = ((REAL) (612 - llcornerx) - xoffset) / xscale;
2884         normmultx = (windowxmax - point1[0]) / normx;
2885       } else if (normx < 0) {
2886         windowxmin = ((REAL) llcornerx - xoffset) / xscale;
2887         normmultx = (windowxmin - point1[0]) / normx;
2888       }
2889       normmulty = 0.0;
2890       if (normy > 0) {
2891         windowymax = ((REAL) (792 - llcornery) - yoffset) / yscale;
2892         normmulty = (windowymax - point1[1]) / normy;
2893       } else if (normy < 0) {
2894         windowymin = ((REAL) llcornery - yoffset) / yscale;
2895         normmulty = (windowymin - point1[1]) / normy;
2896       }
2897       if (normmultx == 0.0) {
2898         normmult = normmulty;
2899       } else if (normmulty == 0.0) {
2900         normmult = normmultx;
2901       } else if (normmultx < normmulty) {
2902         normmult = normmultx;
2903       } else {
2904         normmult = normmulty;
2905       }
2906       if (normmult > 0.0) {
2907         fprintf(edgefile, "%d %d moveto\n",
2908                 (int) (point1[0] * xscale + xoffset),
2909                 (int) (point1[1] * yscale + yoffset));
2910         fprintf(edgefile, "%d %d lineto\nstroke\n",
2911                 (int) ((point1[0] + normmult * normx) * xscale + xoffset),
2912                 (int) ((point1[1] + normmult * normy) * yscale + yoffset));
2913       }
2914     } else {
2915       point2 = &nodeptr[edgeptr[index++] * dim];
2916       fprintf(edgefile, "%d %d moveto\n",
2917               (int) (point1[0] * xscale + xoffset),
2918               (int) (point1[1] * yscale + yoffset));
2919       fprintf(edgefile, "%d %d lineto\nstroke\n",
2920               (int) (point2[0] * xscale + xoffset),
2921               (int) (point2[1] * yscale + yoffset));
2922     }
2923   }
2924 }
2925
2926 void print_adj(adjfile, dim, subdomains, ptr, center, xscale, yscale,
2927                xoffset, yoffset, llcornerx, llcornery)
2928 FILE *adjfile;
2929 int dim;
2930 int subdomains;
2931 int *ptr;
2932 REAL *center;
2933 REAL xscale;
2934 REAL yscale;
2935 REAL xoffset;
2936 REAL yoffset;
2937 int llcornerx;
2938 int llcornery;
2939 {
2940   int i, j;
2941   REAL *point1, *point2;
2942   int colorindex;
2943
2944   if (!bw_ps) {
2945     fprintf(adjfile, "0 0 0 setrgbcolor\n");
2946     fprintf(adjfile, "%d %d moveto\n", llcornerx, llcornery);
2947     fprintf(adjfile, "%d %d lineto\n", 612 - llcornerx, llcornery);
2948     fprintf(adjfile, "%d %d lineto\n", 612 - llcornerx, 792 - llcornery);
2949     fprintf(adjfile, "%d %d lineto\n", llcornerx, 792 - llcornery);
2950     fprintf(adjfile, "fill\n");
2951     fprintf(adjfile, "1 1 0 setrgbcolor\n");
2952   }
2953   for (i = 0; i < subdomains; i++) {
2954     for (j = i + 1; j < subdomains; j++) {
2955       if (ptr[i * subdomains + j]) {
2956         point1 = &center[i * dim];
2957         point2 = &center[j * dim];
2958         fprintf(adjfile, "%d %d moveto\n",
2959                 (int) (point1[0] * xscale + xoffset),
2960                 (int) (point1[1] * yscale + yoffset));
2961         fprintf(adjfile, "%d %d lineto\nstroke\n",
2962                 (int) (point2[0] * xscale + xoffset),
2963                 (int) (point2[1] * yscale + yoffset));
2964       }
2965     }
2966   }
2967   for (i = 0; i < subdomains; i++) {
2968     point1 = &center[i * dim];
2969     if (!bw_ps) {
2970       colorindex = i & 63;
2971       fprintf(adjfile, "%6.3f %6.3f %6.3f setrgbcolor\n",
2972               (REAL) rgb[colorindex].red / 65535.0,
2973               (REAL) rgb[colorindex].green / 65535.0,
2974               (REAL) rgb[colorindex].blue / 65535.0);
2975       fprintf(adjfile, "%d %d %d 0 360 arc\nfill\n",
2976               (int) (point1[0] * xscale + xoffset),
2977               (int) (point1[1] * yscale + yoffset),
2978               5 + (line_width >> 1));
2979     } else {
2980       fprintf(adjfile, "%d %d %d 0 360 arc\nfill\n",
2981               (int) (point1[0] * xscale + xoffset),
2982               (int) (point1[1] * yscale + yoffset),
2983               3 + (line_width >> 1));
2984     }
2985   }
2986 }
2987
2988 void print(inc, image, xmin, ymin, xmax, ymax, eps)
2989 int inc;
2990 int image;
2991 REAL xmin;
2992 REAL ymin;
2993 REAL xmax;
2994 REAL ymax;
2995 int eps;
2996 {
2997   REAL xxscale, yyscale, xxoffset, yyoffset;
2998   char psfilename[FILENAMESIZE];
2999   int llcornerx, llcornery;
3000   FILE *psfile;
3001
3002   if (image == NOTHING) {
3003     return;
3004   }
3005   if (!loaded[inc][image]) {
3006     return;
3007   }
3008   if ((image == PART) && (explode || bw_ps)) {
3009     xmin += (xmin - partcenter[inc][subdomains[inc] << 1]) * explosion;
3010     xmax += (xmax - partcenter[inc][subdomains[inc] << 1]) * explosion;
3011     ymin += (ymin - partcenter[inc][(subdomains[inc] << 1) + 1]) * explosion;
3012     ymax += (ymax - partcenter[inc][(subdomains[inc] << 1) + 1]) * explosion;
3013   }
3014   xxscale = (460.0 - (REAL) line_width) / (xmax - xmin);
3015   yyscale = (640.0 - (REAL) line_width) / (ymax - ymin);
3016   if (xxscale > yyscale) {
3017     xxscale = yyscale;
3018     llcornerx = (604 - (int) (yyscale * (xmax - xmin)) - line_width) >> 1;
3019     llcornery = 72;
3020   } else {
3021     yyscale = xxscale;
3022     llcornerx = 72;
3023     llcornery = (784 - (int) (xxscale * (ymax - ymin)) - line_width) >> 1;
3024   }
3025   xxoffset = 0.5 * (612.0 - xxscale * (xmax - xmin)) - xxscale * xmin +
3026              (line_width >> 1);
3027   yyoffset = 0.5 * (792.0 - yyscale * (ymax - ymin)) - yyscale * ymin +
3028              (line_width >> 1);
3029   switch(image) {
3030     case NODE:
3031       addps(nodefilename[inc], psfilename, eps);
3032       break;
3033     case POLY:
3034       addps(polyfilename[inc], psfilename, eps);
3035       break;
3036     case ELE:
3037       addps(elefilename[inc], psfilename, eps);
3038       break;
3039     case EDGE:
3040       addps(edgefilename[inc], psfilename, eps);
3041       break;
3042     case PART:
3043       addps(partfilename[inc], psfilename, eps);
3044       break;
3045     case ADJ:
3046       addps(adjfilename[inc], psfilename, eps);
3047       break;
3048     case VORO:
3049       addps(vedgefilename[inc], psfilename, eps);
3050       break;
3051     default:
3052       break;
3053   }
3054   if (print_head(psfilename, &psfile, llcornerx, llcornery, eps)) {
3055     return;
3056   }
3057   switch(image) {
3058     case NODE:
3059       print_node(psfile, nodes[inc], node_dim[inc], nodeptr[inc],
3060                  xxscale, yyscale, xxoffset, yyoffset);
3061       break;
3062     case POLY:
3063       if (polynodes[inc] > 0) {
3064         print_poly(psfile, polynodes[inc], poly_dim[inc], polyedges[inc],
3065                    polyholes[inc], polynodeptr[inc], polyedgeptr[inc],
3066                    polyholeptr[inc], xxscale, yyscale, xxoffset, yyoffset);
3067       } else {
3068         print_poly(psfile, nodes[inc], node_dim[inc], polyedges[inc],
3069                    polyholes[inc], nodeptr[inc], polyedgeptr[inc],
3070                    polyholeptr[inc], xxscale, yyscale, xxoffset, yyoffset);
3071       }
3072       break;
3073     case ELE:
3074       print_ele(psfile, nodes[inc], node_dim[inc], elems[inc],
3075                 ele_corners[inc], nodeptr[inc], eleptr[inc],
3076                 (int *) NULL, (REAL *) NULL,
3077                 xxscale, yyscale, xxoffset, yyoffset, llcornerx, llcornery);
3078       break;
3079     case EDGE:
3080       print_edge(psfile, nodes[inc], node_dim[inc], edges[inc],
3081                  nodeptr[inc], edgeptr[inc], normptr[inc],
3082                  xxscale, yyscale, xxoffset, yyoffset, llcornerx, llcornery);
3083       break;
3084     case PART:
3085       print_ele(psfile, nodes[inc], node_dim[inc], elems[inc],
3086                 ele_corners[inc], nodeptr[inc], eleptr[inc],
3087                 partpart[inc], partshift[inc],
3088                 xxscale, yyscale, xxoffset, yyoffset, llcornerx, llcornery);
3089       break;
3090     case ADJ:
3091       print_adj(psfile, node_dim[inc], adjsubdomains[inc], adjptr[inc],
3092                 partcenter[inc],
3093                 xxscale, yyscale, xxoffset, yyoffset, llcornerx, llcornery);
3094       break;
3095     case VORO:
3096       print_edge(psfile, vnodes[inc], vnode_dim[inc], vedges[inc],
3097                  vnodeptr[inc], vedgeptr[inc], vnormptr[inc],
3098                  xxscale, yyscale, xxoffset, yyoffset, llcornerx, llcornery);
3099       break;
3100     default:
3101       break;
3102   }
3103   if (!eps) {
3104     fprintf(psfile, "showpage\n");
3105   }
3106   fclose(psfile);
3107 }
3108
3109 int main(argc, argv)
3110 int argc;
3111 char **argv;
3112 {
3113   REAL xmin, ymin, xmax, ymax;
3114   REAL xptr, yptr, xspan, yspan;
3115   int past_image;
3116   int new_image;
3117   int new_inc;
3118
3119   parsecommandline(argc, argv);
3120   showme_init();
3121   choose_image(start_inc, start_image);
3122   showme_window(argc, argv);
3123
3124   if (current_image != NOTHING) {
3125     xmin = xlo[current_inc][current_image];
3126     ymin = ylo[current_inc][current_image];
3127     xmax = xhi[current_inc][current_image];
3128     ymax = yhi[current_inc][current_image];
3129     zoom = 0;
3130   }
3131
3132   XMaskEvent(display, ExposureMask, &event);
3133   while (1) {
3134     switch (event.type) {
3135       case ButtonRelease:
3136         if (event.xany.window == quitwin) {
3137           XDestroyWindow(display, mainwindow);
3138           XCloseDisplay(display);
3139           return 0;
3140         } else if (event.xany.window == leftwin) {
3141           xspan = 0.25 * (xmax - xmin);
3142           xmin += xspan;
3143           xmax += xspan;
3144           draw(current_inc, current_image, xmin, ymin, xmax, ymax);
3145         } else if (event.xany.window == rightwin) {
3146           xspan = 0.25 * (xmax - xmin);
3147           xmin -= xspan;
3148           xmax -= xspan;
3149           draw(current_inc, current_image, xmin, ymin, xmax, ymax);
3150         } else if (event.xany.window == upwin) {
3151           yspan = 0.25 * (ymax - ymin);
3152           ymin -= yspan;
3153           ymax -= yspan;
3154           draw(current_inc, current_image, xmin, ymin, xmax, ymax);
3155         } else if (event.xany.window == downwin) {
3156           yspan = 0.25 * (ymax - ymin);
3157           ymin += yspan;
3158           ymax += yspan;
3159           draw(current_inc, current_image, xmin, ymin, xmax, ymax);
3160         } else if (event.xany.window == resetwin) {
3161           xmin = xlo[current_inc][current_image];
3162           ymin = ylo[current_inc][current_image];
3163           xmax = xhi[current_inc][current_image];
3164           ymax = yhi[current_inc][current_image];
3165           zoom = 0;
3166           draw(current_inc, current_image, xmin, ymin, xmax, ymax);
3167         } else if (event.xany.window == widthpluswin) {
3168           if (line_width < 100) {
3169             line_width++;
3170             XSetLineAttributes(display, linegc, line_width, LineSolid,
3171                                CapRound, JoinRound);
3172             XSetLineAttributes(display, trianglegc, line_width, LineSolid,
3173                                CapRound, JoinRound);
3174             draw(current_inc, current_image, xmin, ymin, xmax, ymax);
3175           }
3176         } else if (event.xany.window == widthminuswin) {
3177           if (line_width > 1) {
3178             line_width--;
3179             XSetLineAttributes(display, linegc, line_width, LineSolid,
3180                                CapRound, JoinRound);
3181             XSetLineAttributes(display, trianglegc, line_width, LineSolid,
3182                                CapRound, JoinRound);
3183             draw(current_inc, current_image, xmin, ymin, xmax, ymax);
3184           }
3185         } else if (event.xany.window == expwin) {
3186           if ((current_image == PART) && loaded[current_inc][PART]) {
3187             explode = !explode;
3188             draw(current_inc, current_image, xmin, ymin, xmax, ymax);
3189           }
3190         } else if (event.xany.window == exppluswin) {
3191           if ((current_image == PART) && loaded[PART] && explode) {
3192             explosion += 0.125;
3193             findpartshift(subdomains[current_inc], explosion,
3194                           partcenter[current_inc], partshift[current_inc]);
3195             draw(current_inc, current_image, xmin, ymin, xmax, ymax);
3196           }
3197         } else if (event.xany.window == expminuswin) {
3198           if ((current_image == PART) && loaded[PART] && explode &&
3199               (explosion >= 0.125)) {
3200             explosion -= 0.125;
3201             findpartshift(subdomains[current_inc], explosion,
3202                           partcenter[current_inc], partshift[current_inc]);
3203             draw(current_inc, current_image, xmin, ymin, xmax, ymax);
3204           }
3205         } else if (event.xany.window == fillwin) {
3206           if ((current_image == PART) && loaded[PART]) {
3207             fillelem = !fillelem;
3208             draw(current_inc, current_image, xmin, ymin, xmax, ymax);
3209           }
3210         } else if (event.xany.window == pswin) {
3211           fill_button(pswin);
3212           XFlush(display);
3213           print(current_inc, current_image, xmin, ymin, xmax, ymax, 0);
3214           XClearWindow(display, pswin);
3215           XDrawString(display, pswin, fontgc, 2, 13, "PS", 2);
3216         } else if (event.xany.window == epswin) {
3217           fill_button(epswin);
3218           XFlush(display);
3219           print(current_inc, current_image, xmin, ymin, xmax, ymax, 1);
3220           XClearWindow(display, epswin);
3221           XDrawString(display, epswin, fontgc, 2, 13, "EPS", 3);
3222         } else if (event.xany.window == versionpluswin) {
3223           move_inc(1);
3224           loweriteration++;
3225           set_filenames(filename, loweriteration);
3226           if (current_inc == 1) {
3227             current_inc = 0;
3228           } else {
3229             current_image = NOTHING;
3230             XClearWindow(display, mainwindow);
3231           }
3232           draw_buttons();
3233         } else if (event.xany.window == versionminuswin) {
3234           if (loweriteration > 0) {
3235             move_inc(0);
3236             loweriteration--;
3237             set_filenames(filename, loweriteration);
3238             if (current_inc == 0) {
3239               current_inc = 1;
3240             } else {
3241               current_image = NOTHING;
3242               XClearWindow(display, mainwindow);
3243             }
3244             draw_buttons();
3245           }
3246         } else if ((event.xany.window == nodewin[0]) ||
3247                    (event.xany.window == polywin[0]) ||
3248                    (event.xany.window == elewin[0]) ||
3249                    (event.xany.window == edgewin[0]) ||
3250                    (event.xany.window == partwin[0]) ||
3251                    (event.xany.window == adjwin[0]) ||
3252                    (event.xany.window == voronoiwin[0]) ||
3253                    (event.xany.window == nodewin[1]) ||
3254                    (event.xany.window == polywin[1]) ||
3255                    (event.xany.window == elewin[1]) ||
3256                    (event.xany.window == edgewin[1]) ||
3257                    (event.xany.window == partwin[1]) ||
3258                    (event.xany.window == adjwin[1]) ||
3259                    (event.xany.window == voronoiwin[1])) {
3260           if (event.xany.window == nodewin[0]) {
3261             new_inc = 0;
3262             new_image = NODE;
3263           }
3264           if (event.xany.window == polywin[0]) {
3265             new_inc = 0;
3266             new_image = POLY;
3267           }
3268           if (event.xany.window == elewin[0]) {
3269             new_inc = 0;
3270             new_image = ELE;
3271           }
3272           if (event.xany.window == edgewin[0]) {
3273             new_inc = 0;
3274             new_image = EDGE;
3275           }
3276           if (event.xany.window == partwin[0]) {
3277             new_inc = 0;
3278             new_image = PART;
3279           }
3280           if (event.xany.window == adjwin[0]) {
3281             new_inc = 0;
3282             new_image = ADJ;
3283           }
3284           if (event.xany.window == voronoiwin[0]) {
3285             new_inc = 0;
3286             new_image = VORO;
3287           }
3288           if (event.xany.window == nodewin[1]) {
3289             new_inc = 1;
3290             new_image = NODE;
3291           }
3292           if (event.xany.window == polywin[1]) {
3293             new_inc = 1;
3294             new_image = POLY;
3295           }
3296           if (event.xany.window == elewin[1]) {
3297             new_inc = 1;
3298             new_image = ELE;
3299           }
3300           if (event.xany.window == edgewin[1]) {
3301             new_inc = 1;
3302             new_image = EDGE;
3303           }
3304           if (event.xany.window == partwin[1]) {
3305             new_inc = 1;
3306             new_image = PART;
3307           }
3308           if (event.xany.window == adjwin[1]) {
3309             new_inc = 1;
3310             new_image = ADJ;
3311           }
3312           if (event.xany.window == voronoiwin[1]) {
3313             new_inc = 1;
3314             new_image = VORO;
3315           }
3316           past_image = current_image;
3317           if ((current_inc == new_inc) && (current_image == new_image)) {
3318             free_inc(new_inc);
3319             unload_inc(new_inc);
3320           }
3321           choose_image(new_inc, new_image);
3322           if ((past_image == NOTHING) && (current_image != NOTHING)) {
3323             xmin = xlo[current_inc][current_image];
3324             ymin = ylo[current_inc][current_image];
3325             xmax = xhi[current_inc][current_image];
3326             ymax = yhi[current_inc][current_image];
3327             zoom = 0;
3328           }
3329           draw(current_inc, current_image, xmin, ymin, xmax, ymax);
3330         } else {
3331           xptr = ((REAL) event.xbutton.x - xoffset) / xscale;
3332           yptr = ((REAL) event.xbutton.y - yoffset) / yscale;
3333           if ((current_image == PART) && loaded[PART] && explode) {
3334             xptr = (xptr + partcenter[current_inc]
3335                                      [subdomains[current_inc] << 1]
3336                     * explosion) / (1.0 + explosion);
3337             yptr = (yptr + partcenter[current_inc]
3338                                      [(subdomains[current_inc] << 1) + 1]
3339                     * explosion) / (1.0 + explosion);
3340           }
3341           if ((event.xbutton.button == Button1)
3342               || (event.xbutton.button == Button3)) {
3343             if (event.xbutton.button == Button1) {
3344               xspan = 0.25 * (xmax - xmin);
3345               yspan = 0.25 * (ymax - ymin);
3346               zoom++;
3347             } else {
3348               xspan = xmax - xmin;
3349               yspan = ymax - ymin;
3350               zoom--;
3351             }
3352             xmin = xptr - xspan;
3353             ymin = yptr - yspan;
3354             xmax = xptr + xspan;
3355             ymax = yptr + yspan;
3356             draw(current_inc, current_image, xmin, ymin, xmax, ymax);
3357           } else if (event.xbutton.button == Button2) {
3358             printf("x = %.4g, y = %.4g\n", xptr, yptr);
3359           }
3360         }
3361         break;
3362       case DestroyNotify:
3363         XDestroyWindow(display, mainwindow);
3364         XCloseDisplay(display);
3365         return 0;
3366       case ConfigureNotify:
3367         if ((width != event.xconfigure.width) ||
3368             (height != event.xconfigure.height - PANELHEIGHT)) {
3369           width = event.xconfigure.width;
3370           height = event.xconfigure.height - PANELHEIGHT;
3371           draw(current_inc, current_image, xmin, ymin, xmax, ymax);
3372           while (XCheckMaskEvent(display, ExposureMask, &event));
3373         }
3374         break;
3375       case Expose:
3376         draw(current_inc, current_image, xmin, ymin, xmax, ymax);
3377         while (XCheckMaskEvent(display, ExposureMask, &event));
3378         break;
3379       default:
3380         break;
3381     }
3382     XNextEvent(display, &event);
3383   }
3384 }