]> git.mxchange.org Git - flightgear.git/blob - SplitTris/splittris.cxx
e9ec2ff57a0f418575c5713fd50537411592dec2
[flightgear.git] / SplitTris / splittris.cxx
1 // splittris.cxx -- read in a .ele/.node file pair generated by the
2 //                  triangle program and output a simple Wavefront .obj
3 //                  file for the north, south, east, and west edge
4 //                  verticies ... including the normals.
5 //
6 // Written by Curtis Olson, started January 1998.
7 //
8 // Copyright (C) 1997  Curtis L. Olson  - curt@infoplane.com
9 //
10 // This program is free software; you can redistribute it and/or modify
11 // it under the terms of the GNU General Public License as published by
12 // the Free Software Foundation; either version 2 of the License, or
13 // (at your option) any later version.
14 //
15 // This program is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with this program; if not, write to the Free Software
22 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 //
24 // $Id$
25 // (Log is kept at end of this file)
26
27
28 #include <math.h>
29 #include <stdio.h>
30 #include <stdlib.h>   // for atoi()
31 #include <string.h>
32 #include <sys/stat.h> // for stat()
33 #include <unistd.h>   // for stat()
34
35 #include "splittris.hxx"
36
37 #include <Include/fg_constants.h>
38 #include <Include/fg_types.h>
39 #include <Bucket/bucketutils.h>
40
41 #include <Math/fg_geodesy.h>
42 #include <Math/mat3.h>
43 #include <Math/polar3d.hxx>
44
45 // int nodecount, tricount;
46 double xmin, xmax, ymin, ymax;
47
48 // static double nodes_orig[MAX_NODES][3];
49 // static fgPoint3d nodes_cart[MAX_NODES];
50 // static int tris[MAX_TRIS][3];
51
52 container_3d nodes_orig;
53 container_3d nodes_cart;
54 container_tri tri_list;
55
56 fgBUCKET ne_index, nw_index, sw_index, se_index;
57 fgBUCKET north_index, south_index, east_index, west_index;
58
59 // convert a geodetic point lon(arcsec), lat(arcsec), elev(meter) to a
60 // cartesian point
61 fgPoint3d geod_to_cart(fgPoint3d geod) {
62     fgPoint3d cp;
63     fgPoint3d pp;
64     double gc_lon, gc_lat, sl_radius;
65
66     // printf("A geodetic point is (%.2f, %.2f, %.2f)\n", 
67     //        geod[0], geod[1], geod[2]);
68
69     gc_lon = geod.lon * ARCSEC_TO_RAD;
70     fgGeodToGeoc(geod.lat * ARCSEC_TO_RAD, geod.radius, &sl_radius, &gc_lat);
71
72     // printf("A geocentric point is (%.2f, %.2f, %.2f)\n", gc_lon, 
73     //        gc_lat, sl_radius+geod[2]);
74
75     pp.lon = gc_lon;
76     pp.lat = gc_lat;
77     pp.radius = sl_radius + geod.radius;
78     cp = fgPolarToCart3d(pp);
79     
80     // printf("A cart point is (%.8f, %.8f, %.8f)\n", cp.x, cp.y, cp.z);
81
82     return(cp);
83 }
84
85
86 // given three points defining a triangle, calculate the normal
87 void calc_normal(fgPoint3d p1, fgPoint3d p2, 
88                  fgPoint3d p3, double normal[3])
89 {
90     double v1[3], v2[3];
91     double temp;
92
93     v1[0] = p2.x - p1.x; v1[1] = p2.y - p1.y; v1[2] = p2.z - p1.z;
94     v2[0] = p3.x - p1.x; v2[1] = p3.y - p1.y; v2[2] = p3.z - p1.z;
95
96     MAT3cross_product(normal, v1, v2);
97     MAT3_NORMALIZE_VEC(normal,temp);
98
99     // printf("  Normal = %.2f %.2f %.2f\n", normal[0], normal[1], normal[2]);
100 }
101
102
103 // return the file base name ( foo/bar/file.ext = file.ext )
104 string extract_file(const string& input) {
105     int pos;
106
107     pos = input.rfind("/");
108     ++pos;
109
110     return input.substr(pos);
111 }
112
113
114 // return the file path name ( foo/bar/file.ext = foo/bar )
115 string extract_path(const string& input) {
116     int pos;
117
118     pos = input.rfind("/");
119
120     return input.substr(0, pos);
121 }
122
123
124 // return the index of all triangles containing the specified node
125 void find_tris(int n, int *t1, int *t2, int *t3, int *t4, int *t5) {
126     int i;
127
128     *t1 = *t2 = *t3 = *t4 = *t5 = 0;
129
130     i = 1;
131     iterator_tri last = tri_list.end();
132     iterator_tri current = tri_list.begin();
133
134     // skip first null record
135     ++current;
136
137     for ( ; current != last; ++current )
138     {
139         if ( (n == (*current).n1) || (n == (*current).n2) || 
140              (n == (*current).n3) )
141         {
142             if ( *t1 == 0 ) {
143                 *t1 = i;
144             } else if ( *t2 == 0 ) {
145                 *t2 = i;
146             } else if ( *t3 == 0 ) {
147                 *t3 = i;
148             } else if ( *t4 == 0 ) {
149                 *t4 = i;
150             } else {
151                 *t5 = i;
152             }
153         }
154         ++i;
155     }
156 }
157
158
159 // Initialize a new mesh structure
160 void triload(const string& basename) {
161     string nodename, elename;
162     fgPoint3d node1, node2;
163     triangle tri;
164     FILE *node_file, *ele_file;
165     int nodecount, tricount, dim, junk1, junk2;
166     int i;
167
168     nodename = basename + ".node";
169     elename  = basename + ".ele";
170
171     cout << "Loading node file:  " + nodename + " ...\n";
172     if ( (node_file = fopen(nodename.c_str(), "r")) == NULL ) {
173         cout << "Cannot open file " + nodename + "\n";
174         exit(-1);
175     }
176
177     // the triangle program starts counting at 1 by default which is
178     // pretty obnoxious.  Let's just push null record zero's onto our
179     // list to compensate
180     nodes_orig.push_back(node1);
181     nodes_cart.push_back(node1);
182     tri_list.push_back(tri);
183
184     fscanf(node_file, "%d %d %d %d", &nodecount, &dim, &junk1, &junk2);
185     cout << "    Expecting " << nodecount << " nodes\n";
186
187     for ( i = 1; i <= nodecount; i++ ) {
188         fscanf(node_file, "%d %lf %lf %lf %d\n", &junk1, 
189                &(node1.x), &(node1.y), &(node1.z), &junk2);
190         printf("%d %.2f %.2f %.2f\n", junk1, node1.x, node1.y, node1.z);
191         nodes_orig.push_back(node1);
192         node2 = geod_to_cart(node1);
193         nodes_cart.push_back(node2);
194         printf("%d %.2f %.2f %.2f\n", junk1, node2.x, node2.y, node2.z);
195
196         if ( i == 1 ) {
197             xmin = xmax = node1.x;
198             ymin = ymax = node1.y;
199         } else {
200             if ( node1.x < xmin ) {
201                 xmin = node1.x;
202             }
203             if ( node1.x > xmax ) {
204                 xmax = node1.x;
205             }
206             if ( node1.y < ymin ) {
207                 ymin = node1.y;
208             }
209             if ( node1.y > ymax ) {
210                 ymax = node1.y;
211             }
212         }
213     }
214
215     fclose(node_file);
216
217     cout << "Loading element file:  " + elename + " ...\n";
218     if ( (ele_file = fopen(elename.c_str(), "r")) == NULL ) {
219         cout << "Cannot open file " + elename + "\n";
220         exit(-1);
221     }
222
223     fscanf(ele_file, "%d %d %d", &tricount, &junk1, &junk2);
224     cout << "    Expecting " << tricount << " elements\n";
225
226     for ( i = 1; i <= tricount; i++ ) {
227         fscanf(ele_file, "%d %d %d %d\n", &junk1, 
228                &(tri.n1), &(tri.n2), &(tri.n3));
229         printf("%d %d %d %d\n", junk1, tri.n1, tri.n2, tri.n3);
230         tri_list.push_back(tri);
231     }
232
233     fclose(ele_file);
234 }
235
236
237 // check if a file exists
238 int file_exists(char *file) {
239     struct stat stat_buf;
240     int result;
241
242     cout << "checking " << file << " ... ";
243
244     result = stat(file, &stat_buf);
245
246     if ( result != 0 ) {
247         // stat failed, no file
248         cout << "not found.\n";
249         return 0;
250     } else {
251         // stat succeeded, file exists
252         cout << "exists.\n";
253         return 1;
254     }
255 }
256
257
258 // check to see if a shared object exists
259 int shared_object_exists(const char *basepath, const string& ext) {
260     char file[256], scene_path[256];
261     long int index;
262
263     if ( ext == ".sw" ) {
264         fgBucketGenBasePath(&west_index, scene_path);
265         index = fgBucketGenIndex(&west_index);
266         sprintf(file, "%s/%s/%ld.1.se", basepath, scene_path, index);
267         if ( file_exists(file) ) {
268             return(1);
269         }
270         fgBucketGenBasePath(&sw_index, scene_path);
271         index = fgBucketGenIndex(&sw_index);
272         sprintf(file, "%s/%s/%ld.1.ne", basepath, scene_path, index);
273         if ( file_exists(file) ) {
274             return(1);
275         }
276         fgBucketGenBasePath(&south_index, scene_path);
277         index = fgBucketGenIndex(&south_index);
278         sprintf(file, "%s/%s/%ld.1.nw", basepath, scene_path, index);
279         if ( file_exists(file) ) {
280             return(1);
281         }
282     }
283
284     if ( ext == ".se" ) {
285         fgBucketGenBasePath(&east_index, scene_path);
286         index = fgBucketGenIndex(&east_index);
287         sprintf(file, "%s/%s/%ld.1.sw", basepath, scene_path, index);
288         if ( file_exists(file) ) {
289             return(1);
290         }
291         fgBucketGenBasePath(&se_index, scene_path);
292         index = fgBucketGenIndex(&se_index);
293         sprintf(file, "%s/%s/%ld.1.nw", basepath, scene_path, index);
294         if ( file_exists(file) ) {
295             return(1);
296         }
297         fgBucketGenBasePath(&south_index, scene_path);
298         index = fgBucketGenIndex(&south_index);
299         sprintf(file, "%s/%s/%ld.1.ne", basepath, scene_path, index);
300         if ( file_exists(file) ) {
301             return(1);
302         }
303     }
304
305     if ( ext == ".ne" ) {
306         fgBucketGenBasePath(&east_index, scene_path);
307         index = fgBucketGenIndex(&east_index);
308         sprintf(file, "%s/%s/%ld.1.nw", basepath, scene_path, index);
309         if ( file_exists(file) ) {
310             return(1);
311         }
312         fgBucketGenBasePath(&ne_index, scene_path);
313         index = fgBucketGenIndex(&ne_index);
314         sprintf(file, "%s/%s/%ld.1.sw", basepath, scene_path, index);
315         if ( file_exists(file) ) {
316             return(1);
317         }
318         fgBucketGenBasePath(&north_index, scene_path);
319         index = fgBucketGenIndex(&north_index);
320         sprintf(file, "%s/%s/%ld.1.se", basepath, scene_path, index);
321         if ( file_exists(file) ) {
322             return(1);
323         }
324     }
325
326     if ( ext == ".nw" ) {
327         fgBucketGenBasePath(&west_index, scene_path);
328         index = fgBucketGenIndex(&west_index);
329         sprintf(file, "%s/%s/%ld.1.ne", basepath, scene_path, index);
330         if ( file_exists(file) ) {
331             return(1);
332         }
333         fgBucketGenBasePath(&nw_index, scene_path);
334         index = fgBucketGenIndex(&nw_index);
335         sprintf(file, "%s/%s/%ld.1.se", basepath, scene_path, index);
336         if ( file_exists(file) ) {
337             return(1);
338         }
339         fgBucketGenBasePath(&north_index, scene_path);
340         index = fgBucketGenIndex(&north_index);
341         sprintf(file, "%s/%s/%ld.1.sw", basepath, scene_path, index);
342         if ( file_exists(file) ) {
343             return(1);
344         }
345     }
346
347     if ( ext == ".south" ) {
348         fgBucketGenBasePath(&south_index, scene_path);
349         index = fgBucketGenIndex(&south_index);
350         sprintf(file, "%s/%s/%ld.1.north", basepath, scene_path, index);
351         if ( file_exists(file) ) {
352             return(1);
353         }
354     }
355
356     if ( ext == ".north" ) {
357         fgBucketGenBasePath(&north_index, scene_path);
358         index = fgBucketGenIndex(&north_index);
359         sprintf(file, "%s/%s/%ld.1.south", basepath, scene_path, index);
360         if ( file_exists(file) ) {
361             return(1);
362         }
363     }
364
365     if ( ext == ".west" ) {
366         fgBucketGenBasePath(&west_index, scene_path);
367         index = fgBucketGenIndex(&west_index);
368         sprintf(file, "%s/%s/%ld.1.east", basepath, scene_path, index);
369         if ( file_exists(file) ) {
370             return(1);
371         }
372     }
373
374     if ( ext == ".east" ) {
375         fgBucketGenBasePath(&east_index, scene_path);
376         index = fgBucketGenIndex(&east_index);
377         sprintf(file, "%s/%s/%ld.1.west", basepath, scene_path, index);
378         if ( file_exists(file) ) {
379             return(1);
380         }
381     }
382
383     return(0);
384 }
385
386
387 // my custom file opening routine ... don't open if a shared edge or
388 // vertex alread exists
389 FILE *my_open(const string& basename, const string& basepath, 
390               const string& ext)
391 {
392     FILE *fp;
393     string filename;
394
395     // create the output file name
396     filename = basename + ext;
397
398     // check if a shared object already exist from a different tile
399
400     if ( shared_object_exists(basepath.c_str(), ext) ) {
401         // not an actual file open error, but we've already got the
402         // shared edge, so we don't want to create another one
403         cout << "not opening\n";
404         return(NULL);
405     } else {
406         // open the file
407         fp = fopen(filename.c_str(), "w");
408         cout << "Opening " + filename + "\n";
409         return(fp);
410     }
411 }
412
413
414 // dump in WaveFront .obj format
415 void dump_obj(const string& basename, const string& basepath) {
416     fgPoint3d node;
417     double n1[3], n2[3], n3[3], n4[3], n5[3], norm[3], temp;
418     FILE *fp, *sw, *se, *ne, *nw, *north, *south, *east, *west, *body;
419     int i, t1, t2, t3, t4, t5, count, size;
420
421     sw = my_open(basename, basepath, ".sw");
422     se = my_open(basename, basepath, ".se");
423     ne = my_open(basename, basepath, ".ne");
424     nw = my_open(basename, basepath, ".nw");
425
426     north = my_open(basename, basepath, ".north");
427     south = my_open(basename, basepath, ".south");
428     east = my_open(basename, basepath, ".east");
429     west = my_open(basename, basepath, ".west");
430
431     body = my_open(basename, basepath, ".body");
432
433     cout << "Dumping edges file basename:  " + basename + " ...\n";
434
435     // dump vertices
436     cout << "  writing vertices\n";
437
438     iterator_3d last = nodes_orig.end();
439     iterator_3d current = nodes_orig.begin();
440     ++current;
441     for ( ; current != last; ++current) {
442         node = *current;
443
444         if ( (fabs(node.y - ymin) < FG_EPSILON) && 
445              (fabs(node.x - xmin) < FG_EPSILON) ) {
446             fp = sw;
447         } else if ( (fabs(node.y - ymin) < FG_EPSILON) &&
448                     (fabs(node.x - xmax) < FG_EPSILON) ) {
449             fp = se;
450         } else if ( (fabs(node.y - ymax) < FG_EPSILON) &&
451                     (fabs(node.x - xmax) < FG_EPSILON)) {
452             fp = ne;
453         } else if ( (fabs(node.y - ymax) < FG_EPSILON) &&
454                     (fabs(node.x - xmin) < FG_EPSILON) ) {
455             fp = nw;
456         } else if ( fabs(node.x - xmin) < FG_EPSILON ) {
457             fp = west;
458         } else if ( fabs(node.x - xmax) < FG_EPSILON ) {
459             fp = east;
460         } else if ( fabs(node.y - ymin) < FG_EPSILON ) {
461             fp = south;
462         } else if ( fabs(node.y - ymax) < FG_EPSILON ) {
463             fp = north;
464         } else {
465             fp = body;
466         }
467
468         if ( fp != NULL ) {
469             fprintf(fp, "gdn %.2f %.2f %.2f\n", node.x, node.y, node.z);
470         }
471     }
472
473     cout << "  calculating and writing normals\n";
474
475     // calculate and generate normals
476     size = nodes_orig.size();
477     for ( i = 1; i < size; i++ ) {
478         // printf("Finding normal\n");
479
480         find_tris(i, &t1, &t2, &t3, &t4, &t5);
481
482         n1[0] = n1[1] = n1[2] = 0.0;
483         n2[0] = n2[1] = n2[2] = 0.0;
484         n3[0] = n3[1] = n3[2] = 0.0;
485         n4[0] = n4[1] = n4[2] = 0.0;
486         n5[0] = n5[1] = n5[2] = 0.0;
487
488         count = 1;
489         calc_normal(nodes_cart[tri_list[t1].n1],
490                     nodes_cart[tri_list[t1].n2], 
491                     nodes_cart[tri_list[t1].n3],
492                     n1);
493
494         if ( t2 > 0 ) {
495             calc_normal(nodes_cart[tri_list[t2].n1], 
496                         nodes_cart[tri_list[t2].n2], 
497                         nodes_cart[tri_list[t2].n3],
498                         n2);
499             count = 2;
500         }
501
502         if ( t3 > 0 ) {
503             calc_normal(nodes_cart[tri_list[t3].n1],
504                         nodes_cart[tri_list[t3].n2],
505                         nodes_cart[tri_list[t3].n3],
506                         n3);
507             count = 3;
508         }
509
510         if ( t4 > 0 ) {
511             calc_normal(nodes_cart[tri_list[t4].n1],
512                         nodes_cart[tri_list[t4].n2],
513                         nodes_cart[tri_list[t4].n3],
514                         n4);
515             count = 4;
516         }
517
518         if ( t5 > 0 ) {
519             calc_normal(nodes_cart[tri_list[t5].n1],
520                         nodes_cart[tri_list[t5].n2],
521                         nodes_cart[tri_list[t5].n3],
522                         n5);
523             count = 5;
524         }
525
526         // printf("  norm[2] = %.2f %.2f %.2f\n", n1[2], n2[2], n3[2]);
527
528         norm[0] = ( n1[0] + n2[0] + n3[0] + n4[0] + n5[0] ) / (double)count;
529         norm[1] = ( n1[1] + n2[1] + n3[1] + n4[1] + n5[1] ) / (double)count;
530         norm[2] = ( n1[2] + n2[2] + n3[2] + n4[2] + n5[2] ) / (double)count;
531         
532         // printf("  count = %d\n", count);
533         // printf("  Ave. normal = %.4f %.4f %.4f\n", norm[0], norm[1], 
534         //        norm[2]);
535         MAT3_NORMALIZE_VEC(norm, temp);
536         // printf("  Normalized ave. normal = %.4f %.4f %.4f\n", 
537         //        norm[0], norm[1], norm[2]);
538         
539         fp = NULL;
540
541         if ( (fabs(nodes_orig[i].y - ymin) < FG_EPSILON) && 
542              (fabs(nodes_orig[i].x - xmin) < FG_EPSILON) ) {
543             fp = sw;
544         } else if ( (fabs(nodes_orig[i].y - ymin) < FG_EPSILON) &&
545                     (fabs(nodes_orig[i].x - xmax) < FG_EPSILON) ) {
546             fp = se;
547         } else if ( (fabs(nodes_orig[i].y - ymax) < FG_EPSILON) &&
548                     (fabs(nodes_orig[i].x - xmax) < FG_EPSILON)) {
549             fp = ne;
550         } else if ( (fabs(nodes_orig[i].y - ymax) < FG_EPSILON) &&
551                     (fabs(nodes_orig[i].x - xmin) < FG_EPSILON) ) {
552             fp = nw;
553         } else if ( fabs(nodes_orig[i].x - xmin) < FG_EPSILON ) {
554             fp = west;
555         } else if ( fabs(nodes_orig[i].x - xmax) < FG_EPSILON ) {
556             fp = east;
557         } else if ( fabs(nodes_orig[i].y - ymin) < FG_EPSILON ) {
558             fp = south;
559         } else if ( fabs(nodes_orig[i].y - ymax) < FG_EPSILON ) {
560             fp = north;
561         }
562         if ( fp != NULL ) {
563             fprintf(fp, "vn %.4f %.4f %.4f\n", norm[0], norm[1], norm[2]);
564         }
565     }
566
567     if ( sw ) { fclose(sw); }
568     if ( se ) { fclose(se); }
569     if ( ne ) { fclose(ne); }
570     if ( nw ) { fclose(nw); }
571
572     if ( north ) { fclose(north); }
573     if ( south ) { fclose(south); }
574     if ( east ) { fclose(east); }
575     if ( west ) { fclose(west); }
576
577     if ( body ) { fclose(body); }
578 }
579
580
581 int main(int argc, char **argv) {
582     string basename, basepath, temp;
583     fgBUCKET p;
584     long int index;
585     int len;
586
587     basename = argv[1];
588
589     // find the base path of the file
590     basepath = extract_path(basename);
591     basepath = extract_path(basepath);
592     basepath = extract_path(basepath);
593     cout << "basepath = " + basepath + "\n";
594
595     // find the index of the current file
596     temp = extract_file(basename);
597     len = temp.length();
598     if ( len >= 2 ) {
599         temp = temp.substr(0, len-2);
600     }
601     index = atoi( temp.c_str() );
602     cout << "index = " << index << "\n";
603     fgBucketParseIndex(index, &p);
604
605     cout << "bucket = " << p.lon << " " << p.lat << " " << 
606         p.x << " " << p.y << "\n";
607
608     // generate the indexes of the neighbors
609     fgBucketOffset(&p, &ne_index,  1,  1);
610     fgBucketOffset(&p, &nw_index, -1,  1);
611     fgBucketOffset(&p, &se_index,  1, -1);
612     fgBucketOffset(&p, &sw_index, -1, -1);
613
614     fgBucketOffset(&p, &north_index,  0,  1);
615     fgBucketOffset(&p, &south_index,  0, -1);
616     fgBucketOffset(&p, &east_index,  1,  0);
617     fgBucketOffset(&p, &west_index, -1,  0);
618
619     // printf("Corner indexes = %ld %ld %ld %ld\n", 
620     //        ne_index, nw_index, sw_index, se_index);
621     // printf("Edge indexes = %ld %ld %ld %ld\n",
622     //        north_index, south_index, east_index, west_index);
623           
624
625     // load the input data files
626     triload(basename);
627
628     // dump in WaveFront .obj format
629     dump_obj(basename, basepath);
630
631     return(0);
632 }
633
634
635 // $Log$
636 // Revision 1.3  1998/09/22 23:49:56  curt
637 // C++-ified, STL-ified, and string-ified.
638 //
639 // Revision 1.2  1998/09/21 23:16:23  curt
640 // Converted to c++ style comments.
641 //
642 // Revision 1.1  1998/07/08 14:59:13  curt
643 // *.[ch] renamed to *.[ch]xx
644 //
645 // Revision 1.11  1998/07/04 00:56:40  curt
646 // typedef'd struct fgBUCKET.
647 //
648 // Revision 1.10  1998/05/02 01:54:37  curt
649 // Converting to polar3d.h routines.
650 //
651 // Revision 1.9  1998/04/18 04:01:20  curt
652 // Now use libMath rather than having local copies of math routines.
653 //
654 // Revision 1.8  1998/04/14 02:26:08  curt
655 // Code reorganizations.  Added a Lib/ directory for more general libraries.
656 //
657 // Revision 1.7  1998/04/08 23:21:13  curt
658 // Adopted Gnu automake/autoconf system.
659 //
660 // Revision 1.6  1998/03/03 15:36:13  curt
661 // Tweaks for compiling with g++
662 //
663 // Revision 1.5  1998/03/03 03:37:04  curt
664 // Cumulative tweaks.
665 //
666 // Revision 1.4  1998/01/31 00:41:26  curt
667 // Made a few changes converting floats to doubles.
668 //
669 // Revision 1.3  1998/01/27 18:37:04  curt
670 // Lots of updates to get back in sync with changes made over in .../Src/
671 //
672 // Revision 1.2  1998/01/14 15:54:43  curt
673 // Initial revision completed.
674 //
675 // Revision 1.1  1998/01/14 02:11:31  curt
676 // Initial revision.
677 //
678